Physics and Collisions in PlayCanvas
Physics simulation brings a game world to life by making objects fall under gravity, bounce off surfaces, stack on each other, and respond to player-applied forces. Without physics, every movement and interaction must be hand-coded. With physics, the engine calculates realistic responses to forces and collisions, letting you focus on game design rather than mathematics. PlayCanvas makes this accessible through visual editor configuration for common scenarios and a script API for advanced control.
Enable Physics and Add Rigid Bodies
Physics in PlayCanvas requires the ammo.js library, which is included automatically when you add physics components to your project. In the project settings under "Physics," you can configure global properties like gravity (defaulting to -9.81 on the Y axis to match Earth), the fixed timestep for simulation updates, and the maximum number of sub-steps per frame that control simulation accuracy.
To make an entity participate in physics, add two components: a RigidBody and a Collision. The RigidBody defines how the entity behaves in the simulation, while the Collision defines its physical shape. In the RigidBody component, set the "Type" property to one of three values. "Dynamic" bodies are fully simulated, they fall under gravity, respond to forces, and bounce off other objects. "Static" bodies never move but other objects collide with them, making them perfect for floors, walls, and terrain. "Kinematic" bodies move only through script-driven position updates, ignoring forces and gravity but still pushing dynamic objects out of the way, which is useful for moving platforms and elevators.
Configure the mass property for dynamic bodies. Mass determines how an object responds to forces: heavier objects accelerate less for the same applied force. A mass of 0 is not valid for dynamic bodies (use static type instead). Set friction to control how much objects resist sliding against each other (0 is frictionless ice, 1 is high-grip rubber) and restitution to control bounciness (0 absorbs all energy on impact, 1 produces a perfect bounce with no energy loss). Real materials fall between these extremes, with values like 0.3 to 0.5 friction and 0.1 to 0.4 restitution for typical game objects.
Linear and angular damping simulate air resistance and rotational friction. Without damping, a dynamic body set in motion never stops moving in a frictionless environment. Set small damping values (0.01 to 0.1) for natural-feeling movement, or higher values for objects in thick fluids or objects that should come to rest quickly after being disturbed.
Configure Collision Shapes
The Collision component defines the physical shape that the physics engine uses for collision detection. This shape does not need to match the visual model exactly. In fact, using simpler shapes dramatically improves simulation performance because the physics engine calculates intersections between simple primitives much faster than between complex meshes.
Box collisions work best for crates, buildings, walls, and any roughly rectangular object. You set the half-extents (half the width, height, and depth) to size the collision box. Sphere collisions suit balls, projectiles, and any roughly round object. Set the radius to match the object's apparent size. Capsule collisions are ideal for character controllers because the rounded ends prevent the character from catching on ledge edges, and the cylindrical body provides stable upright collision. Set the radius and height to match your character model.
Cylinder and cone shapes cover pipes, tree trunks, traffic cones, and similar geometry. These are computationally more expensive than boxes and spheres but still much cheaper than mesh collisions. Use them when the shape distinction matters for gameplay, such as a cylindrical pillar that objects should slide around smoothly rather than catching on corners.
Mesh collisions use the actual triangle geometry of a model for collision detection. This provides pixel-perfect accuracy for complex environments like terrain, building interiors, and irregular rock formations. However, mesh collision is significantly more expensive and should only be used for static bodies. Dynamic bodies with mesh collision shapes cause serious performance problems because the physics engine must recalculate the mesh collision data every time the body moves or rotates. For dynamic objects with complex shapes, use compound collisions instead, combining multiple simple shapes to approximate the overall form.
Compound collision shapes let you build complex collision geometry from multiple simple primitives. A table might use a flat box for the tabletop and four thin cylinders for the legs. A vehicle might combine boxes for the chassis and cylinders for the wheels. Compound shapes offer a good balance between accuracy and performance for dynamic objects that need more detail than a single primitive provides.
Set Up Trigger Volumes and Contact Events
Trigger volumes detect when objects enter, stay within, or exit a defined region without applying any physical forces. Create a trigger by adding a Collision component to an entity without a RigidBody component, or by setting the RigidBody type to "Static" and enabling the "Trigger" checkbox. The trigger's collision shape defines the detection region, and you listen for events on the entity to know when something enters.
Three events fire on trigger entities. The "triggerenter" event fires once when a rigid body first overlaps the trigger volume. The "triggerleave" event fires once when a previously overlapping body exits the volume. Use these for gameplay mechanics like entering a checkpoint zone, stepping on a pressure plate, or detecting when the player enters a new area that should spawn enemies or trigger a cutscene.
For collisions between two rigid bodies (not triggers), the contact event system provides detailed collision information. Listen for "collisionstart" on an entity to detect the first frame of contact with another body. The callback receives a ContactResult object containing the colliding entity, the contact points, their normal directions, and the impulse magnitude. Use the impulse value to determine how hard the impact was, which is useful for damage calculations, impact sound selection, and particle effect intensity.
The "collisionend" event fires when two previously touching bodies separate. Between start and end, the "contact" event fires every frame that the bodies remain in contact. Continuous contact events are useful for conveyor belts (apply force each frame), hazard zones (apply damage over time), and friction-based sound effects (play scraping sounds while two surfaces slide against each other).
Performance tip: only listen for collision events on entities that actually need them. Every collision event listener has a cost, and in scenes with many physics objects, unnecessary listeners add up. A typical game might have hundreds of physics objects but only listen for collision events on the player character, projectiles, and destructible objects.
Implement Raycasting for Gameplay
Raycasting shoots an invisible line through the physics world and reports what it hits. This is one of the most useful physics features for gameplay because it answers the question "what is in this direction?" without requiring a physical object to travel there. Use raycasting for projectile hit detection (instant-hit weapons like laser guns), line-of-sight checks (can the enemy see the player?), ground detection (is the character standing on something?), and mouse picking (what did the player click on?).
PlayCanvas provides two raycasting methods through the physics system. this.app.systems.rigidbody.raycastFirst(start, end) returns the closest hit result along the ray, including the hit entity, the world-space hit point, and the surface normal at the contact. This is the most common form, used for single-target interactions like shooting or clicking. this.app.systems.rigidbody.raycastAll(start, end) returns an array of all entities the ray passes through, useful for piercing weapons or checking all objects along a sightline.
For mouse picking, convert the screen-space mouse position to a ray using the camera's screenToWorld method. Cast the ray from the camera's near plane position through the clicked point into the scene. The first hit result tells you which entity the player clicked on, enabling object selection, interaction prompts, and context menus. This technique is essential for point-and-click games, strategy games, and any application where the player interacts with 3D objects through mouse or touch input.
Ground detection uses a short downward ray from the character's position to check if there is a surface below. Cast the ray from the character's center downward by slightly more than half the character's height. If the ray hits, the character is grounded and can jump. If it misses, the character is airborne. Adjust the ray length to accommodate slopes and minor terrain irregularities so the grounded check does not flicker on uneven surfaces.
Add Joints and Constraints
Joints connect two rigid bodies with constraints that limit their relative movement. PlayCanvas exposes joint creation through the ammo.js API, letting you build mechanical systems like hinged doors, swinging pendulums, spring-loaded platforms, and vehicle suspensions. While the editor does not have a visual joint tool, creating joints in scripts is straightforward.
A hinge joint constrains two bodies to rotate around a single shared axis. Use this for doors that swing on hinges, flipping platforms, and pendulum traps. You specify the anchor point and the hinge axis in each body's local space, then set optional angle limits to prevent the hinge from rotating beyond a defined range. Adding a motor to the hinge applies a constant or variable torque, creating powered doors that open automatically or fan blades that spin continuously.
A point-to-point (ball and socket) joint constrains two bodies to share a single anchor point while allowing free rotation around that point. This is useful for ragdoll limbs, chain links, and wrecking balls. The bodies can rotate freely relative to each other but cannot separate from the anchor position.
Slider joints restrict movement to a single axis, creating pistons, sliding doors, and elevator platforms. Spring constraints apply a restorative force that pulls two bodies toward their rest position, useful for suspension systems, bouncy connections, and soft constraints that allow limited deformation before snapping back. Cone twist joints combine angular limits on multiple axes, providing the range-of-motion constraints needed for realistic ragdoll shoulder and hip joints.
When building joint-based systems, start with generous constraint limits and tighten them gradually. Overly tight constraints can cause physics instability where the solver cannot satisfy all constraints simultaneously, resulting in jittering or explosions. Increase the physics simulation's iteration count in the project settings if complex joint chains exhibit instability, trading CPU time for more accurate constraint solving.
Use the simplest collision shapes that produce acceptable gameplay, reserve mesh collisions for static geometry only, and rely on raycasting instead of physical projectiles for instant-hit interactions. These practices keep the physics simulation fast while delivering the interactions your game design requires.