This commit is contained in:
2026-03-04 11:07:13 -08:00
parent 4742ed003c
commit a4cc5e8f5f
985 changed files with 3858 additions and 1206 deletions

View File

@@ -200,6 +200,79 @@ Each room has:
- `GameScript` (GameScript.gd) - Script builder for cutscenes
- `Ego` (Ego.gd) - Player character
## Interaction System (Global)
The game uses a **cursor-based action system** with 4 modes that cycle via right-click:
| Cursor | Action | Icon | Purpose |
|--------|--------|------|---------|
| 0 | Walk | boot_icon.png | Move player to location |
| 1 | Look | eye_icon.png | Examine objects/room |
| 2 | Touch | hand_icon.png | Interact with objects |
| 3 | Talk | speech_icon.png | Talk to characters |
### Key Components
#### ActionState (Autoload)
Global singleton (`ActionState.gd`) that tracks the current cursor action:
```gdscript
ActionState.current_action # 0-3 (WALK, LOOK, TOUCH, TALK)
ActionState.Action.WALK # Enum values
```
#### SetPiece Nodes
Interactive areas in rooms use `SetPiece_.gd` (extends Polygon2D):
**Signals emitted:**
- `interacted` - Generic interaction (takes precedence over cursor actions)
- `walked` - When walk cursor clicks the piece
- `looked` - When look cursor clicks the piece
- `touched` - When touch cursor clicks the piece
- `talked` - When talk cursor clicks the piece
**Priority Rule:** If `interacted` signal has connections, it overrides cursor-specific actions.
### Room Setup for Interactions
1. **Add SetPiece nodes** to room scene for interactive objects:
```gdscript
[node name="pool" type="Polygon2D" parent="."]
polygon = PackedVector2Array(...)
script = ExtResource("SetPiece_.gd")
label = "Pool"
```
2. **Connect signals** in .tscn:
```gdscript
[connection signal="looked" from="pool" to="." method="_on_pool_looked"]
```
3. **Implement handlers** in room script:
```gdscript
func _on_pool_looked() -> void:
start_main_script(ScriptBuilder.init(
ScriptBuilder.say(ego, "The water looks inviting.")
).build(self, "_on_script_complete"))
```
### Room-Wide Look
Clicking empty space with look cursor triggers `_on_room_looked()`:
```gdscript
func _on_room_looked() -> void:
# Override in room script for room description
start_main_script(ScriptBuilder.init(
ScriptBuilder.say(ego, "Room description here...")
).build(self, "_on_script_complete"))
```
### Behavior Rules
1. **Precedence**: `interacted` signal always wins if connected
2. **Fallback**: If no handler for cursor action, do nothing (silent)
3. **SetPiece detection**: Mouse must be inside polygon
4. **Unhandled clicks**: Scene._unhandled_input handles empty space
### Common Patterns
#### Navigation

21
ActionState.gd Normal file
View File

@@ -0,0 +1,21 @@
extends Node
enum Action { WALK = 0, LOOK = 1, TOUCH = 2, TALK = 3 }
var current_action: int = Action.WALK:
set(value):
current_action = value
action_changed.emit(value)
signal action_changed(new_action: int)
func get_action_name() -> String:
match current_action:
Action.WALK: return "walk"
Action.LOOK: return "look"
Action.TOUCH: return "touch"
Action.TALK: return "talk"
return "walk"
func get_action_enum() -> int:
return current_action

1
ActionState.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://gqmmvqddc8d4

View File

