package org.atriasoft.gameengine.engines; import java.util.Vector; import org.atriasoft.etk.math.Vector3f; import org.atriasoft.gale.resource.ResourceColored3DObject; import org.atriasoft.gameengine.Component; import org.atriasoft.gameengine.Engine; import org.atriasoft.gameengine.Environement; import org.atriasoft.gameengine.camera.Camera; import org.atriasoft.gameengine.components.ComponentPhysics; import org.atriasoft.gameengine.internal.Log; import net.jreactphysics3d.constraint.ContactPointInfo; import net.jreactphysics3d.engine.DynamicsWorld; import net.jreactphysics3d.engine.EventListener; public class EnginePhysics extends Engine implements EventListener { public static final String ENGINE_NAME = "physics"; // Constant physics time step private static final float TIME_STEP = 1.0f / 60.0f; boolean propertyDebugAABB = false; boolean propertyDebugShape = false; // Start engine with no gravity private final Vector3f gravity = new Vector3f(0.0f, 0.0f, 0.0f); private float accumulator = 0; //private final EngineGravity gravity; private final DynamicsWorld dynamicsWorld; private final Vector components = new Vector(); private final ResourceColored3DObject debugDrawProperty = ResourceColored3DObject.create(); public EnginePhysics(final Environement env) { super(env); /* this.gravity = (EngineGravity) env.getEngine("gravity"); if (this.gravity == null) { Log.critical("Must initialyse Gravity before physics..."); } */ final Vector3f gravity = new Vector3f(0.0f, 0.0f, 0.0f); this.dynamicsWorld = new DynamicsWorld(gravity); // Set the number of iterations of the constraint solver this.dynamicsWorld.setNbIterationsVelocitySolver(15); this.dynamicsWorld.setEventListener(this); } private void applyForces(final float timeStep) { for (final ComponentPhysics it : this.components) { //it.applyForces(TIME_STEP, gravity); } } @Override public void beginContact(final ContactPointInfo contact) { ComponentPhysics component1 = null; ComponentPhysics component2 = null; // Called when a new contact point is found between two bodies that were separated before. Log.warning("collision detection [BEGIN] " + contact.localPoint1 + " depth=" + contact.penetrationDepth); if (contact.shape1 != null && contact.shape1.getUserData() != null) { component1 = (ComponentPhysics) contact.shape1.getUserData(); } if (contact.shape2 != null && contact.shape2.getUserData() != null) { component2 = (ComponentPhysics) contact.shape2.getUserData(); } if (component1 != null) { component1.beginContact(component2, contact.normal, contact.localPoint1, contact.localPoint2, contact.penetrationDepth); } if (component2 != null) { component2.beginContact(component1, contact.normal.multiplyNew(-1), contact.localPoint2, contact.localPoint1, contact.penetrationDepth); } } @Override public void beginInternalTick() { // TODO Auto-generated method stub } @Override public void componentAdd(final Component ref) { if (ref instanceof ComponentPhysics == false) { return; } final ComponentPhysics elem = (ComponentPhysics) ref; this.components.add(elem); elem.generate(); } @Override public void componentRemove(final Component ref) { this.components.remove(ref); } @Override public void endInternalTick() { // TODO Auto-generated method stub } public DynamicsWorld getDynamicsWorld() { return this.dynamicsWorld; } @Override public String getType() { // TODO Auto-generated method stub return ENGINE_NAME; } @Override public void newContact(final ContactPointInfo contact) { ComponentPhysics component1 = null; ComponentPhysics component2 = null; //Called when a new contact point is found between two bodies. Log.warning("collision detection [ NEW ] " + contact.localPoint1 + " depth=" + contact.penetrationDepth); if (contact.shape1 != null && contact.shape1.getUserData() != null) { component1 = (ComponentPhysics) contact.shape1.getUserData(); } if (contact.shape2 != null && contact.shape2.getUserData() != null) { component2 = (ComponentPhysics) contact.shape2.getUserData(); } if (component1 != null) { component1.newContact(component2, contact.normal, contact.localPoint1, contact.localPoint2, contact.penetrationDepth); } if (component2 != null) { component2.newContact(component1, contact.normal.multiplyNew(-1), contact.localPoint2, contact.localPoint1, contact.penetrationDepth); } } @Override public void render(final long deltaMili, final Camera camera) { // TODO Auto-generated method stub for (final ComponentPhysics it : this.components) { //Log.info("Render " + it); it.renderDebug(this.debugDrawProperty, camera); } //debugDrawProperty.drawCone(2, 5, 9, 12, Matrix4f.identity(), new Color(1,1,0,1)); //debugDrawProperty.drawSquare(new Vector3f(1,1,1), Matrix4f.identity(), new Color(1,1,0,1)); //debugDrawProperty.drawCubeLine(new Vector3f(1,1,1), new Vector3f(5,5,5), new Color(1,0,1,1), Matrix4f.identity(), true, true); //debugDrawProperty.drawCubeLine(new Vector3f(0,0,0), new Vector3f(32,32,32), new Color(1,0,1,1), Matrix4f.identity(), true, true); } @Override public void renderDebug(final long deltaMili, final Camera camera) { if (this.propertyDebugShape == true) { for (final ComponentPhysics it : this.components) { it.drawShape(this.debugDrawProperty, camera); } } if (this.propertyDebugAABB == true) { for (final ComponentPhysics it : this.components) { it.renderDebug(this.debugDrawProperty, camera); } } } void setGravity(final Vector3f _axePower) { if (this.dynamicsWorld != null) { final Vector3f gravity = _axePower.clone(); this.dynamicsWorld.setGravity(gravity); } } @Override public void update(final long deltaMili) { final float deltaTime = deltaMili * 0.0001f; // Add the time difference in the accumulator this.accumulator += deltaTime; // While there is enough accumulated time to take one or several physics steps while (this.accumulator >= TIME_STEP) { if (this.dynamicsWorld != null) { // call every object to usdate their constant forces applyed for (final ComponentPhysics it : this.components) { if (it != null) { it.update(TIME_STEP); } } // Update the Dynamics world with a constant time step Log.debug("Update the Physic engine ... " + TIME_STEP); this.dynamicsWorld.update(TIME_STEP); } // Decrease the accumulated time this.accumulator -= TIME_STEP; } for (final ComponentPhysics elem : this.components) { elem.emitAll(); } } }