| name | moss-physics |
| description | Integrate Moss physics library for collision detection and physics simulation. Use when working with physics bodies, shapes, collisions, or forces. |
Physics with Moss
Moss is the custom physics library for Subspace Infinity, integrated via sio2-mphys.
Building Moss
Moss must be built from source and published locally:
cd ~/github/assofohdz/moss
./gradlew publishToMavenLocal
Core Classes
MPhysSystem
The main physics system that manages the physics space:
import com.simsilica.ext.mphys.MPhysSystem;
import com.simsilica.mblock.phys.MBlockShape;
import com.simsilica.mphys.PhysicsSpace;
MPhysSystem<MBlockShape> physics = (MPhysSystem<MBlockShape>) getSystem(MPhysSystem.class, true);
PhysicsSpace<EntityId, MBlockShape> space = physics.getPhysicsSpace();
RigidBody Access
RigidBody<EntityId, MBlockShape> rb = physics.getPhysicsSpace()
.getBinIndex()
.getRigidBody(entityId);
StaticBody<EntityId, MBlockShape> sb = physics.getPhysicsSpace()
.getBinIndex()
.getStaticBody(entityId);
Body Initializer
Register custom initialization for physics bodies:
physics.getBodyFactory().addDynamicInitializer(new MyBodyInitializer());
public class MyBodyInitializer implements BodyInitializer<EntityId, MBlockShape> {
@Override
public void initialize(RigidBody<EntityId, MBlockShape> body) {
}
}
Contact System
Implementing ContactListener
public class ContactSystem<K, S extends AbstractShape> extends AbstractGameSystem
implements ContactListener<EntityId, MBlockShape> {
private MPhysSystem<?> physics;
@Override
protected void initialize() {
physics = getSystem(MPhysSystem.class);
physics.getPhysicsSpace().getContactDispatcher().addListener(this);
}
@Override
public void newContact(Contact contact) {
RigidBody<EntityId, MBlockShape> bodyOne = contact.body1;
AbstractBody<EntityId, MBlockShape> bodyTwo = contact.body2;
if (bodyTwo != null) {
EntityId one = bodyOne.id;
EntityId two = bodyTwo.id;
if (shouldDisable(one, two)) {
contact.disable();
return;
}
}
contact.restitution = 1.0f;
}
}
Category-Based Collision Filtering
CollisionCategory category = ed.getComponent(entityId, CollisionCategory.class);
CategoryFilter filter = category.getFilter();
if (!filterTwo.isAllowed(filterOne)) {
contact.disable();
}
Physics Listeners
Registering Listeners
MPhysSystem<S> system = getPhysicsSystem();
system.addPhysicsListener(myPhysicsObserver);
system.getBinEntityManager().addObjectStatusListener(myStatusListener);
PhysicsListener Interface
public class PhysicsObserver implements PhysicsListener<EntityId, S>,
ObjectStatusListener<S> {
@Override
public void startFrame(long frameTime, double stepSize) {
}
@Override
public void endFrame() {
}
@Override
public void update(RigidBody<EntityId, S> body) {
boolean active = !body.isSleepy();
Vec3d position = body.position;
Quatd orientation = body.orientation;
}
@Override
public void objectLoaded(EntityId id, RigidBody<EntityId, S> body) {
}
@Override
public void objectUnloaded(EntityId id, RigidBody<EntityId, S> body) {
}
}
Movement and Drivers
MobDriver Pattern
For AI-controlled physics entities:
public class MobDriver implements ControlDriver<MBlockShape> {
private final MPhysSystem<MBlockShape> physics;
private final EntityId mob;
public MobDriver(MPhysSystem<MBlockShape> physics, EntityId mob) {
this.physics = physics;
this.mob = mob;
}
}
Movement Settings
public class MovementSettings {
public float groundImpulse = 40;
public float airImpulse = 25;
public float movementSpeed = 2;
}
Shape Factory
Registering Shape Factories
ShapeFactoryRegistry<MBlockShape> shapeFactory = new ShapeFactoryRegistry<>();
registerShapeFactories(shapeFactory, ed);
systems.register(ShapeFactory.class, shapeFactory);
Integration with Zay-ES
Physics Components
ShapeInfo - defines shape and mass
CollisionCategory - collision filtering
Parent - parent-child relationships (skip collisions)
AttackVelocity - projectile velocities
Creating Physics Entity
EntityId entity = ed.createEntity();
ed.setComponents(entity,
new Position(x, y, z),
new ShapeInfo(ShapeNames.SHIP, mass),
new CollisionCategory(CategoryFilter.PLAYER)
);