tag

#physics

38 items (2 guides · 36 fixes)

guides
fixes
26.07.08e
"A frame-budget method for stylized s&box scenes"

Census tris × instances before decimating; prefer BoxCollider over ModelCollider for decorative props.

26.08.05
"A second render material can seal a doorway shut in the compiled collision"

A PhysicsHullFile node compiled with import_mode HullPerElement treats a material break as an element boundary. Paint two adjoining primitives with a second material and the compiler folds them into one element and builds one convex hull across both. The convex hull of a wall with a hole in it is a solid wall, so every doorway and window built the same way seals shut at once, with no geometry change in the diff. Every offline check stays green, because none of them compile the model. The defect is only visible in the compiled collision, which the editor or an in-engine walk probe can see. Fix by giving physics its own single-material copy of the source mesh, so the render mesh's material list never reaches the physics node, and pin the physics mesh to the render mesh with a lint.

26.07.22
"A self-crossing track breaks nearest-waypoint lap position; drive it from a monotone cursor"

On a track that crosses itself (a figure-eight, or any lap that revisits the same ground), a per-frame nearest-waypoint lookup jumps about half a lap at the crossing, because two points that sit close together can be arclength-distant. Drive lap position from a monotone cursor that only advances along the committed branch, do lateral math in a left-of-travel frame, and keep the branch-discrimination cone tighter than the branches' angular separation.

26.07.15a
"An accumulator guard that resets on a transient flicker never fires"

A per-run accumulator guard (budget, cooldown, or streak counter) that resets on a transient state flicker never actually fires, because the reset zeroes it faster than it can fill. Reset only on a signal that truly ends the episode (sustained air, real forward progress), never on a per-tick proxy the episode itself trips constantly.

26.07.08e
"Character facing derived from velocity flips 180 degrees on every pendulum reversal"

Deriving a visual's facing from horizontal velocity causes 180-degree snaps on any momentum reversal. Lock facing to an attach-time azimuth for pendulums and oscillators.

26.07.08e
"Collider choice that actually costs you"

BoxCollider is cheap and follows WorldScale; Capsule/ModelCollider don't scale with WorldScale and ModelCollider is costly on clutter.

26.07.08e
"Deep vertical terrain sink defeats lateral eject and mantle: escalate through hard-recover to a top-out"

A stationary vertical sink at a chunk-corner seam defeats eject, mantle, and even hard-recover (the anchor itself can be buried under an overhang). The terminal escape is a top-out to the chunk surface.

26.07.08e
"Double jump doesn't work with Jump(): set Velocity.z directly"

Jump() helpers clamp against rising velocity, eating the second impulse. Set Velocity.z directly for a reliable double jump.

26.07.22
"Editor play mode is hard-capped at 60 fps: cvars won't lift it"

Editor-embedded play mode pins at exactly 60 fps regardless of cvars. The cap is the compositor's vsync on the editor window, not the engine frame sync. Under the cap even the p50 pins to 16.67 ms: read the tail (p99, worst frame, over-budget count), not the median.

26.07.22
"Editor vsync hides physics cost: time the step directly"

Frame fps pins at 60 in the editor regardless of physics load: implement IScenePhysicsEvents.PrePhysicsStep/PostPhysicsStep with a Stopwatch to get the true, vsync-free CPU cost of the solver step.

26.07.22
"Freeze a physics actor by going kinematic, not by destroying its Rigidbody"

Turning a composite physics actor into static scenery by destroying its Rigidbody silently kills every child system that keyed its own liveness off that body. Set MotionEnabled = false instead: the body stays alive, dependents keep ticking, and a kinematic body reads zero delta-v for free.

26.07.08e
"GameObject.Destroy keeps rendering in edit mode: deferred queue not processed between regenerations"

A runtime-generated world root torn down with GameObject.Destroy() keeps rendering in edit mode because the deferred queue isn't flushed: use DestroyImmediate and sweep all matching roots.

26.07.08e
"Ground snap pops on rolling slopes: rate-limit the downward snap"

An idempotent ground-snap jitters on curved terrain because the slope curves away within each step: ease the downward snap at a bounded glue rate.

26.08.05
"import_rotation fixes the render mesh and leaves PhysicsHullFile collision unrotated"

The render node in a vmdl honours import_rotation. PhysicsHullFile and PhysicsMeshFile ignore it. So correcting an off-axis import with import_rotation fixes the picture and leaves the collision exactly where it was. The model builds clean with no error and no warning, photographs correctly, and a player walks straight through it. Bake a corrected engine-frame copy of the mesh that both the render node and the physics node read, rather than rotating one consumer with a property the other ignores.

26.07.08e
"Kinematic movement that doesn't get stuck"

Always handle tr.StartedSolid: ignore that frame so an overlapped body can walk free; slide-trace the wish onto the hit plane.

26.07.18
"Library extraction seam must cover every side effect"

A library extraction seam covers only the headline behavior: every other side effect of the replaced code path silently disappears unless explicitly reproduced on the consumer side.

26.07.08e
"My model has no collision even though it loads fine"

RenderMeshFile alone compiles clean with zero physics: ModelCollider needs PhysicsMeshFile/PhysicsHullFile in the vmdl.

