Physics and Collisions
Access Pixscape's Box2D world from LibGDX and work with entity bodies, contacts, ray casts, and collision queries.
On this page
Pixscape uses LibGDX Box2D for runtime physics. Bodies, collision shapes, and joints created in Studio are recreated automatically when the scene loads.
Use api.physics() when gameplay needs to inspect physics state or access the current scene’s Box2D world and bodies.
Use Pixscape physics
import games.pixscape.runtime.api.PhysicsAPI;
PhysicsAPI physics = api.physics();
if (physics.isRunning()) {
float pixelsPerMeter = physics.pixelsPerMeter();
}
isRunning() tells you whether physics is currently active for the loaded scene. It describes the live simulation, not only the scene’s configured physics setting.
Pixels and Box2D meters
Pixscape scenes use world/pixel coordinates, while Box2D works in meters. pixelsPerMeter() returns the scale used by the current scene.
float ppm = api.physics().pixelsPerMeter();
float meters = pixels / ppm;
float pixelsAgain = meters * ppm;
Use this scale when passing Pixscape positions or distances to native Box2D operations.
Access the Box2D world
box2dWorld() gives you the native LibGDX/Box2D world used by Pixscape. It returns null when physics is unavailable.
import com.badlogic.gdx.physics.box2d.World;
World world = api.physics().box2dWorld();
if (world != null) {
// Native Box2D operations
}
Access an entity body
Combine the Physics API with an EntityRef to get the live Box2D body for an entity:
import com.badlogic.gdx.physics.box2d.Body;
import games.pixscape.runtime.api.EntityRef;
EntityRef player = api.entities().requireTag("player");
Body body = api.physics().body(player);
if (body != null) {
body.applyLinearImpulse(2f, 0f, body.getWorldCenter().x, body.getWorldCenter().y, true);
}
body(...) returns null when the entity is missing or inactive, has no live physics body, or physics is unavailable.
Ownership and lifetime
The World and Body objects returned by PhysicsAPI belong to Pixscape. You can query them and use normal Box2D body operations, but:
- do not dispose the
World; - do not destroy Pixscape-owned bodies directly;
- do not run your own normal
world.step(...)loop; - do not assume these native objects live forever.
Pixscape controls normal Box2D stepping as part of the Runtime loop. To remove a Pixscape entity, normally use EntityRef.remove() and let Runtime manage its native body.
The Box2D world belongs to the current Runtime scene. Pixscape can also recreate an entity’s body. After a scene change or Runtime rebuild, get the World and Body again from api.physics().
Collision events
Use a normal Box2D ContactListener for gameplay collision events:
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.Manifold;
import com.badlogic.gdx.physics.box2d.World;
World world = api.physics().box2dWorld();
if (world != null) {
world.setContactListener(new ContactListener() {
@Override
public void beginContact(Contact contact) {
Fixture a = contact.getFixtureA();
Fixture b = contact.getFixtureB();
// Gameplay collision logic
}
@Override
public void endContact(Contact contact) {
}
@Override
public void preSolve(Contact contact, Manifold oldManifold) {
}
@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
});
}
A Box2D World has one active contact listener. If several gameplay systems need collision events, route them from one listener into your own game code.
Ray casts
Ray casts use Box2D meters. Convert logical Pixscape world coordinates with the scene’s pixels-per-meter value:
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.World;
World world = api.physics().box2dWorld();
if (world != null) {
float ppm = api.physics().pixelsPerMeter();
Vector2 from = new Vector2(x1 / ppm, y1 / ppm);
Vector2 to = new Vector2(x2 / ppm, y2 / ppm);
world.rayCast((fixture, point, normal, fraction) -> {
// Return the fraction to clip the ray at this hit.
// Return -1f to ignore this fixture.
return fraction;
}, from, to);
}
Use the standard Box2D callback return values when you need different filtering or traversal behavior.
AABB queries
Use QueryAABB(...) for nearby-object checks, trigger areas, and other broad-phase gameplay queries. Its bounds are also in Box2D meters.
World world = api.physics().box2dWorld();
if (world != null) {
world.QueryAABB(fixture -> {
// Inspect the fixture. Return true to continue the query.
return true;
}, lowerX, lowerY, upperX, upperY);
}
Physics parallax
Physics coordinates may use the scene’s physics parallax settings:
float parallaxX = api.physics().parallaxX();
float parallaxY = api.physics().parallaxY();
An unset parallax value, or no active scene, behaves as 1.
If you unproject a screen position through a camera, the result is a rendered world position. removeParallax(...) converts it back to the logical Pixscape world position used for physics interaction:
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Vector2;
Vector2 logicalWorld = new Vector2();
api.physics().removeParallax(
renderedWorldPosition,
camera,
logicalWorld
);
The arguments are the rendered Vector2, the OrthographicCamera, and the output Vector2. The output may be the same object as the rendered position.
removeParallax(...) still returns Pixscape world coordinates. Divide by pixelsPerMeter() separately when a Box2D operation needs meters.
Studio-authored physics
Bodies, collision shapes, and joints authored in Studio are saved with the scene and recreated by Runtime when the scene loads. Gameplay can then retrieve their native bodies with api.physics().body(entity) or interact with all of them through the shared Box2D world. See the Studio Physics guide for visual body and collision-shape editing.
Tiled and Spatial collision geometry prepared by Pixscape participates in that same world. Their authoring and data rules are covered by the dedicated Tiled and Spatial documentation.
Advanced Runtime integration
Normal gameplay should prefer api.physics() and standard Box2D operations. Experienced integrations can still use the Expert ECS API, Box2dSyncSystem, and Box2dWorldService when extending Runtime physics synchronization or lifecycle behavior.
These expert surfaces are not required to retrieve the world or an entity body. Even in expert code, acquire native objects through PhysicsAPI instead of depending on Runtime body or fixture cache components.
Direct changes to authored Pixscape physics components must follow Runtime’s validation and dirty/rebuild rules. Keep that work in the expert ECS layer; the internal compiled fixture and runtime-body caches are not gameplay APIs.