mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-16 04:42:04 +00:00
fix(*): Detect wall contact by contact normal so floor contact anywhere on the pitch is exempt from the wall penalty
This commit is contained in:
@@ -29,9 +29,9 @@ extends AIController3D
|
|||||||
# flat, idle ship farms nothing.
|
# flat, idle ship farms nothing.
|
||||||
@export var tilt_penalty := 0.002
|
@export var tilt_penalty := 0.002
|
||||||
|
|
||||||
# A ship (1x1x4 box) touching a wall has its centre within ~2.05 of it;
|
# Contact normals with y above this are floor contact (exempt from the wall
|
||||||
# 2.5 adds slack for contact jitter without misreading mid-field contact.
|
# penalty); below it they read as wall (sideways) or ceiling (downward).
|
||||||
const WALL_PROXIMITY_MARGIN := 2.5
|
const FLOOR_NORMAL_MIN_Y := 0.7
|
||||||
|
|
||||||
var ship: Ship
|
var ship: Ship
|
||||||
var rl_controller: RLShipController
|
var rl_controller: RLShipController
|
||||||
@@ -101,8 +101,9 @@ func _physics_process(delta):
|
|||||||
# Dense penalty: every tick spent pressed against a wall or the ceiling
|
# Dense penalty: every tick spent pressed against a wall or the ceiling
|
||||||
# (contact monitoring is already on for the ball-touch reward). Ships
|
# (contact monitoring is already on for the ball-touch reward). Ships
|
||||||
# bumping each other, the ball, or the floor is fine. The boundary is one
|
# bumping each other, the ball, or the floor is fine. The boundary is one
|
||||||
# body, so position tells us which surface the contact is.
|
# body, so the contact normal tells us which surface: floor contact
|
||||||
if wall_contact_penalty > 0.0 and _touching_boundary() and _near_wall_or_ceiling():
|
# pushes the ship up (+Y), walls push sideways, the ceiling down.
|
||||||
|
if wall_contact_penalty > 0.0 and _wall_or_ceiling_contact():
|
||||||
reward -= wall_contact_penalty
|
reward -= wall_contact_penalty
|
||||||
|
|
||||||
# Dense penalty: tilt away from upright (0 flat, max when inverted) —
|
# Dense penalty: tilt away from upright (0 flat, max when inverted) —
|
||||||
@@ -112,20 +113,20 @@ func _physics_process(delta):
|
|||||||
reward -= tilt_penalty * (1.0 - uprightness) * 0.5
|
reward -= tilt_penalty * (1.0 - uprightness) * 0.5
|
||||||
|
|
||||||
|
|
||||||
func _touching_boundary() -> bool:
|
func _wall_or_ceiling_contact() -> bool:
|
||||||
for body in ship.get_colliding_bodies():
|
var state := PhysicsServer3D.body_get_direct_state(ship.get_rid())
|
||||||
if body is ArenaBoundary:
|
if state == null:
|
||||||
|
return false
|
||||||
|
for i in state.get_contact_count():
|
||||||
|
if not state.get_contact_collider_object(i) is ArenaBoundary:
|
||||||
|
continue
|
||||||
|
# Normal points from the surface into the ship: floor ≈ +Y (exempt),
|
||||||
|
# anything flatter or downward is a wall or the ceiling.
|
||||||
|
if state.get_contact_local_normal(i).y < FLOOR_NORMAL_MIN_Y:
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
|
||||||
func _near_wall_or_ceiling() -> bool:
|
|
||||||
var p := ship.global_position
|
|
||||||
return absf(p.x) > ArenaBoundary.INNER_HALF_X - WALL_PROXIMITY_MARGIN \
|
|
||||||
or absf(p.z) > ArenaBoundary.INNER_HALF_Z - WALL_PROXIMITY_MARGIN \
|
|
||||||
or p.y > ArenaBoundary.INNER_HEIGHT - WALL_PROXIMITY_MARGIN
|
|
||||||
|
|
||||||
|
|
||||||
func _on_ship_body_entered(body: Node) -> void:
|
func _on_ship_body_entered(body: Node) -> void:
|
||||||
if body.is_in_group("ball"):
|
if body.is_in_group("ball"):
|
||||||
reward += ball_touch_reward
|
reward += ball_touch_reward
|
||||||
|
|||||||
Reference in New Issue
Block a user