From 35095a84dd0f304cd1ad770a57bdbec28cf18ae0 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 7 Oct 2023 02:59:58 +0200 Subject: [PATCH] Refactor `Ghost`'s placement feature into a separate `PrecisePlacement` node --- interface/ghost/ghost.gd | 99 ------------------------ interface/ghost/ghost.tscn | 5 +- interface/ghost/precise_placement.gd | 101 +++++++++++++++++++++++++ interface/ghost/precise_placement.tscn | 6 ++ 4 files changed, 111 insertions(+), 100 deletions(-) create mode 100644 interface/ghost/precise_placement.gd create mode 100644 interface/ghost/precise_placement.tscn diff --git a/interface/ghost/ghost.gd b/interface/ghost/ghost.gd index 0aacff3..7f9ab7e 100644 --- a/interface/ghost/ghost.gd +++ b/interface/ghost/ghost.gd @@ -41,111 +41,12 @@ var can_place: bool: preview_sprite.modulate = Color(1.0, 0.0, 0.0, 0.5) -## Whether the ghost is currently being dragged or not. -var is_being_dragged: bool - - func _ready(): collision_mask = collision_mask_prevent_placement | collision_mask_delete_placement preview_sprite.texture = preview_texture -## The degrees to rotate by when rotation is quantized. -@export_range(1, 180, 1) var rotation_quantized_degrees: float = 45 - -## The degrees to rotate by when rotation is quantized and precise rotation is being requested. -@export_range(1, 180, 1) var rotation_quantized_precise_degrees: float = 5 - - -## Get the degrees a piece should be rotated by when rotation is quantized. -func get_rotation_quantized_degrees() -> float: - var degrees = rotation_quantized_precise_degrees if Input.is_action_pressed("ghost_precise") else rotation_quantized_degrees - var intensity = 1.0 if Input.is_action_just_pressed("ghost_clockwise") else 0.0 - 1.0 if Input.is_action_just_pressed("ghost_counterclockwise") else 0.0 - return degrees * intensity - -## The last [InputEventMouse] received. -var last_mouse_event: InputEventMouse = null - -## The last [InputEventScreenTouch] or [InputEventScreenDrag] received for each possible touch index. -var last_touch_events: Array[InputEvent] = [ - null, null, null, null, null, - null, null, null, null, null, -] - -func count_active_touch_events() -> int: - var total = 0 - for event in last_touch_events: - if event != null: - total += 1 - return total - -func _input(event: InputEvent): - # Count active events - var count = count_active_touch_events() - #print("[Ghost] Counting ", count, " active events!") - - # Mouse drag - if count == 0: - # Mouse drag - if event is InputEventMouseMotion and last_mouse_event: - position += event.relative - # Touch drag - elif count == 1: - # Touch drag - if event is InputEventScreenDrag: - position += event.relative - # Handle rotation - elif count == 2: - # Find the previous event - var previous - if event is InputEventScreenTouch or event is InputEventScreenDrag: - previous = last_touch_events[event.index] - # At this point previous shouldn't be null - # If it is, just try again at the next frame - if previous == null: - #print("[Ghost] Rotation occurred, but previous was null, so it was cancelled.") - return - # Find the other event - var other - for last_touch_index in len(last_touch_events): - if event is InputEventScreenTouch or event is InputEventScreenDrag: - if event.index == last_touch_index: - continue - if last_touch_events[last_touch_index] != null: - other = last_touch_events[last_touch_index] - # At this point other shouldn't be null - # If it is, just try again at the next frame - if other == null: - #print("[Ghost] Rotation occurred, but other was null, so it was cancelled.") - return - # Find the two vectors between the touches, one using the previous position, and one using the current one - var previous_vec: Vector2 = previous.position - other.position - var current_vec: Vector2 = event.position - other.position - #print("[Ghost] previous_vec: ", previous_vec, " | current_vec: ", current_vec) - # Find the angle between the two vectors - var rotation_radians = previous_vec.angle_to(current_vec) - #print("[Ghost] Rotation was successful, rotating by: ", rotation_radians) - # Apply the rotation - rotation += rotation_radians - - # Store last events - if event is InputEventMouseButton: - last_mouse_event = event if event.pressed else null - #print("[Ghost] last_mouse_event updated in response to a InputEventMouseButton: ", last_mouse_event) - elif event is InputEventMouseMotion and last_mouse_event != null: - last_mouse_event = event - #print("[Ghost] last_mouse_event updated in response to a InputEventMouseMotion: ", last_mouse_event) - elif event is InputEventScreenTouch: - last_touch_events[event.index] = event if event.pressed else null - #print("[Ghost] last_touch_events[", event.index , "] updated in response to a InputEventScreenTouch: ", last_mouse_event) - elif event is InputEventScreenDrag: - last_touch_events[event.index] = event - #print("[Ghost] last_touch_events[", event.index , "] updated in response to a InputEventScreenDrag: ", last_mouse_event) - - func _physics_process(_delta: float): - # Handle quantized rotation - rotation_degrees += get_rotation_quantized_degrees() # Update collision update_can_place() diff --git a/interface/ghost/ghost.tscn b/interface/ghost/ghost.tscn index 297f6ab..3d96549 100644 --- a/interface/ghost/ghost.tscn +++ b/interface/ghost/ghost.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=3 format=3 uid="uid://qtk4tm6l367w"] +[gd_scene load_steps=4 format=3 uid="uid://qtk4tm6l367w"] [ext_resource type="Script" path="res://interface/ghost/ghost.gd" id="1_1bq64"] [ext_resource type="PackedScene" uid="uid://c3p0jdf7416ac" path="res://converters/full_converter_shape.tscn" id="2_bo8dp"] +[ext_resource type="PackedScene" uid="uid://cgpjm06hleokk" path="res://interface/ghost/precise_placement.tscn" id="3_70ahv"] [node name="Ghost" type="Area2D"] collision_layer = 0 @@ -17,3 +18,5 @@ scale = Vector2(2.5, 2.5) [node name="PreviewSprite" type="Sprite2D" parent="PlacementShape"] modulate = Color(1, 1, 1, 0.5) z_index = 10 + +[node name="PrecisePlacement" parent="." instance=ExtResource("3_70ahv")] diff --git a/interface/ghost/precise_placement.gd b/interface/ghost/precise_placement.gd new file mode 100644 index 0000000..b12fa63 --- /dev/null +++ b/interface/ghost/precise_placement.gd @@ -0,0 +1,101 @@ +extends Node +class_name PrecisePlacement + + +## The degrees to rotate by when rotation is quantized. +@export_range(1, 180, 1) var rotation_quantized_degrees: float = 45 + +## The degrees to rotate by when rotation is quantized and precise rotation is being requested. +@export_range(1, 180, 1) var rotation_quantized_precise_degrees: float = 5 + + +## The [Node2D] this script should act on. +@onready var target: Node2D = get_parent() + + +## Whether the target is currently being dragged or not. +var is_dragging: bool = false + +## The last [InputEventMouse] received. +var last_mouse_event: InputEventMouse = null + +## The last [InputEventScreenTouch] or [InputEventScreenDrag] received for each possible touch index. +var last_touch_events: Array[InputEvent] = [ + null, null, null, null, null, + null, null, null, null, null, +] + + +## Count the number of non-[null] [last_touch_events]. +func count_active_touch_events() -> int: + var total = 0 + for event in last_touch_events: + if event != null: + total += 1 + return total + +## Handle event-based input +func _input(event: InputEvent): + # Count active events + var count = count_active_touch_events() + + # Mouse drag + if count == 0: + # Mouse drag + if event is InputEventMouseMotion and last_mouse_event: + target.position += event.relative + # Touch drag + elif count == 1: + # Touch drag + if event is InputEventScreenDrag: + target.position += event.relative + # Handle rotation + elif count == 2: + # Find the previous event + var previous + if event is InputEventScreenTouch or event is InputEventScreenDrag: + previous = last_touch_events[event.index] + # At this point previous shouldn't be null + # If it is, just try again at the next frame + if previous == null: + return + # Find the other event + var other + for last_touch_index in len(last_touch_events): + if event is InputEventScreenTouch or event is InputEventScreenDrag: + if event.index == last_touch_index: + continue + if last_touch_events[last_touch_index] != null: + other = last_touch_events[last_touch_index] + # At this point other shouldn't be null + # If it is, just try again at the next frame + if other == null: + return + # Find the two vectors between the touches, one using the previous position, and one using the current one + var previous_vec: Vector2 = previous.position - other.position + var current_vec: Vector2 = event.position - other.position + # Find the angle between the two vectors + var rotation_radians = previous_vec.angle_to(current_vec) + # Apply the rotation + target.rotation += rotation_radians + + # Store last events + if event is InputEventMouseButton: + last_mouse_event = event if event.pressed else null + elif event is InputEventMouseMotion and last_mouse_event != null: + last_mouse_event = event + elif event is InputEventScreenTouch: + last_touch_events[event.index] = event if event.pressed else null + elif event is InputEventScreenDrag: + last_touch_events[event.index] = event + +## Get the degrees that the target should be rotated by in a given frame when rotation is quantized. +func get_rotation_quantized_degrees() -> float: + var degrees = rotation_quantized_precise_degrees if Input.is_action_pressed("ghost_precise") else rotation_quantized_degrees + var intensity = 1.0 if Input.is_action_just_pressed("ghost_clockwise") else 0.0 - 1.0 if Input.is_action_just_pressed("ghost_counterclockwise") else 0.0 + return degrees * intensity + +## Handle polling-based input +func _physics_process(_delta): + # Handle quantized rotation + target.rotation_degrees += get_rotation_quantized_degrees() diff --git a/interface/ghost/precise_placement.tscn b/interface/ghost/precise_placement.tscn new file mode 100644 index 0000000..81189b8 --- /dev/null +++ b/interface/ghost/precise_placement.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://cgpjm06hleokk"] + +[ext_resource type="Script" path="res://interface/ghost/precise_placement.gd" id="1_e7b5h"] + +[node name="PrecisePlacement" type="Node"] +script = ExtResource("1_e7b5h")