Configure Box2D physics in FXGL — add PhysicsComponent to entities, set body types (DYNAMIC, STATIC, KINEMATIC), define fixture properties (density, friction, restitution), handle collision callbacks (onCollisionBegin, onCollision, onCollisionEnd), detect collectibles, filter collisions, perform raycasting, and set up gravity. Use this skill when adding physics to a game, implementing platformer jump/gravity, handling bullet hits, detecting player picking up items, or setting up wall/floor colliders.
Instrucciones de origen · Vista previa de solo lectura
name
fxgl-physics-collision
description
Configure Box2D physics in FXGL — add PhysicsComponent to entities, set body types (DYNAMIC, STATIC, KINEMATIC), define fixture properties (density, friction, restitution), handle collision callbacks (onCollisionBegin, onCollision, onCollisionEnd), detect collectibles, filter collisions, perform raycasting, and set up gravity. Use this skill when adding physics to a game, implementing platformer jump/gravity, handling bullet hits, detecting player picking up items, or setting up wall/floor colliders.
// In initSettings:
settings.setWidth(1280); settings.setHeight(720);
// In initPhysics:
getPhysicsWorld().setGravity(0, 1250);
// Player entity setup:PhysicsComponentphysics=newPhysicsComponent();
physics.setBodyType(BodyType.DYNAMIC);
physics.setFixtureDef(newFixtureDef().friction(0.0f)); // zero friction for crisp movement// CRITICAL: prevent rotation — players should not tip over
physics.addGroundSensor(newHitBox("sensor", newPoint2D(5, 60), BoundingShape.box(30, 5)),
() -> onGroundSensor());
// Jump in PlayerComponent:publicvoidjump() {
if (isOnGround) {
physics.setVelocityY(-600);
isOnGround = false;
}
}
// Horizontal movement (set X velocity; don't add to existing)publicvoidmoveLeft() { physics.setVelocityX(-200); }
publicvoidmoveRight() { physics.setVelocityX( 200); }
publicvoidstop() { physics.setVelocityX(0); }
// Ground detection
onCollisionBegin(EntityType.PLAYER, EntityType.PLATFORM, (p, g) -> isOnGround = true);
onCollisionEnd (EntityType.PLAYER, EntityType.PLATFORM, (p, g) -> isOnGround = false);
Applying Forces and Impulses
PhysicsComponentpc= entity.getComponent(PhysicsComponent.class);
// Instant velocity change (teleport-like push)
pc.setVelocityX(300);
pc.setVelocityY(-400);
// Get current velocitydoublevx= pc.getVelocityX();
doublevy= pc.getVelocityY();
// Apply continuous force (accumulates each frame)
pc.applyBodyForce(newPoint2D(0, -5000)); // lift upward// Apply impulse (single-frame push, like a jump)
pc.applyBodyImpulse(newPoint2D(200, -300));
// Apply at specific point on body (creates torque)
pc.applyForceToCenter(newPoint2D(100, 0));
Sensor Bodies (Ghost / Trigger Zone)
Sensors detect overlaps but exert no physical force:
// Fire a ray from player to mouse positionPoint2Dstart= player.getCenter();
Point2Dend= getInput().getMousePositionWorld();
getPhysicsWorld().raycast((fixture, point, normal, fraction) -> {
Entityhit= (Entity) fixture.getBody().getUserData();
if (hit != null && hit.isType(EntityType.ENEMY)) {
hit.getComponent(HPComponent.class).damage(50);
return0; // stop at first hit
}
return1; // continue to next fixture
}, start, end);
Collision Filtering (Category/Mask Bits)
// Define bit flags (up to 16 categories)shortPLAYER=0x0001;
shortENEMY=0x0002;
shortBULLET=0x0004;
shortPLATFORM=0x0008;
// Bullet only collides with enemiesFixtureDefbulletFD=newFixtureDef()
.categoryBits(BULLET)
.maskBits(ENEMY); // only hits enemies// Player collides with everythingFixtureDefplayerFD=newFixtureDef()
.categoryBits(PLAYER)
.maskBits((short)(ENEMY | PLATFORM));
Gotchas
setBodyType before buildAndAttach() — changing body type after the entity is in
the world has no effect unless you recreate the physics body.
Zero friction on player — default friction causes players to "stick" to walls when
jumping. Set FixtureDef.friction(0.0f) on the player fixture.
Collision callbacks run on the physics thread — avoid spawning/removing entities
directly in callbacks. Wrap with runOnce(() -> entity.removeFromWorld(), Duration.ZERO).
collidable() is required — without it, the PhysicsComponent registers the body
but no collision callbacks will fire.
Static bodies don't move even if you call setPosition() directly. Use KINEMATIC
for platforms that move under programmatic control.
High-speed objects tunnel through thin walls. Increase PhysicsTick frequency or
use continuous collision detection (CCD) via physics.setCCDEnabled(true).
Gravity affects ALL dynamic bodies — use BodyType.KINEMATIC for top-down games
with no gravity, or setGravity(0, 0) for the entire world.
Screen bounds: use entityBuilder().buildScreenBoundsAndAttach(40) to get invisible
STATIC walls around the viewport without writing manual entity code.