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