progress
This commit is contained in:
73
AGENTS.md
73
AGENTS.md
@@ -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
21
ActionState.gd
Normal 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
1
ActionState.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://gqmmvqddc8d4
|
||||
6
Ego.tscn
6
Ego.tscn
@@ -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
|
||||
|
||||
34
Game.tscn
34
Game.tscn
@@ -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)
|
||||
|
||||
@@ -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])
|
||||
|
||||
13
Scene.gd
13
Scene.gd
@@ -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
|
||||
|
||||
29
SetPiece_.gd
29
SetPiece_.gd
@@ -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")
|
||||
|
||||
20
UITheme.tres
20
UITheme.tres
@@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user