stable
Ivory 2025-09-24 20:01:45 -04:00
parent d044031489
commit 304419b01a
20 changed files with 334 additions and 188 deletions

View File

@ -0,0 +1 @@
uid://denhgj0vxywle

View File

@ -17,6 +17,8 @@ var total_height: int
var thickness: int
var off: Vector2
var residents_field: Array[int]
@onready var selection_manager: SelectionManager = Util.find(SelectionManager)
func _enter_tree():
@ -25,7 +27,9 @@ func _enter_tree():
func _ready():
_calc_dims()
Engine.is_editor_hint()
residents_field.resize(cells ** 2)
for idx in len(residents_field):
residents_field[idx] = 0
func _calc_dims():
total_width = cells * cell_size
@ -85,23 +89,20 @@ func quantize_on_objects(world_position: Vector2) -> Rect2:
var tile_pos = world2tile(world_position)
var size = Vector2i.ONE
for tile in things:
# we subtract ONE here, because the encloses thing is a >= test and goes OOB with integers
if Rect2(tile.tile_pos, tile.size - Vector2i.ONE).encloses(Rect2(tile_pos, Vector2.ZERO)):
size = tile.size
tile_pos = tile.tile_pos
break
return tile2world_rect(Rect2i(tile_pos, size))
if tile.get_worldbox().has_point(world_position):
return tile.get_worldbox()
return quantize(world_position, Vector2.ONE)
func _get_tile_at_tile_pos(pos: Vector2i) -> Positional:
func _get_tile_at_tile_pos(pos: Vector2i) -> TileTransform:
for tile in things:
if tile.get_tilebox().has_point(pos):
return tile
return null
func _get_tile_at_world_pos(pos: Vector2) -> Positional:
func _get_tile_at_world_pos(pos: Vector2) -> TileTransform:
#var world_pos = world2tile_f(pos)
for tile in things:
if tile.worldbox.has_point(pos):
if tile.get_worldbox().has_point(pos):
return tile
return null
@ -116,77 +117,22 @@ func contains_world_pos(pos: Vector2) -> bool:
func _shift_rect_half(rect: Rect2) -> Rect2:
return Rect2(rect.position + rect.size / -2, rect.size)
var left_dragging = false
var left_mouse_down = false
var left_mouse_down_start_pos: Vector2 = Vector2.ZERO
func _is_mouse_pos_significant() -> bool:
return (get_local_mouse_position() - left_mouse_down_start_pos).length_squared() > 50
func _input(event: InputEvent):
if event is InputEventMouseMotion:
if left_mouse_down:
if not left_dragging and _is_mouse_pos_significant():
left_dragging = true
_begin_drag(get_local_mouse_position())
elif left_dragging:
_dragging(get_local_mouse_position())
elif event is InputEventMouseButton:
if event.button_index == 1:
left_mouse_down = event.pressed
if event.pressed:
left_mouse_down_start_pos = get_local_mouse_position()
else:
if left_dragging:
left_dragging = false
_end_drag(get_local_mouse_position())
else:
_click(get_local_mouse_position())
var things: Array[Positional] = []
var things: Array[TileTransform] = []
var things_dict: Dictionary = {}
func register_tile(tile: Positional) -> void:
func tile_pos2index(pos: Vector2i) -> int:
return pos.x + pos.y * self.cells
func idnex2tile_pos(idx: int) -> Vector2i:
return Vector2i(
idx % self.cells,
floor(idx / self.cells)
)
func register_tile(tile: TileTransform) -> void:
things.append(tile)
func remove_tile(tile: Positional) -> void:
func remove_tile(tile: TileTransform) -> void:
things.erase(tile)
func _begin_drag(pos: Vector2):
print("drag from", pos)
func _dragging(pos: Vector2):
pass
func _end_drag(pos: Vector2):
print("to", pos)
func _click(pos: Vector2):
print("click at", pos)
var tile = _get_tile_at_world_pos(pos)
if tile == null:
selection_manager.clear()
return
selection_manager.select_array([tile])
func _double_click(pos: Vector2):
pass
func _right_click(pos: Vector2):
pass

View File

@ -0,0 +1 @@
uid://8lkq20gwkrvx

View File

