Skip to content
Development
Skill

/physics-tuning

Engine-neutral physics tuning with Godot checks: fixed timestep and interpolation, CCD against tunnelling, damping, solver iterations and collision layer matrices. Use when bodies jitter, fast objects pass through walls or physics feels floaty or wrong. Not for engine physics

From plugin
awesome-gamedev-agent-skills
8.6k79 skills

Claude Code

$ npx -y skills add gamedev-skills/awesome-gamedev-agent-skills --skill physics-tuning --agent claude-code

SKILL.md

physics-tuning.SKILL.md
name: physics-tuning
description: >
  Engine-neutral physics tuning with Godot checks: fixed timestep and interpolation, CCD against
  tunnelling, damping, solver iterations and collision layer matrices. Use when bodies jitter,
  fast objects pass through walls or physics feels floaty or wrong. Not for engine physics APIs
  (`godot-physics`, `unity-physics`, `roblox-physics`, `phaser-arcade-physics`) or jump feel
  (`platformer`).

Physics tuning

Most "bad physics" is a mismatch between the fixed-rate simulation and the variable-rate render loop, or untuned CCD, mass, damping and layer settings. This skill owns those engine-neutral decisions and the checks that prove them. The engine's bodies, callbacks and settings come from `godot-physics`, `unity-physics` or `roblox-physics`; load both when tuning inside an engine.

When to use

  • Motion jitters, bodies tunnel through walls, stacks explode, joints shake, or speed depends on

frame rate.

  • Deciding what runs in the fixed step and what in the render frame, and how to interpolate.
  • Tuning gravity, mass, damping, restitution, solver iterations, sleeping and the layer matrix.

**Not this skill:** engine API (`godot-physics`, `unity-physics`, `roblox-physics`), character controller code (`godot-2d-movement`), jump arcs and forgiveness windows (`platformer`), camera smoothing (`camera-systems`), CPU cost of the simulation (`performance-optimization`).

Core workflow

1. **Read the current settings first**: tick rate, max steps per frame, interpolation, physics engine (Godot `[physics]` in `project.godot`; Unity `ProjectSettings/TimeManager.asset` and `DynamicsManager.asset`). Change one knob at a time. 2. **Simulate in the fixed step.** Forces, velocities and collision reads go in `_physics_process` / `FixedUpdate` and use that step's `dt`. 3. **Interpolate rendering** between ticks with the engine's built-in option before hand-rolling it. 4. **Stop tunnelling**: keep `speed / tick_rate` below the thinnest wall, or enable CCD on the small fast bodies, or use a ray or shape cast for bullets. 5. **Tune the body, not the scene**: mass for relative weight, damping for drag, gravity scale per object, bounce and friction in a physics material. 6. **Stabilize stacks and joints** with modest mass ratios, more solver iterations and sleeping. 7. **Plan the layer matrix** as a named table: what each layer is, and what it scans. 8. **Run the checks** below, then ask the user to judge feel with specific questions.

Patterns

1. Fixed step for simulation, interpolation for display

func _physics_process(dt):                  # Unity: FixedUpdate()
    velocity += gravity * dt                # integrate with the FIXED dt
    move_and_slide()
# WRONG: forces or movement in _process/Update with the frame dt: speed and collisions then
# depend on frame rate.

Turn on the built-in interpolation: Godot `physics/common/physics_interpolation = true` (off by default; it covers 2D and 3D nodes), Unity `Rigidbody.interpolation = Interpolate` on the player and the bodies the camera follows. Hand-roll (`Engine.get_physics_interpolation_fraction()`, lerp previous to current) only for something the engine does not cover, and never both on one node.

2. Tunnelling: CCD and a speed cap

body.continuous_cd = true                    # RigidBody3D: a bool
body2d.continuous_cd = RigidBody2D.CCD_MODE_CAST_RAY   # RigidBody2D: an enum; see Gotchas
# Unity: CollisionDetectionMode.ContinuousSpeculative (cheap, covers dynamic bodies) or
# ContinuousDynamic (fast vs fast). Plain Continuous only sweeps against static colliders.
const MAX_SPEED := 40.0
if velocity.length() > MAX_SPEED:
    velocity = velocity.normalized() * MAX_SPEED
# Rule of thumb: speed / ticks_per_second < thinnest wall, or CCD, or a ray cast.

3. Body tuning

body.mass = 2.0               # relative weight in collisions; does not change fall speed
body.linear_damp = 0.5        # drag (Unity 6: linearDamping, formerly drag)
body.gravity_scale = 1.5      # per-object gravity (Unity: Rigidbody2D.gravityScale)
var material := PhysicsMaterial.new()
material.bounce = 0.2         # restitution 0..1 (Unity: PhysicsMaterial.bounciness)
material.friction = 0.8
body.physics_material_override = material

4. Collision layer matrix as data

# A body is ON its layers and SCANS its mask. Name the bits once and build masks from names.
const LAYER := { "world": 1 << 0, "player": 1 << 1, "enemy": 1 << 2, "pickup": 1 << 3 }
player.collision_layer = LAYER.player
player.collision_mask  = LAYER.world | LAYER.enemy
pickup.collision_layer = LAYER.pickup
pickup.collision_mask  = LAYER.player        # the pickup only reacts to the player

Write the same table into the engine's layer names (Godot `[layer_names]` in `project.godot`; Unity's Physics collision matrix) so the editor and code agree.

5. Tunnel test (headless, exits 1 on failure)

# tools/tunnel_test.gd: godot --headless --path . --script res://tools/tunnel_test.gd
# Fires a small fast body at a thin wall; exits 1 if it ends up on the far side.
extends SceneTree

const SPEED := 3000.0                          # px/s: the fastest body in the game
const WALL := 4.0                              # px: the thinnest wall it must not cross
const RADIUS := 4.0                            # px: that body's collision radius
const MODE := RigidBody2D.CCD_MODE_CAST_RAY    # the CCD mode the game uses

func _initialize() -> void:
    var wall := StaticBody2D.new()
    var wall_shape := CollisionShape2D.new()
    wall_shape.shape = RectangleShape2D.new()
    wall_shape.shape.size = Vector2(WALL, 400)
    wall.add_child(wall_shape)
    wall.position = Vector2(500, 0)
    root.add_child(wall)
    var body := RigidBody2D.new()
    var shape := CollisionShape2D.new()
    shape.shape = CircleShape2D.new()
    shape.shape.radius = RADIUS
    body.add_child(shape)
Read more
@gamedev-skills
Ships withawesome-gamedev-agent-skills

<img src="docs/assets/awesome-gamedev-agent-skills-banner.png" width="820" alt="awesome-gamedev-agent-skills — game-dev skills for AI coding agents.

Stars on GitHub

Momentum

stars in total
8.6k
Star history of gamedev-skills/awesome-gamedev-agent-skills on GitHub, a chart by star-history.com

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills13d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react4d252k
@facebook@facebookInstall Skill

Questions about physics-tuning.

Which coding agents can use physics-tuning?
physics-tuning installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.