Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First addition of the JBox2D physics engine alongside Bullet (3D).
Not tested very thoroughly -- and not testable yet from GAML.The same interfaces now allow to choose between JBullet (java), JBox2D (java), Bullet (native). The goal, ultimately, is to have two choices : 2D or 3D, which would lead, by default, to either Box2D or Bullet (both natives). But, in case the natives wouldn't work (or be loaded), to be able to rely on the two corresponding java libraries. More integration needs to be made with other plugins too. For the moment, the two skills in physics only listen to "location" (i.e. to detect a change of location coming from elsewhere), but it is technically possigle to listen to any variable (change of shape, change of speed, change of heading,...).
- Loading branch information
1 parent
9dd1dde
commit ca40712
Showing
161 changed files
with
29,989 additions
and
213 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
182 changes: 182 additions & 0 deletions
182
...s.gaml.extensions.physics/src/gama/extensions/physics/box2d_version/Box2DBodyWrapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
package gama.extensions.physics.box2d_version; | ||
|
||
import static msi.gaml.types.GamaGeometryType.buildRectangle; | ||
|
||
import org.jbox2d.collision.AABB; | ||
import org.jbox2d.collision.shapes.MassData; | ||
import org.jbox2d.collision.shapes.Shape; | ||
import org.jbox2d.common.Vec2; | ||
import org.jbox2d.dynamics.Body; | ||
import org.jbox2d.dynamics.BodyDef; | ||
import org.jbox2d.dynamics.BodyType; | ||
import org.jbox2d.dynamics.FixtureDef; | ||
import org.jbox2d.dynamics.World; | ||
|
||
import gama.extensions.physics.common.AbstractBodyWrapper; | ||
import gama.extensions.physics.common.IBody; | ||
import msi.gama.metamodel.agent.IAgent; | ||
import msi.gama.metamodel.shape.GamaPoint; | ||
import msi.gama.metamodel.shape.IShape; | ||
|
||
public class Box2DBodyWrapper extends AbstractBodyWrapper<World, Body, Shape, Vec2> implements IBox2DPhysicalEntity { | ||
|
||
final BodyDef def = new BodyDef(); | ||
final FixtureDef fixtureDef = new FixtureDef(); | ||
MassData ms = new MassData(); | ||
|
||
public Box2DBodyWrapper(final IAgent agent, final Box2DPhysicalWorld world) { | ||
super(agent, world); | ||
} | ||
|
||
@Override | ||
public Body createAndInitializeBody(final Shape shape, final World world) { | ||
IBody previous = (IBody) agent.getAttribute(BODY); | ||
if (previous != null) { | ||
GamaPoint pointTransfer = new GamaPoint(); | ||
def.type = isStatic ? BodyType.STATIC : BodyType.DYNAMIC; | ||
def.angularDamping = previous.getAngularDamping(); | ||
def.angularVelocity = (float) previous.getAngularVelocity(pointTransfer).norm(); | ||
def.linearDamping = previous.getLinearDamping(); | ||
toVector(previous.getLinearVelocity(pointTransfer), def.linearVelocity); | ||
def.allowSleep = false; | ||
def.userData = this; | ||
} | ||
Body body = world.createBody(def); | ||
if (previous != null) { | ||
fixtureDef.density = 1f; | ||
fixtureDef.friction = previous.getFriction(); | ||
fixtureDef.restitution = previous.getRestitution(); | ||
fixtureDef.shape = shape; | ||
} | ||
body.createFixture(fixtureDef); | ||
if (previous != null) { ms.mass = previous.getMass(); } | ||
body.setMassData(ms); | ||
return body; | ||
} | ||
|
||
@Override | ||
public float getMass() { | ||
return body.m_mass; | ||
} | ||
|
||
@Override | ||
public float getFriction() { | ||
return body.getFixtureList().getFriction(); | ||
} | ||
|
||
@Override | ||
public float getRestitution() { | ||
return body.getFixtureList().getRestitution(); | ||
} | ||
|
||
@Override | ||
public float getLinearDamping() { | ||
return body.m_linearDamping; | ||
} | ||
|
||
@Override | ||
public float getAngularDamping() { | ||
return body.m_angularDamping; | ||
} | ||
|
||
@Override | ||
public float getContactDamping() { | ||
// Doesnt exist | ||
return 0; | ||
} | ||
|
||
@Override | ||
public GamaPoint getAngularVelocity(final GamaPoint v) { | ||
// TODO Auto-generated method stub | ||
return null; | ||
} | ||
|
||
@Override | ||
public GamaPoint getLinearVelocity(final GamaPoint v) { | ||
return toGamaPoint(body.getLinearVelocity(), v); | ||
} | ||
|
||
@Override | ||
public IShape getAABB() { | ||
AABB aabb = body.getFixtureList().getAABB(0); | ||
Vec2 v = aabb.getExtents(); | ||
return buildRectangle(v.x * 2, v.y * 2, new GamaPoint(v.x, v.y)); | ||
} | ||
|
||
@Override | ||
public void setMass(final Double mass) { | ||
ms.mass = mass.floatValue(); | ||
body.setMassData(ms); | ||
|
||
} | ||
|
||
@Override | ||
public void setCCD(final boolean v) { | ||
// Verify this | ||
body.setBullet(v); | ||
} | ||
|
||
@Override | ||
public void setFriction(final Double friction) { | ||
body.getFixtureList().setFriction(friction.floatValue()); | ||
|
||
} | ||
|
||
@Override | ||
public void setRestitution(final Double restitution) { | ||
body.getFixtureList().setRestitution(restitution.floatValue()); | ||
} | ||
|
||
@Override | ||
public void setDamping(final Double damping) { | ||
body.setLinearDamping(damping.floatValue()); | ||
} | ||
|
||
@Override | ||
public void setAngularDamping(final Double damping) { | ||
body.setAngularDamping(damping.floatValue()); | ||
} | ||
|
||
@Override | ||
public void setContactDamping(final Double damping) { | ||
// Not available | ||
} | ||
|
||
@Override | ||
public void setAngularVelocity(final GamaPoint angularVelocity) { | ||
body.setAngularVelocity((float) angularVelocity.norm()); | ||
} | ||
|
||
@Override | ||
public void setLinearVelocity(final GamaPoint linearVelocity) { | ||
body.setLinearVelocity(toVector(linearVelocity)); | ||
} | ||
|
||
@Override | ||
public void setLocation(final GamaPoint loc) { | ||
body.setTransform(toVector(loc), body.getAngle()); | ||
} | ||
|
||
@Override | ||
public void clearForces() { | ||
body.setLinearVelocity(new Vec2(0, 0)); | ||
body.setAngularVelocity(0); | ||
} | ||
|
||
@Override | ||
public void applyImpulse(final GamaPoint impulse) { | ||
body.applyLinearImpulse(toVector(impulse), body.getLocalCenter(), true); | ||
} | ||
|
||
@Override | ||
public void applyTorque(final GamaPoint torque) { | ||
body.applyTorque((float) torque.norm()); | ||
} | ||
|
||
@Override | ||
public void applyForce(final GamaPoint force) { | ||
body.applyForceToCenter(toVector(force)); | ||
|
||
} | ||
|
||
} |
77 changes: 77 additions & 0 deletions
77
...gaml.extensions.physics/src/gama/extensions/physics/box2d_version/Box2DPhysicalWorld.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package gama.extensions.physics.box2d_version; | ||
|
||
import org.jbox2d.collision.shapes.Shape; | ||
import org.jbox2d.common.Vec2; | ||
import org.jbox2d.dynamics.World; | ||
|
||
import gama.extensions.physics.common.AbstractPhysicalWorld; | ||
import gama.extensions.physics.common.IShapeConverter; | ||
import gama.extensions.physics.gaml.PhysicalSimulationAgent; | ||
import msi.gama.metamodel.agent.IAgent; | ||
import msi.gama.metamodel.shape.GamaPoint; | ||
|
||
public class Box2DPhysicalWorld extends AbstractPhysicalWorld<World, Shape, Vec2> implements IBox2DPhysicalEntity { | ||
|
||
protected Box2DPhysicalWorld(final PhysicalSimulationAgent physicalSimulationAgent) { | ||
super(physicalSimulationAgent); | ||
} | ||
|
||
@Override | ||
public void registerAgent(final IAgent agent) { | ||
Box2DBodyWrapper body = new Box2DBodyWrapper(agent, this); | ||
} | ||
|
||
@Override | ||
public void unregisterAgent(final IAgent agent) { | ||
// TODO Auto-generated method stub | ||
|
||
} | ||
|
||
@Override | ||
public void setCCD(final boolean ccd) { | ||
|
||
} | ||
|
||
@Override | ||
public void setGravity(final GamaPoint gravity) { | ||
if (world != null) { world.setGravity(toVector(gravity)); } | ||
} | ||
|
||
@Override | ||
public void dispose() { | ||
// TODO Auto-generated method stub | ||
|
||
} | ||
|
||
@Override | ||
public void updatePositionsAndRotations() { | ||
// TODO Auto-generated method stub | ||
|
||
} | ||
|
||
@Override | ||
protected World createWorld() { | ||
GamaPoint p = simulation.getGravity(simulation.getScope()); | ||
World result = new World(toVector(p)); | ||
result.setAutoClearForces(true); | ||
result.setContactListener(contactListener); | ||
return result; | ||
} | ||
|
||
@Override | ||
protected IShapeConverter<Shape, Vec2> createShapeConverter() { | ||
return new Box2DShapeConverter(); | ||
} | ||
|
||
@Override | ||
protected void updateAgentsShape() { | ||
// TODO Auto-generated method stub | ||
|
||
} | ||
|
||
@Override | ||
protected void updateEngine(final Double timeStep, final int maxSubSteps) { | ||
getWorld().step(timeStep.floatValue(), maxSubSteps, maxSubSteps); | ||
} | ||
|
||
} |
86 changes: 86 additions & 0 deletions
86
...aml.extensions.physics/src/gama/extensions/physics/box2d_version/Box2DShapeConverter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package gama.extensions.physics.box2d_version; | ||
|
||
import org.jbox2d.collision.shapes.CircleShape; | ||
import org.jbox2d.collision.shapes.EdgeShape; | ||
import org.jbox2d.collision.shapes.PolygonShape; | ||
import org.jbox2d.collision.shapes.Shape; | ||
import org.jbox2d.common.Vec2; | ||
import org.locationtech.jts.geom.LineString; | ||
|
||
import gama.extensions.physics.common.IShapeConverter; | ||
import msi.gama.common.geometry.GeometryUtils; | ||
import msi.gama.metamodel.agent.IAgent; | ||
import msi.gama.metamodel.shape.GamaPoint; | ||
import msi.gama.metamodel.shape.IShape; | ||
import msi.gama.metamodel.shape.IShape.Type; | ||
import msi.gama.runtime.IScope; | ||
import msi.gama.util.matrix.GamaFloatMatrix; | ||
|
||
public class Box2DShapeConverter implements IShapeConverter<Shape, Vec2>, IBox2DPhysicalEntity { | ||
|
||
@Override | ||
public void computeTranslation(final IAgent agent, final Type type, final float depth, final Vec2 aabbTranslation, | ||
final Vec2 visualTranslation) { | ||
// Normally not applicable. | ||
} | ||
|
||
@Override | ||
public Shape convertShape(final IShape shape, final Type type, final float depth) { | ||
|
||
switch (type) { | ||
case BOX: | ||
case PLAN: | ||
case SQUARE: | ||
case CUBE: | ||
case CONE: | ||
case PYRAMID: | ||
PolygonShape p = new PolygonShape(); | ||
p.setAsBox(shape.getWidth().floatValue() / 2, shape.getHeight().floatValue() / 2); | ||
return p; | ||
case LINECYLINDER: | ||
// oriented on the Y or on the X (default) axis | ||
LineString line = (LineString) shape.getInnerGeometry(); | ||
EdgeShape e = new EdgeShape(); | ||
e.set(toVector((GamaPoint) line.getCoordinateN(0)), toVector((GamaPoint) line.getCoordinateN(1))); | ||
return e; | ||
case SPHERE: | ||
case CIRCLE: | ||
case POINT: | ||
case CYLINDER: | ||
CircleShape cc = new CircleShape(); | ||
cc.setRadius(shape.getWidth().floatValue() / 2); | ||
return cc; | ||
default: | ||
GamaPoint[] points = GeometryUtils.getPointsOf(shape); | ||
switch (points.length) { | ||
case 0: | ||
return null; | ||
case 1: | ||
return convertShape(shape, IShape.Type.POINT, depth); | ||
case 2: | ||
EdgeShape l = new EdgeShape(); | ||
l.set(toVector(points[0]), toVector(points[1])); | ||
return l; | ||
default: | ||
PolygonShape ps = new PolygonShape(); | ||
Vec2[] vertices = new Vec2[points.length]; | ||
for (int i = 0; i < points.length; i++) { | ||
vertices[i] = toVector(points[i]); | ||
} | ||
ps.set(vertices, vertices.length); | ||
return ps; | ||
} | ||
|
||
} | ||
} | ||
|
||
@Override | ||
public Shape convertTerrain(final IScope scope, final GamaFloatMatrix field, final Double width, | ||
final Double height, final float depth) { | ||
// No way to support "depth" here to build the shape :) | ||
PolygonShape rectangle = new PolygonShape(); | ||
rectangle.setAsBox(width.floatValue(), height.floatValue()); | ||
return rectangle; | ||
} | ||
|
||
} |
29 changes: 29 additions & 0 deletions
29
...ml.extensions.physics/src/gama/extensions/physics/box2d_version/IBox2DPhysicalEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package gama.extensions.physics.box2d_version; | ||
|
||
import org.jbox2d.common.Vec2; | ||
|
||
import gama.extensions.physics.common.IPhysicalEntity; | ||
import gama.extensions.physics.common.VectorUtils; | ||
import msi.gama.metamodel.shape.GamaPoint; | ||
|
||
public interface IBox2DPhysicalEntity extends IPhysicalEntity<Vec2> { | ||
@Override | ||
default Vec2 toVector(final GamaPoint v) { | ||
return VectorUtils.toBox2DVector(v); | ||
} | ||
|
||
default Vec2 toVector(final GamaPoint v, final Vec2 to) { | ||
return VectorUtils.toBox2DVector(v, to); | ||
} | ||
|
||
@Override | ||
default GamaPoint toGamaPoint(final Vec2 v) { | ||
return VectorUtils.toGamaPoint(v); | ||
|
||
} | ||
|
||
default GamaPoint toGamaPoint(final Vec2 v, final GamaPoint result) { | ||
return VectorUtils.toGamaPoint(v, result); | ||
} | ||
|
||
} |
Oops, something went wrong.