@ -0,0 +1,213 @@
extends Node2D
@onready var grid: Grid = $/root/Root/Grid
@export var highlight_color: Color = Color(1, 1, 1, 0.2)
@export var deletion_color: Color = Color(1, 1, 1, 0.2)
var animation_speed = 0.8
enum AnimationState {
Active,
Fading,
Exploding
}
enum CursorMode {
Selection,
Deletion
}
class Display:
var mode: CursorMode
var box: Rect2
var desired_box: Rect2
var opacity: float
var confirmed_callback: Callable
var cancelled_callback: Callable
var dragging: bool = false
var drag_from: Rect2
var state: AnimationState = AnimationState.Fading
var display_count = 10
var displays: Array[Display] = []
var display_idx = -1
var display: Display:
get():
return displays[display_idx] if display_idx >= 0 else null
func new_display():
if display_idx < 0:
display_idx += display_count
display_idx += 1
display_idx = display_idx % display_count
display.dragging = false
display.box = get_viewport_rect()
display.box.size = Vector2.ONE * max(display.box.size.x, display.box.size.y)
display.box = Rect2(display.box.position + display.box.size / -2.0, display.box.size).grow(100)
display.opacity = -2.0
display.state = AnimationState.Active
display.desired_box = display.box
func end_display():
if display == null: return
if display.state == AnimationState.Active:
display.state = AnimationState.Fading
if display.state == AnimationState.Exploding:
display.desired_box = display.desired_box.grow(30)
display_idx -= display_count
var left_dragging = false
var left_mouse_down = false
var left_mouse_down_start_pos: Vector2 = Vector2.ZERO
func _is_mouse_pos_significant() -> bool:
return (get_local_mouse_position() - left_mouse_down_start_pos).length_squared() > 50
#eventually, replace this weird shit with an array of old rects that are fading out
#let them fade out, and just remove them. have a method to abandon the current box
#and start a new one that just follows the normal box-booting procedure.
#if you're not in the grid, it simply wont be created yet. have to have a has_box prop
#or something like that. but this is good enough for now
func _ready():
selection_manager = Util.find(SelectionManager)
displays.resize(display_count)
for idx in range(displays.size()):
displays[idx] = Display.new()
displays[idx].opacity = 0.0
displays[idx].state = AnimationState.Fading
mouse_in_grid = grid.contains_world_pos(get_local_mouse_position())
if mouse_in_grid:
new_display()
func _lerp_opacity(c: Color, t: float) -> Color:
return Color(c.r, c.g, c.b, c.a * t)
func update_display_animations(delta):
for d in displays:
var old_size = d.box.size
var desired_size = d.desired_box.size
var new_size = 0.0
match d.state:
AnimationState.Exploding:
new_size = lerp(old_size, desired_size, delta * 3 * animation_speed)
AnimationState.Active, \
AnimationState.Fading:
if old_size.length_squared() > desired_size.length_squared():
new_size = lerp(old_size, desired_size, delta * 30 * animation_speed)
else:
new_size = lerp(old_size, desired_size, delta * 30 * animation_speed)
var old_center = d.box.get_center()
var desired_center = d.desired_box.get_center()
var new_center = lerp(old_center, desired_center, delta * 50 * animation_speed)
d.box = Rect2(new_center - new_size / 2.0, new_size)
match d.state:
AnimationState.Fading:
d.opacity = lerp(d.opacity, 0.0, delta * 10 * animation_speed)
AnimationState.Active:
d.opacity = lerp(d.opacity, 1.0, delta * 20 * animation_speed)
AnimationState.Exploding:
d.opacity = lerp(d.opacity, -1.0, delta * 5 * animation_speed)
var mouse_in_grid: bool = false
var mousing_over: Rect2
func _process(delta):
queue_redraw()
var mouse = get_local_mouse_position()
var new_mousing_over = grid.quantize_on_objects(mouse)
var new_mouse_in_grid = grid.contains_world_pos(mouse)
if mouse_in_grid && !new_mouse_in_grid:
end_display()
if !mouse_in_grid && new_mouse_in_grid:
new_display()
display.mode = CursorMode.Deletion
if new_mousing_over != mousing_over && display == null && new_mouse_in_grid:
new_display()
mouse_in_grid = new_mouse_in_grid
mousing_over = new_mousing_over
update_display_animations(delta)
# only do anything new if we have a mouse on the grid!
if !mouse_in_grid: return
if display == null: return
display.desired_box = mousing_over
func _draw():
#draw_rect(mousing_over.grow(-8), Color.FIREBRICK, true)
for d in displays:
match d.mode:
CursorMode.Selection:
draw_rect(d.box, _lerp_opacity(highlight_color, d.opacity), true)
CursorMode.Deletion:
draw_rect(d.box, _lerp_opacity(deletion_color, d.opacity), true)
enum State {
# Selection will automatically go do selection things
Selection,
# whereas these hoes will just call callbacks.
LineDrag,
Area,
}
var state: State = State.Selection
var selection_manager: SelectionManager
func _begin_drag(pos: Vector2):
display.drag_from
print("drag from", pos)
func _dragging(pos: Vector2):
pass
func _end_drag(pos: Vector2):
print("to", pos)
func _click(pos: Vector2):
print("click at", pos)
if display == null:
new_display()
display.state = AnimationState.Exploding
end_display()
var tile = grid._get_tile_at_world_pos(pos)
if tile == null:
selection_manager.clear()
return
selection_manager.select_array([tile])
func _double_click(pos: Vector2):
pass
func _right_click(pos: Vector2):
pass
func _input(event: InputEvent):
if event is InputEventMouseMotion:
if left_mouse_down:
if not left_dragging and _is_mouse_pos_significant():
left_dragging = true
_begin_drag(get_local_mouse_position())
elif left_dragging:
_dragging(get_local_mouse_position())
elif event is InputEventMouseButton:
if event.button_index == 1:
left_mouse_down = event.pressed
if event.pressed:
left_mouse_down_start_pos = get_local_mouse_position()
else:
if left_dragging:
left_dragging = false
_end_drag(get_local_mouse_position())
else:
_click(get_local_mouse_position())

