feat: Enhance Trigger Area Reliability in Sandbox Stage

- Updated `_rule_matches` to ensure `entered_area` checks both source and target instance IDs for accurate event triggering.
- Refined `_update_area_entry` to utilize `_movable_overlaps_area`, ensuring that visible stickman/prop geometry is considered for area overlap detection.
- Introduced a new regression test suite in `tests/test_phase4c_area.gd` to validate the functionality of `entered_area` rules, covering various edge cases and ensuring correct behavior for source-specific and wildcard rules.
- Documented the architectural changes and validation results in `specs/phase_4c_area.md`, detailing the scope, data contracts, and design decisions made during implementation.
- Added new agent configurations for architect, developer, and writer roles to streamline the development process and improve documentation practices.
This commit is contained in:
2026-09-11 15:43:08 -04:00
parent 31282313be
commit 04e0f1bea2
11 changed files with 489 additions and 9 deletions
+14 -2
View File
@@ -2436,7 +2436,7 @@ func _rule_matches(rule: Dictionary, event: Dictionary) -> bool:
"speech_finished":
return _ids_match(source_id, source)
"entered_area":
return _ids_match(target_id, target)
return _ids_match(source_id, source) and _ids_match(target_id, target)
"collided":
return _ids_match(source_id, source) and _ids_match(target_id, target)
_:
@@ -2492,7 +2492,7 @@ func _update_area_entry() -> void:
for node: Node2D in movables:
var point := _movable_point(node)
var key := "%d:%d" % [area.get_instance_id(), node.get_instance_id()]
var inside: bool = area_rect.has_point(point)
var inside: bool = _movable_overlaps_area(node, area_rect)
var was: bool = bool(_area_overlap.get(key, false))
if inside and not was:
_area_overlap[key] = true
@@ -2533,6 +2533,18 @@ func _movable_point(node: Node2D) -> Vector2:
return node.global_position
## Trigger entry follows the visible object, not only its origin/feet anchor.
## StageSelection already owns the mounted-geometry world AABB contract used by
## selection and gizmos, so reuse it here to keep what the user sees and what
## the event engine detects in agreement. Point-like fallbacks retain the old
## behavior for any future movable without visual bounds.
func _movable_overlaps_area(node: Node2D, area_rect: Rect2) -> bool:
var bounds := STAGE_SELECTION.get_world_aabb(node).abs()
if bounds.size.is_zero_approx():
return area_rect.has_point(_movable_point(node))
return area_rect.intersects(bounds, true)
func _show_toast(msg: String) -> void:
_toast_text = msg
_toast_timer = 2.0