hadean-godot/Scripts/GridInput.gd

214 lines
6.4 KiB
GDScript

extends Node2D
class_name GridInput
@onready var grid: Grid = $/root/Root/Grid
var highlight_color: Color = Color(1.0, 1.0, 1.0, 0.38)
var build_color: Color = Color(0.087, 0.62, 0.087, 0.514)
var deletion_color: Color = Color(0.76, 0.237, 0.106, 0.4)
var current_color = highlight_color
var cursor_pool: CursorPool
func _ready():
cursor_pool = Util.find_child_type(self, CursorPool)
enum AreaType {
Rectangle,
Line,
None,
}
var current_marquee_type: AreaType = AreaType.Rectangle
# === RAW MOUSE EVENTS ===
# first we process inputs raw and separate them out into something digestable
# This uses some state data!
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:
_update_drag(get_local_mouse_position())
else:
_update_hover(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:
_left_click(get_local_mouse_position())
elif event.button_index == 2 && event.pressed:
_right_click(get_local_mouse_position())
# for now, lets pretend these are simple :)
func _left_click(pos: Vector2):
if !grid.contains_world_pos(pos): return
var tile_pos = grid.world2tile(pos)
_grid_clicked(tile_pos)
func _right_click(pos: Vector2):
_cancel_operation()
#cursor_pool.explode()
#if !mouse_in_grid: return
#cursor_pool.new_cursor(current_color)
#_update_cursor()
var mouse_in_grid: bool = false # TODO init this correctly lol
func __mouse_may_have_left_or_entered_grid(pos: Vector2):
var new_mouse_in_grid = grid.contains_world_pos(pos)
var mouse_entered_grid = new_mouse_in_grid && !mouse_in_grid
var mouse_left_grid = !new_mouse_in_grid && mouse_in_grid
mouse_in_grid = new_mouse_in_grid
if mouse_entered_grid: _mouse_enter_grid()
elif mouse_left_grid: _mouse_leave_grid()
func _update_hover(pos: Vector2):
__mouse_may_have_left_or_entered_grid(pos)
if !mouse_in_grid: return
_mouse_hover_grid(pos)
# while dragging will attempt to begin marquee selection
var in_marquee: bool = false
var marquee_start_tile: Vector2i = Vector2i.ZERO
func __get_current_marquee_area(pos: Vector2i):
var marquee_end_tile = grid.world2tile(pos)
match current_marquee_type:
AreaType.Rectangle:
return Rect2i(marquee_start_tile, Vector2i.ONE).merge(Rect2i(marquee_end_tile, Vector2i.ONE))
AreaType.Line:
var vertical = Rect2i(marquee_start_tile, Vector2i.ONE).merge(Rect2i(Vector2i(marquee_start_tile.x, marquee_end_tile.y), Vector2i.ONE))
var horizontal = Rect2i(marquee_start_tile, Vector2i.ONE).merge(Rect2i(Vector2i(marquee_end_tile.x, marquee_start_tile.y), Vector2i.ONE))
return vertical if vertical.get_area() > horizontal.get_area() else horizontal
func _begin_drag(pos: Vector2):
__mouse_may_have_left_or_entered_grid(pos)
if !mouse_in_grid: return
in_marquee = true
marquee_start_tile = grid.world2tile(pos)
_begin_marquee(marquee_start_tile)
func _update_drag(pos: Vector2):
__mouse_may_have_left_or_entered_grid(pos)
if !mouse_in_grid: return
if !in_marquee: return
var new_area = __get_current_marquee_area(pos)
_update_marquee(new_area)
func _end_drag(pos: Vector2):
if !in_marquee:
cursor_pool.new_cursor(current_color)
_update_cursor()
return
var final_area = __get_current_marquee_area(pos)
if !mouse_in_grid:
_cancel_marquee()
else:
_end_marquee(final_area)
in_marquee = false
# === PROCESSED GAME INTERACTION EVENTS ===
func _mouse_enter_grid():
if !in_marquee && !_left_dragging:
cursor_pool.new_cursor(current_color)
if in_marquee:
cursor_pool.new_cursor(current_color)
cursor_pool.current_cursor.animation = \
cursor_pool.AnimationState.Area
func _mouse_leave_grid():
cursor_pool.fade_out()
func _mouse_hover_grid(world_pos: Vector2):
_update_cursor()
func _cancel_operation():
clear_request()
func _begin_marquee(tile_pos: Vector2i):
cursor_pool.current_cursor.desired_box = \
grid.tile2world_rect(Rect2i(tile_pos, Vector2i.ONE))
cursor_pool.current_cursor.animation = CursorPool.AnimationState.Area
func _update_marquee(area: Rect2i):
cursor_pool.current_cursor.desired_box = \
grid.tile2world_rect(area)
func _end_marquee(area: Rect2i):
_area_selected(area)
cursor_pool.explode()
cursor_pool.new_cursor(current_color)
_update_cursor()
func _cancel_marquee():
cursor_pool.explode()
if !mouse_in_grid: return
cursor_pool.new_cursor(current_color)
func _grid_clicked(tile_pos: Vector2i):
_area_selected(Rect2i(tile_pos, Vector2i.ONE))
cursor_pool.explode()
cursor_pool.new_cursor(current_color)
_update_cursor()
pass
func _update_cursor(world_pos = get_local_mouse_position()):
cursor_pool.current_cursor.desired_box = \
grid.quantize_on_objects(world_pos)
enum Style {
Highlight,
Build,
Delete
}
class Request:
var context: Variant
var confirmed
var cancelled
var request: Request = null
var one_shot: bool = false
@export var selection_manager: SelectionManager
func _area_selected(area: Rect2i):
if request != null:
request.confirmed.call(request.context, area)
if one_shot: _reset()
return
if area.size == Vector2i.ONE:
var item = grid._get_building_at(area.position)
if item != null:
selection_manager.select_array([item])
return
if item == null:
selection_manager.clear()
func clear_request():
if request == null: return
request.cancelled.call(request.context)
request = null
_reset()
func request_area(ctx, confirm, cancel, style: Style, area_type: AreaType, one_shot: bool):
if request != null:
clear_request()
request = Request.new()
request.confirmed = confirm
request.cancelled = cancel
request.context = ctx
current_marquee_type = area_type
_set_style(style)
func _reset():
_set_style(Style.Highlight)
current_marquee_type = AreaType.Rectangle
func _set_style(style: Style):
match style:
Style.Highlight: current_color = highlight_color
Style.Build: current_color = build_color
Style.Delete: current_color = deletion_color
cursor_pool.change_color(current_color)