View File

@ -0,0 +1 @@
uid://xe60g0el2j5x

View File

@ -1,58 +0,0 @@
extends Node2D
@onready var grid: Grid = $/root/Root/Grid
@export var highlight_color: Color = Color(1, 1, 1, 0.2)
@onready var d_pos: Rect2 = grid.quantize(get_local_mouse_position(), Vector2i.ONE)
@onready var c_pos: Rect2 = d_pos
@onready var d_opacity = 1.0 if grid.contains_world_pos(get_local_mouse_position()) else 0.0
@onready var c_opacity = 0.0
#eventually, replace this weird shit with an array of old rects that are fading out
#let them fade out, and just remove them. have a method to abandon the current box
#and start a new one that just follows the normal box-booting procedure.
#if you're not in the grid, it simply wont be created yet. have to have a has_box prop
#or something like that. but this is good enough for now
func _lerp_opacity(c: Color, t: float) -> Color:
return Color(c.r, c.g, c.b, c.a * t)
func _process(delta):
queue_redraw()
var a_center = c_pos.get_center()
if c_opacity >= 0.01:
var b_center = d_pos.get_center()
# i know its not right but stfu
var n_center = lerp(a_center, b_center, delta * 60)
var a_size = c_pos.size
var b_size = d_pos.size
var n_size: Vector2
if a_size.length_squared() > b_size.length_squared():
n_size = lerp(a_size, b_size, delta * 20)
else:
#getting bigger needs to be ffaster because it looks nice but also lerping
#bigger makes it last longer at the very end
n_size = lerp(a_size, b_size, delta * 60)
var n_pos = n_center - n_size / 2
c_pos = Rect2(n_pos, n_size)
else:
c_pos = Rect2(d_pos)
var mouse = get_local_mouse_position()
if grid.contains_world_pos(mouse) and not grid.left_dragging:
d_pos = grid.quantize_on_objects(get_local_mouse_position())
if grid.contains_world_pos(a_center):
d_opacity = 1.0
else:
d_opacity = 0.0
if d_opacity > c_opacity or grid.left_dragging:
c_opacity = lerp(c_opacity, d_opacity, delta * 30)
else:
c_opacity = lerp(c_opacity, d_opacity, delta * 3)
func _draw():
draw_rect(c_pos, _lerp_opacity(highlight_color, c_opacity), true)

View File

@ -1,5 +1,2 @@
@tool
extends Node
func _center_rect(rect: Rect2) -> Rect2:
return Rect2(rect.size / -2, rect.size)

View File

@ -0,0 +1 @@
uid://b22r7vlrq7up0

View File

