Implement collision bodies, physics events, and hit reactions for StickmanRig
- Added a new specification for collision bodies, detailing the implementation requirements and corrections needed in the StickmanRig, PropBlock, and SandboxStage scripts. - Created a comprehensive test suite for collision bodies, including tests for proxy geometry, physics alignment, reaction handling, ghost collision, and stage contact routing. - Ensured that the collision system correctly handles ragdoll transitions and maintains the integrity of existing event rules. - Introduced new methods in StickmanRig for managing collision bodies and applying reactions based on impact direction and speed. - Updated PropBlock to emit signals for collisions and separations, preserving the order of events for stickman and prop interactions.
This commit is contained in:
+26
-3
@@ -33,6 +33,7 @@ const CIRCLE_SEGMENTS: int = 48
|
||||
const DEFAULT_FILL_COLOR := Color(0.55, 0.35, 0.15, 1.0)
|
||||
const DEFAULT_OUTLINE_COLOR := Color(0.15, 0.08, 0.02, 1.0)
|
||||
const DEFAULT_OUTLINE_WIDTH: float = 2.0
|
||||
const MAX_CONTACTS_REPORTED := 32
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Exported properties
|
||||
@@ -94,7 +95,8 @@ var _circle_shape: CircleShape2D
|
||||
|
||||
## Emitted when this prop's body makes contact with another physics body.
|
||||
## `other` is the body that entered contact (Phase 4 trigger source).
|
||||
signal collided(other: Node)
|
||||
signal collided(other: Node, contact_normal: Vector2, contact_position: Vector2)
|
||||
signal separated(other: Node)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Lifecycle
|
||||
@@ -106,13 +108,34 @@ func _ready() -> void:
|
||||
_apply_style()
|
||||
# Enable contact reporting so the body_entered signal fires (Phase 4).
|
||||
contact_monitor = true
|
||||
max_contacts_reported = 8
|
||||
max_contacts_reported = MAX_CONTACTS_REPORTED
|
||||
continuous_cd = RigidBody2D.CCD_MODE_CAST_SHAPE
|
||||
if not body_entered.is_connected(_on_body_entered):
|
||||
body_entered.connect(_on_body_entered)
|
||||
if not body_exited.is_connected(_on_body_exited):
|
||||
body_exited.connect(_on_body_exited)
|
||||
|
||||
|
||||
func _on_body_entered(body: Node) -> void:
|
||||
collided.emit(body)
|
||||
var center: Vector2 = (body as Node2D).global_position if body is Node2D else global_position
|
||||
var normal: Vector2 = (center - global_position).normalized()
|
||||
var position: Vector2 = global_position
|
||||
var direct_state := PhysicsServer2D.body_get_direct_state(get_rid())
|
||||
if direct_state != null:
|
||||
for index: int in direct_state.get_contact_count():
|
||||
if direct_state.get_contact_collider_id(index) == body.get_instance_id():
|
||||
var reported: Vector2 = direct_state.get_contact_local_normal(index)
|
||||
if not reported.is_zero_approx():
|
||||
normal = reported.normalized()
|
||||
if normal.dot(center - global_position) < 0.0:
|
||||
normal = -normal
|
||||
position = direct_state.get_contact_local_position(index)
|
||||
break
|
||||
collided.emit(body, normal, position)
|
||||
|
||||
|
||||
func _on_body_exited(body: Node) -> void:
|
||||
separated.emit(body)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Internal build / apply
|
||||
|
||||
Reference in New Issue
Block a user