214 lines
5.9 KiB
GDScript
214 lines
5.9 KiB
GDScript
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())
|