@@ -705,7 +705,7 @@ script = ExtResource("195")
[node name="Sprite2D" type="Sprite2D" parent="."]
modulate = Color(1, 1, 1, 0.490196)
position = Vector2(33, 20)
scale = Vector2(0.850195, 0.202601)
scale = Vector2(1.70039, 0.405202)
texture = ExtResource("2")
offset = Vector2(0, -500)
@@ -744,7 +744,7 @@ z_as_relative = false
texture_filter = 2
material = SubResource("ShaderMaterial_sle7q")
position = Vector2(-14, -13)
scale = Vector2(0.75, 0.75)
scale = Vector2(1.5, 1.5)
sprite_frames = SubResource("1")
animation = &"idle_SE"
frame_progress = 0.153569
@@ -756,7 +756,7 @@ visible = false
self_modulate = Color(0.929412, 0.929412, 0.929412, 1)
clip_children = 2
position = Vector2(-25, -52)
scale = Vector2(1.61328, 1)
scale = Vector2(3.22656, 2)
sprite_frames = SubResource("SpriteFrames_cfk81")
autoplay = "default"
frame_progress = 0.339611

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=19 format=3 uid="uid://dni0wqjh12rn6"]
[gd_scene format=3 uid="uid://dni0wqjh12rn6"]
[ext_resource type="Script" uid="uid://b2npq7lwis0ri" path="res://label.gd" id="1"]
[ext_resource type="Script" uid="uid://cv4llkc0yrjxa" path="res://MainGame.gd" id="2"]
@@ -9,7 +9,7 @@
[ext_resource type="Script" uid="uid://dsmai0fv8apie" path="res://GameScript.gd" id="5_rglkg"]
[ext_resource type="PackedScene" uid="uid://c0mp4a2u3jkd" path="res://portrait.tscn" id="7_fj12q"]
[ext_resource type="Script" uid="uid://bsvab128vy1ip" path="res://OffsetCameraBasedOnMovement.gd" id="8_cvftx"]
[ext_resource type="PackedScene" uid="uid://dx5rhiwa1tnvx" path="res://scenes/kq4_003_fountain_pool/kq4_003_fountain_pool.tscn" id="8_yx171"]
[ext_resource type="PackedScene" uid="uid://dyk4rcqsk3aed" path="res://scenes/kq4_003_fountain_pool/kq4_003_fountain_pool.tscn" id="8_yx171"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_44mjr"]
shader = ExtResource("2_jr51a")
@@ -72,44 +72,42 @@ font_size = 32
outline_size = 5
outline_color = Color(0, 0, 0, 1)
[node name="Node2D" type="Node2D"]
[node name="Node2D" type="Node2D" unique_id=826166852]
script = ExtResource("2")
[node name="SceneDisplay" type="CanvasLayer" parent="."]
[node name="SceneDisplay" type="CanvasLayer" parent="." unique_id=1739356944]
[node name="SceneTexture" type="Sprite2D" parent="SceneDisplay"]
[node name="SceneTexture" type="Sprite2D" parent="SceneDisplay" unique_id=1754946621]
texture_filter = 2
material = SubResource("ShaderMaterial_44mjr")
texture = SubResource("ViewportTexture_wppwg")
centered = false
script = ExtResource("3_a4qo8")
[node name="Fade" type="Sprite2D" parent="SceneDisplay"]
[node name="Fade" type="Sprite2D" parent="SceneDisplay" unique_id=256457664]
modulate = Color(1, 1, 1, 0)
position = Vector2(-17, -7)
scale = Vector2(2048, 2048)
texture = SubResource("6")
centered = false
[node name="FadePlayer" type="AnimationPlayer" parent="SceneDisplay/Fade"]
[node name="FadePlayer" type="AnimationPlayer" parent="SceneDisplay/Fade" unique_id=1894226220]
unique_name_in_owner = true
libraries = {
&"": SubResource("AnimationLibrary_nmfun")
}
libraries/ = SubResource("AnimationLibrary_nmfun")
[node name="SceneViewport" type="SubViewport" parent="."]
[node name="SceneViewport" type="SubViewport" parent="." unique_id=1826796630]
handle_input_locally = false
msaa_2d = 2
screen_space_aa = 1
physics_object_picking = true
size = Vector2i(1920, 1080)
[node name="label" type="Node2D" parent="SceneViewport"]
[node name="label" type="Node2D" parent="SceneViewport" unique_id=677429968]
z_index = 1
position = Vector2(1442.87, 661.499)
script = ExtResource("1")
[node name="label" type="Label" parent="SceneViewport/label"]
[node name="label" type="Label" parent="SceneViewport/label" unique_id=1495298472]
offset_left = 53.2751
offset_top = 6.65936
offset_right = 461.275
@@ -117,9 +115,9 @@ offset_bottom = 110.659
theme = ExtResource("4")
label_settings = SubResource("LabelSettings_va2rf")
[node name="PlayerTracker" type="Node2D" parent="SceneViewport"]
[node name="PlayerTracker" type="Node2D" parent="SceneViewport" unique_id=752944130]
[node name="Camera2D" type="Camera2D" parent="SceneViewport/PlayerTracker"]
[node name="Camera2D" type="Camera2D" parent="SceneViewport/PlayerTracker" unique_id=1215014860]
limit_left = 0
limit_top = 0
limit_right = 99999999
@@ -129,12 +127,12 @@ position_smoothing_enabled = true
position_smoothing_speed = 1.385
script = ExtResource("8_cvftx")
[node name="background" parent="SceneViewport" instance=ExtResource("8_yx171")]
[node name="background" parent="SceneViewport" unique_id=1906581101 instance=ExtResource("8_yx171")]
[node name="GameScript" type="Node" parent="."]
[node name="GameScript" type="Node" parent="." unique_id=947629093]
unique_name_in_owner = true
script = ExtResource("5_rglkg")
[node name="dialogue" parent="." instance=ExtResource("7_fj12q")]
[node name="dialogue" parent="." unique_id=186154081 instance=ExtResource("7_fj12q")]
position = Vector2(328, 106)
scale = Vector2(0.75, 0.75)

View File

@@ -58,7 +58,5 @@ func _input(event):
if event.is_action_released("quit"):
get_tree().quit()
if event.is_action_released("right_click"):
cursor_index = cursor_index +1
if cursor_index >= cursors.size():
cursor_index = 0
Input.set_custom_mouse_cursor(cursors[cursor_index])
ActionState.current_action = (ActionState.current_action + 1) % 4
Input.set_custom_mouse_cursor(cursors[ActionState.current_action])

View File

@@ -125,6 +125,17 @@ func start_main_script(s):
func _unhandled_input(event):
if event is InputEventMouseButton and event.is_action("interact"):
print (ego.position, pathfind.to_local(get_global_mouse_position()))
var path = NavigationServer2D.map_get_path(map, ego.position, pathfind.to_local(get_global_mouse_position()), true)
# If look cursor is active and we got here, no SetPiece handled the input
# so this is a room-wide look
if ActionState.current_action == ActionState.Action.LOOK:
_on_room_looked()
return
var path = NavigationServer2D.map_get_path(map, ego.position, pathfind.to_local(get_global_mouse_position()), true)
start_main_script(ScriptBuilder.init(ScriptBuilder.walk_path(ego, path)).can_interrupt().build(self, "_on_script_complete"))
pass
func _on_room_looked() -> void:
# Default room look description - override in room scripts
pass

View File

@@ -12,7 +12,7 @@ extends Polygon2D
func _ready():
self.color.a = 0.25
if Engine.is_editor_hint():
self.color.a = 0.25
self.color.a = 0.25
notify_property_list_changed()
pass
else:
@@ -20,6 +20,10 @@ func _ready():
pass # Replace with function body.
signal interacted
signal walked
signal looked
signal touched
signal talked
signal entered(lab)
signal exited
@@ -33,7 +37,7 @@ func _process(delta):
else:
if Geometry2D.is_point_in_polygon(to_local(get_global_mouse_position()), self.polygon):
if is_in == false:
is_in = true
is_in = true
emit_signal("entered", label)
else:
if is_in == true:
@@ -47,4 +51,23 @@ func _input(event):
if Geometry2D.is_point_in_polygon(to_local(get_global_mouse_position()), self.polygon):
if event is InputEventMouseButton and event.is_action("interact"):
get_viewport().set_input_as_handled()
emit_signal("interacted")
# Check if interacted signal has connections - it takes precedence
if interacted.get_connections().size() > 0:
emit_signal("interacted")
return
# Otherwise, emit action-specific signal based on current cursor
match ActionState.current_action:
ActionState.Action.WALK:
if walked.get_connections().size() > 0:
emit_signal("walked")
ActionState.Action.LOOK:
if looked.get_connections().size() > 0:
emit_signal("looked")
ActionState.Action.TOUCH:
if touched.get_connections().size() > 0:
emit_signal("touched")
ActionState.Action.TALK:
if talked.get_connections().size() > 0:
emit_signal("talked")

View File

@@ -1,4 +1,4 @@
[gd_resource type="Theme" load_steps=25 format=4 uid="uid://dkli02kmdncbc"]
[gd_resource type="Theme" format=4 uid="uid://dkli02kmdncbc"]
[sub_resource type="Image" id="Image_n80ss"]
data = {
@@ -205,6 +205,15 @@ style_name = "Regular"
subpixel_positioning = 0
msdf_pixel_range = 14
msdf_size = 128
cache/0/variation_coordinates = {}
cache/0/face_index = 0
cache/0/embolden = 0.0
cache/0/transform = Transform2D(1, 0, 0, 1, 0, 0)
cache/0/spacing_top = 0
cache/0/spacing_bottom = 0
cache/0/spacing_space = 0
cache/0/spacing_glyph = 0
cache/0/baseline_offset = 0.0
cache/0/16/0/ascent = 13.0
cache/0/16/0/descent = 4.0
cache/0/16/0/underline_position = 1.59375
@@ -1506,6 +1515,15 @@ cache/0/32/5/glyphs/91/texture_idx = 0
[sub_resource type="FontFile" id="3"]
fallbacks = Array[Font]([SubResource("2")])
cache/0/variation_coordinates = {}
cache/0/face_index = 0
cache/0/embolden = 0.0
cache/0/transform = Transform2D(1, 0, 0, 1, 0, 0)
cache/0/spacing_top = 0
cache/0/spacing_bottom = 0
cache/0/spacing_space = 0
cache/0/spacing_glyph = 0
cache/0/baseline_offset = 0.0
cache/0/16/0/ascent = 0.0
cache/0/16/0/descent = 0.0
cache/0/16/0/underline_position = 0.0

Binary file not shown.

View File

@@ -18,6 +18,8 @@ dest_files=["res://.godot/imported/idle-med.png-0138e16d5f660e8411756bbd4065cd26
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
@@ -25,6 +27,10 @@ mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

Binary file not shown.

View File

@@ -18,6 +18,8 @@ dest_files=["res://.godot/imported/idle-s-med.png-2ec519a8bcf274402acb959afd6f7b
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
@@ -25,6 +27,10 @@ mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

Some files were not shown because too many files have changed in this diff Show More