feat(poc): implement Sprint 1 proof of concept
- project.godot with autoload configuration - Reception room with placeholder visuals - Draggable Character with DragDropComponent - Interactive flower object with bounce animation - GameState, SaveManager, AudioManager, InputManager autoloads - HUD with back button and music toggle Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
80
scripts/systems/drag_drop_component.gd
Normal file
80
scripts/systems/drag_drop_component.gd
Normal file
@@ -0,0 +1,80 @@
|
||||
## DragDropComponent — reusable drag-and-drop node; attach to any Character or InteractiveObject.
|
||||
class_name DragDropComponent extends Node
|
||||
|
||||
signal drag_picked_up(global_position: Vector2)
|
||||
signal drag_released(global_position: Vector2)
|
||||
|
||||
const DRAG_Z_INDEX: int = 10
|
||||
const DRAG_SCALE: float = 1.1
|
||||
|
||||
@export var drag_target: Node2D
|
||||
|
||||
var _is_dragging: bool = false
|
||||
var _drag_offset: Vector2 = Vector2.ZERO
|
||||
var _original_z_index: int = 0
|
||||
var _original_scale: Vector2 = Vector2.ONE
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
if drag_target == null:
|
||||
drag_target = get_parent() as Node2D
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventScreenTouch:
|
||||
_handle_press(event.pressed, event.position)
|
||||
elif event is InputEventScreenDrag and _is_dragging:
|
||||
_move_to(event.position)
|
||||
elif event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
|
||||
_handle_press(event.pressed, event.position)
|
||||
elif event is InputEventMouseMotion and _is_dragging:
|
||||
_move_to(event.position)
|
||||
|
||||
|
||||
func _handle_press(pressed: bool, screen_pos: Vector2) -> void:
|
||||
if pressed and _is_position_over_target(screen_pos):
|
||||
_start_drag(screen_pos)
|
||||
elif not pressed and _is_dragging:
|
||||
_end_drag(screen_pos)
|
||||
|
||||
|
||||
func _start_drag(screen_pos: Vector2) -> void:
|
||||
_is_dragging = true
|
||||
var world_pos: Vector2 = _screen_to_world(screen_pos)
|
||||
_drag_offset = drag_target.global_position - world_pos
|
||||
_original_z_index = drag_target.z_index
|
||||
_original_scale = drag_target.scale
|
||||
drag_target.z_index = DRAG_Z_INDEX
|
||||
drag_target.scale = _original_scale * DRAG_SCALE
|
||||
drag_picked_up.emit(drag_target.global_position)
|
||||
|
||||
|
||||
func _end_drag(_screen_pos: Vector2) -> void:
|
||||
_is_dragging = false
|
||||
drag_target.z_index = _original_z_index
|
||||
drag_target.scale = _original_scale
|
||||
drag_released.emit(drag_target.global_position)
|
||||
|
||||
|
||||
func _move_to(screen_pos: Vector2) -> void:
|
||||
var world_pos: Vector2 = _screen_to_world(screen_pos)
|
||||
drag_target.global_position = world_pos + _drag_offset
|
||||
|
||||
|
||||
func _screen_to_world(screen_pos: Vector2) -> Vector2:
|
||||
var canvas_transform: Transform2D = drag_target.get_viewport().get_canvas_transform()
|
||||
return canvas_transform.affine_inverse() * screen_pos
|
||||
|
||||
|
||||
func _is_position_over_target(screen_pos: Vector2) -> bool:
|
||||
if drag_target == null:
|
||||
return false
|
||||
var world_pos: Vector2 = _screen_to_world(screen_pos)
|
||||
var local_pos: Vector2 = drag_target.to_local(world_pos)
|
||||
var area: Area2D = drag_target.get_node_or_null("CollisionArea") as Area2D
|
||||
if area == null:
|
||||
return local_pos.length() < 64.0
|
||||
for child in area.get_children():
|
||||
if child is CollisionShape2D and child.shape != null:
|
||||
return child.shape.get_rect().has_point(local_pos)
|
||||
return local_pos.length() < 64.0
|
||||
21
scripts/systems/hud.gd
Normal file
21
scripts/systems/hud.gd
Normal file
@@ -0,0 +1,21 @@
|
||||
## HUD — heads-up display with back button and music toggle.
|
||||
extends CanvasLayer
|
||||
|
||||
var _music_enabled: bool = true
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
pass
|
||||
|
||||
|
||||
func _on_back_button_pressed() -> void:
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
func _on_music_toggle_pressed() -> void:
|
||||
_music_enabled = not _music_enabled
|
||||
var volume: float = AudioManager.DEFAULT_MUSIC_VOLUME if _music_enabled else 0.0
|
||||
AudioManager.set_music_volume(volume)
|
||||
var btn: Button = get_node_or_null("MusicToggle") as Button
|
||||
if btn != null:
|
||||
btn.text = "♪" if _music_enabled else "✕"
|
||||
Reference in New Issue
Block a user