26.07.08e
"My scaled-up tree's collider didn't scale"

CapsuleCollider and ModelCollider ignore WorldScale; BoxCollider follows it. Bake scale into import_scale instead.

26.07.08e
"Noclip in a trace-based kinematic controller is a state, not a collider toggle"

Disabling a collider does nothing for a hand-integrated kinematic controller: noclip must be a movement state that skips traces, gravity, and ground-snap entirely.

26.08.05
"One vmdl, many tagged collision hulls"

A PhysicsShapeList node compiles with several tagged PhysicsHullFile children, so one vmdl can carry a compound collision volume. The per-shape tags stay inert through a scene ModelCollider.

26.07.08e
"Orient a flat decal box to the hit normal"

Rotation.FromYaw alone leaves a decal flat on the floor: build a rotation that aligns the thin axis to the surface normal, then offset along it.

26.07.15a
"Per-shape collision_tags in a vmdl are inert at runtime on a ModelCollider"

A multi-hull vmdl authored with per-shape collision_tags does not get those tags at runtime -- a scene ModelCollider overwrites every shape with the GameObject's own tags, so Scene.Trace.WithoutTags can't filter one hull from another. Split the hulls across separate collider GameObjects instead.

26.08.05
"Ragdoll a scripted-rig NPC with pure engine physics"

PhysicsShapeList + PhysicsJointList in the vmdl + ModelPhysics toggle. No collapse clips, no SetBoneTransform. On current builds ModelPhysics.PhysicsGroup reads NULL: enumerate ModelPhysics.Bodies directly and resolve bones by name→index.

26.07.22
"Read collision direction from the impulse, not the struck object's velocity"

A collision rule that keys its direction on the struck object's own velocity is correct for the object that caused the hit and silently backwards for the object that got hit. A car rolling forward at 2 m/s and rammed from behind reads as moving forward, so it dents its nose instead of its rear. Derive the direction from the negated impulse delta-v, which points from the struck face inward for both bodies.

26.08.05
"Rigidbody component API"

Rigidbody API verified across multiple projects: Gravity, MassOverride, Velocity, ApplyForce, and the recipe for a dynamic pushable prop. AutoSleep lives on PhysicsBody (set-only as of 26.08.05), which is now populated on the same tick the component is created.

26.07.08e
"Rotation.FromYaw is counter-clockwise"

Rotation.FromYaw(+angle) is a LEFT (CCW) turn. Get the sign right or steering, AI, and autopilot spiral the wrong way.

26.07.08e
"Runtime world-building helpers"

FlatBox/Prop/Deco/Wire helpers plus Obstacle records as plain data beat physics queries for build validity.

26.07.08e
"s&box units are inches"

1 m = 39.37 engine units: design in SI, convert once at the engine boundary, and audit every consumer.

26.07.22
"SceneTrace sphere sweep EndPosition is the sphere centre, not the feet"

SceneTraceResult.EndPosition on a sphere-radius sweep is the sphere's CENTRE at contact, not the contact point. Treating it as where the feet landed is off by a full radius. Derive the real contact position as from + (to - from) * Fraction in one helper. A related trap: snapping the sphere exactly tangent to the floor makes the next horizontal sweep intermittently report StartedSolid.

26.07.15a
"Swept trace: HitPosition is the surface, EndPosition is the shape centre"

For a swept sphere/hull trace, HitPosition is the true surface contact point while EndPosition is the swept shape's centre at impact. Seat surface effects at HitPosition.

26.07.08e
"The bone-name `.` → `_` compiler trap"

Model compiler rewrites upper_arm.L → upper_arm_L; physics KV3 that still says .L makes limb bodies unknown while the torso works.

26.07.22
"The Citizen ragdoll has 18 bodies and 16 joints, countable offline"

The Citizen ragdoll physics rig has 18 shapes (17 capsules plus 1 cylinder) and 16 joints (12 conical ballsockets plus 4 revolute hinges). A common folk estimate lands near 9 to 13 bodies, roughly half the real count, so it undercounts per-body and joint-solve cost. Both prefab files are plain KV3 text, so you count them offline with no editor running.

26.07.08e
"Trace-based kinematic controllers don't fire trigger volumes"

A trace-based kinematic character controller has no collider component, so trigger volumes and ITriggerListener never fire against it. Use distance polling instead.

26.07.08e
"Trace-based kinematic controllers don't fire triggers"

A hand-integrated trace mover has no collider component: ITriggerListener and OnTriggerEnter never fire. Use distance-polling instead.

26.07.08e
"Vector3.Right is (0, -1, 0), not +X"

Source engine convention: Forward = +X, Left = +Y, Right = -Y. Using Vector3.Right for '+X' silently slides geometry the wrong way.

26.07.15a
"Zero-radius Scene.Trace.Ray slips through coarse voxel ModelColliders"

A zero-radius Scene.Trace.Ray passes straight through coarse voxel ModelColliders and returns Hit=false. Sweep a thin sphere (.Radius(...)) and it hits.

Want to know when new guides or fixes drop? Join the community to help build this out. Report gotchas, flag outdated fixes, or just lurk.

Join the Discord