@ -5,7 +5,7 @@ const SIGNAL_SELECTION_CHANGED = "selection-changed"
@export var selected_box_hidden_color = Color(1, 1, 1, 0)
@export var selected_box_color = Color(1, 1, 1, 0.6)
@onready var selection: Array[Positional] = []
@onready var selection: Array[TileTransform] = []
var anim_t: float = 0.0
func _process(delta):
@ -19,11 +19,11 @@ func clear():
emit_signal(SIGNAL_SELECTION_CHANGED)
print("clear selection ", len(selection))
func append_array(items: Array[Positional]):
func append_array(items: Array[TileTransform]):
selection.append_array(items)
emit_signal(SIGNAL_SELECTION_CHANGED)
func select_array(items: Array[Positional]):
func select_array(items: Array[TileTransform]):
clear()
if items.is_empty():
return
@ -35,7 +35,7 @@ func _draw():
return
for tile in selection:
draw_rect(
tile.worldbox.grow(lerp(-16, 0, anim_t)),
tile.get_worldbox().grow(lerp(-16, 0, anim_t)),
lerp(selected_box_hidden_color, selected_box_color, anim_t ** 1.3),
false, 3
)

View File

@ -0,0 +1 @@
uid://cuqcfju7y8ply

View File

@ -3,28 +3,45 @@
extends Node2D
class_name TileRenderer
@export var target: Positional
@export var base_color: Color = Color.SPRING_GREEN
@export var top_color: Color = Color.WEB_GREEN
var drawbox: Rect2
var drawbox_top: Rect2
var tile_transform: TileTransform
var grid: Grid
var text_pos: Vector2
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
tile_transform = Util.find_parent_type(self, TileTransform)
grid = Util.find_parent_type(self, Grid)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta):
queue_redraw()
func _draw():
draw_circle(Vector2.ZERO, 10, Color.ANTIQUE_WHITE)
_update_drawbox()
draw_rect(drawbox, base_color, true)
draw_rect(drawbox_top, top_color, true)
draw_string(ThemeDB.fallback_font, text_pos, "House", HORIZONTAL_ALIGNMENT_CENTER, drawbox_top.size.x, 12)
func _update_drawbox():
var size = self.tile_transform.size * (self.grid.cell_size if self.grid != null else 100)
var box = Rect2(size / -2.0, size)
if not is_node_ready():
return
# drawbox = _center_rect(_inset_rect(worldbox, 5))
# drawbox_top = _center_rect(_inset_rect(worldbox, 7))
# drawbox_top.size.y -= 8
self.drawbox = box
self.drawbox_top = Rect2(
drawbox.position.x + 2.0,
drawbox.position.y + drawbox.size.y - 18.0,
drawbox.size.x - 4.0,
16.0
)
# drawbox_top.size.y = 16
text_pos = drawbox_top.position
text_pos.y += drawbox_top.size.y - 3

View File

@ -0,0 +1 @@
uid://2mbjbn23ry8t

View File

