Loading...
Loading...
Tune game physics for stable, good-feeling motion — fixed vs variable timestep, render interpolation, mass/gravity/drag, continuous collision detection (CCD) to stop tunneling, fixing jitter, and collision layers/masks. Engine-neutral. Use when the user mentions physics feel, jitter, tunneling, fixed timestep, FixedUpdate, CCD, bouncing/unstable physics, or collision layers.
npx skill4agent add gamedev-skills/awesome-gamedev-agent-skills physics-tuninggodot-physicsunity-physicsgodot-physicsunity-physicsinput-systemsgame-aiinput-systemsplatformerdtdtFixedUpdate_physics_processdt# Physics callback: runs at the FIXED rate. Use its dt for all integration.
func _physics_process(dt): # Unity: void FixedUpdate()
velocity += gravity * dt # integrate with the FIXED dt
move_and_slide() # engine resolves collisions this step
_prev_pos = _curr_pos; _curr_pos = global_position # record for interpolation
# Render frame: runs as fast as the display. Interpolate between physics states.
func _process(_frame_dt): # Unity: void Update()
var alpha = Engine.get_physics_interpolation_fraction() # 0..1 within the tick
visual.global_position = _prev_pos.lerp(_curr_pos, alpha)
# RIGHT: integrate in the fixed step, render via interpolation.
# WRONG: applying forces in _process/Update with frame dt — speed and collisions
# then depend on frame rate and jitter under load.physics_interpolationRigidbody.interpolation = Interpolate# Fast, small bodies skip past thin colliders between ticks. Two fixes:
body.continuous_cd = true # RigidBody3D bool (RigidBody2D: CCD_MODE_* enum). Unity: rb.collisionDetectionMode = Continuous
# Cap velocity so a single step can't move more than ~one collider thickness.
const MAX_SPEED := 40.0
if velocity.length() > MAX_SPEED:
velocity = velocity.normalized() * MAX_SPEED
# Rule of thumb: max_distance_per_step (= speed / physics_hz) should be < the
# thinnest wall. Raise physics_hz or enable CCD when that fails.# Mass is RELATIVE weight in collisions; it does NOT change fall speed (gravity
# accelerates all masses equally). Use drag and gravity_scale to shape feel.
body.mass = 2.0 # heavier pushes lighter in collisions
body.linear_damp = 0.5 # air drag: higher = stops sooner (Unity: drag)
body.gravity_scale = 1.5 # per-object gravity multiplier (snappier fall)
# Bounce/slide come from the physics material, not code:
material.bounce = 0.2 # restitution 0..1 (Unity: bounciness)
material.friction = 0.8 # surface grip# A body is ON its layer(s) and SCANS the layers in its mask. Both directions of a
# pair must be configured for them to interact.
player.collision_layer = LAYER_PLAYER
player.collision_mask = LAYER_WORLD | LAYER_ENEMY # player detects world+enemies
pickup.collision_layer = LAYER_PICKUP
pickup.collision_mask = LAYER_PLAYER # pickup only reacts to player
# Unity equivalent: assign GameObject layers and edit the Physics collision matrix
# (or Physics.IgnoreLayerCollision). Keep a named layer constant table, not magic numbers.Update_processgravity_scaledtreferences/timestep-and-ccd.mdgodot-physicsunity-physicsinput-systemsgame-aiplatformerfps-shooter