@ -1,6 +1,6 @@
@tool
extends Node2D
class_name Positional
class_name TileTransform
enum State {
CLEAN,
@ -19,7 +19,7 @@ enum State {
# - - - - - - - - - - - - - - - -
@onready var grid = Util.find(Grid)
var grid: Grid
var _worldbox: Rect2 = Rect2(0, 0, 0, 0)
var _tilebox: Rect2i = Rect2i(0, 0, 0, 0)
@ -27,6 +27,8 @@ var state: State = State.CLEAN
var has_adjusted_positions_this_frame = false
func _ready():
grid = Util.find_parent_type(self, Grid)
grid.register_tile(self)
set_notify_transform(true)
_quantize()
@ -37,8 +39,6 @@ func _process(_delta):
func _enter_tree():
set_notify_transform(true)
if grid != null:
grid.register_tile(self)
func _exit_tree():
if grid != null:
@ -58,16 +58,18 @@ func _position_updated():
pass
func _quantize():
if grid == null || !Engine.is_editor_hint() || !quantize_in_editor:
if Engine.is_editor_hint() && !quantize_in_editor:
return
if grid == null:
return
if has_adjusted_positions_this_frame:
state = State.UPDATE_POSITION
return
var top_left_world_pos = position - grid.tile2world_size(size - Vector2i.ONE) / 2
var tile_pos = grid.world2tile(top_left_world_pos)
_worldbox = grid.tile2world_rect(Rect2i(tile_pos, size))
position = _worldbox.get_center()
print("updated " + self.name + "'s world box to: " + str(self._worldbox))
state = State.CLEAN
has_adjusted_positions_this_frame = true

View File

@ -0,0 +1 @@
uid://cqhn1h452g2li

View File

@ -1,5 +1,4 @@
@tool
extends Node
func find(type):
@ -11,6 +10,20 @@ func find(type):
return _find_type_on_base(root, type)
func find_parent_type(node: Node, type: Script):
var current_node = node
if node == null:
return null
#print("Searching for " + type.get_global_name() + " from " + node.name)
var i = 0
while current_node != null and i < 10:
i += 1
if is_instance_of(current_node, type):
return current_node
current_node = current_node.get_parent()
return null;
func _find_type_on_base(base: Node, type):
if is_instance_of(base, type):
return base
@ -20,6 +33,8 @@ func _find_type_on_base(base: Node, type):
return found_node
return null
func center_rect(rect: Rect2) -> Rect2:
return Rect2(rect.size / -2, rect.size)
func is_debug():
return true

View File

@ -0,0 +1 @@
uid://dm0x2ko2cehhy

View File

@ -1,10 +1,12 @@
[gd_scene load_steps=3 format=3 uid="uid://cgygrdlj7ty6s"]
[ext_resource type="Script" path="res://Scripts/Positional.gd" id="1_jjdrc"]
[ext_resource type="Script" path="res://Scripts/TileRenderer.gd" id="2_p4boj"]
[ext_resource type="Script" uid="uid://cqhn1h452g2li" path="res://Scripts/TileTransform.gd" id="1_jjdrc"]
[ext_resource type="Script" uid="uid://2mbjbn23ry8t" path="res://Scripts/TileRenderer.gd" id="2_p4boj"]
[node name="Farm" type="Node2D"]
script = ExtResource("1_jjdrc")
[node name="TileRenderer" type="Node2D" parent="."]
script = ExtResource("2_p4boj")
base_color = Color(0.0828, 0.36, 0.13362, 1)
top_color = Color(0.0108, 0.18, 0.04182, 1)

View File

@ -1,30 +1,33 @@
[gd_scene load_steps=5 format=3 uid="uid://co6md8v2b8hhu"]
[ext_resource type="Script" path="res://Scripts/Grid.gd" id="1_2s04l"]
[ext_resource type="Script" path="res://Scripts/SelectionManager.gd" id="1_anesy"]
[ext_resource type="Script" uid="uid://8lkq20gwkrvx" path="res://Scripts/Grid.gd" id="1_2s04l"]
[ext_resource type="Script" uid="uid://cuqcfju7y8ply" path="res://Scripts/SelectionManager.gd" id="1_anesy"]
[ext_resource type="PackedScene" uid="uid://cgygrdlj7ty6s" path="res://Tiles/farm.tscn" id="2_7ixwv"]
[ext_resource type="Script" path="res://Scripts/Highlight.gd" id="3_62nr3"]
[ext_resource type="Script" uid="uid://xe60g0el2j5x" path="res://Scripts/GridInput.gd" id="3_62nr3"]
[node name="Root" type="Node2D"]
position = Vector2(13, -2)
[node name="Camera2D" type="Camera2D" parent="."]
[node name="Grid" type="Node2D" parent="."]
script = ExtResource("1_2s04l")
cells = 32
cell_size = 24
cells = 10
cell_size = 48
[node name="Tiles" type="Node" parent="Grid"]
[node name="Farm" parent="Grid" instance=ExtResource("2_7ixwv")]
position = Vector2(204, -132)
position = Vector2(-96, 192)
size = Vector2i(6, 2)
[node name="Farm2" parent="Grid" instance=ExtResource("2_7ixwv")]
position = Vector2(-108, -108)
position = Vector2(-144, -120)
size = Vector2i(2, 3)
[node name="Farm3" parent="Grid" instance=ExtResource("2_7ixwv")]
position = Vector2(-12, -156)
position = Vector2(168, -72)
[node name="Highlight" type="Node2D" parent="."]
[node name="GridInput" type="Node2D" parent="."]
script = ExtResource("3_62nr3")
highlight_color = Color(1, 1, 1, 0.301961)

View File

@ -0,0 +1 @@
uid://ba7h0healwg4

View File

@ -12,7 +12,7 @@ config_version=5
config/name="MobileGame"
run/main_scene="res://World.tscn"
config/features=PackedStringArray("4.2", "Mobile")
config/features=PackedStringArray("4.4", "Mobile")
config/icon="res://icon.svg"
[autoload]
@ -26,7 +26,7 @@ window/size/viewport_height=900
[editor_plugins]
enabled=PackedStringArray("res://addons/tile_helper/plugin.cfg")
enabled=PackedStringArray()
[rendering]