diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md
index 783a724b..9dc19f22 100644
--- a/docs/src/progress/renderertodo.md
+++ b/docs/src/progress/renderertodo.md
@@ -2119,6 +2119,7 @@ Fix projection matrix being sent to light manager
(06/05/2025)
voxel tests
+Physics work
diff --git a/src/main/java/electrosphere/collision/CollisionEngine.java b/src/main/java/electrosphere/collision/CollisionEngine.java
index 586a4c33..c54ac599 100644
--- a/src/main/java/electrosphere/collision/CollisionEngine.java
+++ b/src/main/java/electrosphere/collision/CollisionEngine.java
@@ -7,6 +7,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
import org.joml.Matrix4d;
import org.joml.Quaterniond;
@@ -135,6 +136,12 @@ public class CollisionEngine {
*/
protected static final int MAX_CONTACTS = 64;
+ /**
+ *
Maximum number of contact points per geom-geom collision
+ * Note:
+ */
+ protected static final int MIN_CONTACTS = 4;
+
/**
* The list of dbodies ode should be tracking
*/
@@ -265,13 +272,13 @@ public class CollisionEngine {
case Collidable.TYPE_CREATURE: {
switch(impactor.getType()){
case Collidable.TYPE_STATIC: {
- receiver.addImpulse(new Impulse(normal, localPosition, worldPos, magnitude * 2, Collidable.TYPE_STATIC));
+ receiver.addImpulse(normal, localPosition, worldPos, magnitude * 2, Collidable.TYPE_STATIC);
} break;
case Collidable.TYPE_CREATURE: {
- receiver.addImpulse(new Impulse(normal, localPosition, worldPos, magnitude, Collidable.TYPE_CREATURE));
+ receiver.addImpulse(normal, localPosition, worldPos, magnitude, Collidable.TYPE_CREATURE);
} break;
case Collidable.TYPE_OBJECT: {
- receiver.addImpulse(new Impulse(normal, localPosition, worldPos, magnitude, Collidable.TYPE_OBJECT));
+ receiver.addImpulse(normal, localPosition, worldPos, magnitude, Collidable.TYPE_OBJECT);
} break;
}
} break;
@@ -1608,12 +1615,15 @@ public class CollisionEngine {
* @return The status of the collision engine
*/
public String getStatus(){
+ CollisionEngine.lockOde();
String message = "" +
"Name: " + this.name + "\n" +
"Bodies: " + this.bodies.size() + "\n" +
"Body Ptrs: " + this.bodyPointerMap.size() + "\n" +
"Geom Ptrs: " + this.geomPointerMap.size() + "\n" +
"Collidables: " + this.collidableList.size() + "\n" +
+ " (Static) Collidables: " + this.collidableList.stream().filter((Collidable collidable) -> collidable.getType().matches(Collidable.TYPE_STATIC)).collect(Collectors.toList()).size() + "\n" +
+ " (Creature) Collidables: " + this.collidableList.stream().filter((Collidable collidable) -> collidable.getType().matches(Collidable.TYPE_CREATURE)).collect(Collectors.toList()).size() + "\n" +
"Space geom count: " + this.space.getNumGeoms() + "\n" +
"Tracked geom count: " + this.geomCount + "\n" +
"Floating origin: " + this.floatingOrigin.x + "," + this.floatingOrigin.y + "," + this.floatingOrigin.z + "\n" +
@@ -1621,6 +1631,7 @@ public class CollisionEngine {
"Final Collision Count: " + this.finalCollisionCount + "\n" +
""
;
+ CollisionEngine.unlockOde();
return message;
}
diff --git a/src/main/java/electrosphere/collision/PhysicsCallback.java b/src/main/java/electrosphere/collision/PhysicsCallback.java
index 3d928815..2ce2f4bd 100644
--- a/src/main/java/electrosphere/collision/PhysicsCallback.java
+++ b/src/main/java/electrosphere/collision/PhysicsCallback.java
@@ -25,6 +25,11 @@ public class PhysicsCallback implements DNearCallback {
*/
protected CollisionEngine engine;
+ /**
+ * Enables geom-geom collisions between non-statics
+ */
+ private boolean enableGeomGeom = false;
+
/**
* Constructor
*/
@@ -43,7 +48,13 @@ public class PhysicsCallback implements DNearCallback {
}
//if neither are bodies
- if(o1.getBody() == null && o2.getBody() == null){
+ if(
+ o1.getBody() == null && o2.getBody() == null &&
+ (
+ !this.enableGeomGeom ||
+ (o1.getCategoryBits() == Collidable.TYPE_STATIC_BIT && o2.getCategoryBits() == Collidable.TYPE_STATIC_BIT)
+ )
+ ){
return;
}
@@ -91,6 +102,16 @@ public class PhysicsCallback implements DNearCallback {
throw new Error(message);
}
+ //Controls whether we should grab MAX_CONTACTS or MIN_CONTACTS
+ boolean isGeomGeomCollision = o1.getBody() == null && o2.getBody() == null;
+
+ //Number of contacts to poll for
+ int contactCount = CollisionEngine.MAX_CONTACTS;
+ if(isGeomGeomCollision && this.enableGeomGeom){
+ contactCount = CollisionEngine.MIN_CONTACTS;
+ }
+
+
Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - Full collision phase");
try {
Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - setup");
@@ -101,7 +122,7 @@ public class PhysicsCallback implements DNearCallback {
if(c2 != null){
surfaceParams2 = c2.getSurfaceParams();
}
- for (int i=0; i< CollisionEngine.MAX_CONTACTS; i++) {
+ for (int i=0; i< contactCount; i++) {
DContact contact = engine.contacts.get(i);
contact.surface.mode = surfaceParams1.getMode();
contact.surface.mu = surfaceParams1.getMu();
@@ -144,7 +165,7 @@ public class PhysicsCallback implements DNearCallback {
Globals.profiler.endCpuSample();
//calculate collisions
Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - OdeHelper.collide");
- int numc = OdeHelper.collide(o1,o2,CollisionEngine.MAX_CONTACTS,engine.contacts.getGeomBuffer());
+ int numc = OdeHelper.collide(o1,o2,contactCount,engine.contacts.getGeomBuffer());
Globals.profiler.endCpuSample();
//create DContacts based on each collision that occurs
Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - contact iterations");
@@ -160,18 +181,20 @@ public class PhysicsCallback implements DNearCallback {
}
//
- //add contact to contact group
- DJoint c = OdeHelper.createContactJoint(engine.world,engine.contactgroup,contact);
- if(b1 == null){
- if(b2 == null){
+ //add contact to contact group - don't create contacts for non-geom collisions
+ if(!isGeomGeomCollision){
+ DJoint c = OdeHelper.createContactJoint(engine.world,engine.contactgroup,contact);
+ if(b1 == null){
+ if(b2 == null){
+ } else {
+ c.attach(null,b2);
+ }
} else {
- c.attach(null,b2);
- }
- } else {
- if(b2 == null){
- c.attach(b1,null);
- } else {
- c.attach(b1,b2);
+ if(b2 == null){
+ c.attach(b1,null);
+ } else {
+ c.attach(b1,b2);
+ }
}
}
diff --git a/src/main/java/electrosphere/collision/collidable/Collidable.java b/src/main/java/electrosphere/collision/collidable/Collidable.java
index e7bf9d7f..8f782f1e 100644
--- a/src/main/java/electrosphere/collision/collidable/Collidable.java
+++ b/src/main/java/electrosphere/collision/collidable/Collidable.java
@@ -4,14 +4,20 @@ import electrosphere.entity.Entity;
import electrosphere.entity.state.collidable.Impulse;
import java.util.Arrays;
-import java.util.LinkedList;
import java.util.List;
+import org.joml.Vector3d;
+
/**
* Stores the type of the collidable object as well as the impulses currently applied to it
*/
public class Collidable {
+
+ /**
+ * Max impulses that can be applied to a collidable
+ */
+ public static final int MAX_IMPULSES = 5;
/**
* The entity this collidable is attached to
@@ -31,7 +37,12 @@ public class Collidable {
/**
* The impulses to be applied to this collidable
*/
- private List impulses = new LinkedList();
+ private Impulse[] impulses = new Impulse[MAX_IMPULSES];
+
+ /**
+ * The number of impulses stored in the collidable
+ */
+ private int impulseCount = 0;
/**
* The params for the surface of this collidable when a collision occurs
@@ -78,6 +89,9 @@ public class Collidable {
this.type = type;
this.parentTracksCollidable = parentTracksCollidable;
this.surfaceParams = new SurfaceParams();
+ for(int i = 0; i < MAX_IMPULSES; i++){
+ this.impulses[i] = new Impulse();
+ }
}
/**
@@ -96,12 +110,42 @@ public class Collidable {
return this.surfaceParams;
}
- public List getImpulses() {
+ /**
+ * Gets the array of impulses
+ * @return The array of impulses
+ */
+ public Impulse[] getImpulses() {
return impulses;
}
+ /**
+ * Adds an impulse the collidable
+ * @param impulse The impulse
+ */
public void addImpulse(Impulse impulse) {
- impulses.add(impulse);
+ if(this.impulseCount < MAX_IMPULSES){
+ impulses[this.impulseCount].setCollisionPoint(impulse.getCollisionPoint());
+ impulses[this.impulseCount].setDirection(impulse.getDirection());
+ impulses[this.impulseCount].setWorldPoint(impulse.getWorldPoint());
+ impulses[this.impulseCount].setType(impulse.getType());
+ impulses[this.impulseCount].setForce(impulse.getForce());
+ this.impulseCount++;
+ }
+ }
+
+ /**
+ * Adds an impulse the collidable
+ * @param impulse The impulse
+ */
+ public void addImpulse(Vector3d direction, Vector3d collisionPoint, Vector3d worldPoint, double force, String type){
+ if(this.impulseCount < MAX_IMPULSES){
+ impulses[this.impulseCount].setCollisionPoint(collisionPoint);
+ impulses[this.impulseCount].setDirection(direction);
+ impulses[this.impulseCount].setWorldPoint(worldPoint);
+ impulses[this.impulseCount].setType(type);
+ impulses[this.impulseCount].setForce(force);
+ this.impulseCount++;
+ }
}
public Entity getParent() {
@@ -124,8 +168,14 @@ public class Collidable {
this.type = type;
}
+ /**
+ * Clears the impulses
+ */
public void clear(){
- impulses.clear();
+ for(int i = 0; i < MAX_IMPULSES; i++){
+ impulses[i].clear();
+ }
+ this.impulseCount = 0;
}
/**
@@ -144,6 +194,14 @@ public class Collidable {
this.ready = ready;
}
+ /**
+ * Gets the number of impulses stored in the collidable
+ * @return The number of impulses
+ */
+ public int getImpulseCount(){
+ return this.impulseCount;
+ }
+
diff --git a/src/main/java/electrosphere/entity/state/collidable/Impulse.java b/src/main/java/electrosphere/entity/state/collidable/Impulse.java
index 7812d618..192cc7f3 100644
--- a/src/main/java/electrosphere/entity/state/collidable/Impulse.java
+++ b/src/main/java/electrosphere/entity/state/collidable/Impulse.java
@@ -21,25 +21,109 @@ public class Impulse {
this.worldPoint = worldPoint;
}
+ /**
+ * Constructor for collidable work
+ */
+ public Impulse(){
+ this.direction = new Vector3d();
+ this.collisionPoint = new Vector3d();
+ this.worldPoint = new Vector3d();
+ this.force = 0;
+ this.type = null;
+ }
+
+ /**
+ * Gets the direction of the impulse
+ * @return The direction of the impulse
+ */
public Vector3d getDirection() {
return direction;
}
+ /**
+ * Gets the force of the impulse
+ * @return The force of the impulse
+ */
public double getForce() {
return force;
}
+ /**
+ * Gets the type of the impulse
+ * @return The type of the impulse
+ */
public String getType() {
return type;
}
+ /**
+ * Gets the collision point of the impulse
+ * @return The collision point of the impulse
+ */
public Vector3d getCollisionPoint() {
return collisionPoint;
}
+ /**
+ * Gets the world point of the impulse
+ * @return The world point of the impulse
+ */
public Vector3d getWorldPoint(){
return worldPoint;
}
+
+ /**
+ * Sets the direction of the impulse
+ * @param direction The direction of the impulse
+ */
+ public void setDirection(Vector3d direction) {
+ this.direction = direction;
+ }
+
+ /**
+ * Sets the collision point of the impulse
+ * @param collisionPoint The collision point of the impulse
+ */
+ public void setCollisionPoint(Vector3d collisionPoint) {
+ this.collisionPoint = collisionPoint;
+ }
+
+ /**
+ * Sets the world point of the impulse
+ * @param worldPoint The world point of the impulse
+ */
+ public void setWorldPoint(Vector3d worldPoint) {
+ this.worldPoint = worldPoint;
+ }
+
+ /**
+ * Sets the force of the impulse
+ * @param force The force of the impulse
+ */
+ public void setForce(double force) {
+ this.force = force;
+ }
+
+ /**
+ * Sets the type of the impulse
+ * @param type The type of the impulse
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Clears the data in the impulse
+ */
+ public void clear(){
+ this.direction.set(0,0,0);
+ this.collisionPoint.set(0,0,0);
+ this.worldPoint.set(0,0,0);
+ this.force = 0;
+ this.type = null;
+ }
+
+
}
diff --git a/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java b/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java
index 947552a7..6f75d674 100644
--- a/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java
+++ b/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java
@@ -3,10 +3,13 @@ package electrosphere.entity.state.collidable;
import electrosphere.collision.collidable.Collidable;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
+import electrosphere.entity.EntityUtils;
+import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.state.movement.fall.ServerFallTree;
+import org.joml.Vector3d;
import org.ode4j.ode.DBody;
import org.ode4j.ode.DGeom;
@@ -25,6 +28,11 @@ public class ServerCollidableTree implements BehaviorTree {
*/
protected DBody body;
+ /**
+ * The geom
+ */
+ protected DGeom geom;
+
/**
* The collidable
*/
@@ -52,6 +60,7 @@ public class ServerCollidableTree implements BehaviorTree {
public ServerCollidableTree(Entity e, Collidable collidable, DGeom geom){
parent = e;
this.collidable = collidable;
+ this.geom = geom;
}
/**
@@ -61,16 +70,22 @@ public class ServerCollidableTree implements BehaviorTree {
public void simulate(float deltaTime){
//have we hit a terrain impulse?
//handle impulses
- for(Impulse impulse : collidable.getImpulses()){
- if(impulse.type.matches(Collidable.TYPE_CREATURE)){
+ Impulse[] impulses = collidable.getImpulses();
+ Vector3d pos = EntityUtils.getPosition(parent);
+ for(int i = 0; i < collidable.getImpulseCount(); i++){
+ if(impulses[i].type.matches(Collidable.TYPE_CREATURE)){
if(ServerGravityTree.getServerGravityTree(parent)!=null){
ServerGravityTree.getServerGravityTree(parent).start();
}
}
- if(impulse.type.matches(Collidable.TYPE_WORLD_BOUND) || impulse.type.matches(Collidable.TYPE_STATIC)){
+ if(impulses[i].type.matches(Collidable.TYPE_WORLD_BOUND) || impulses[i].type.matches(Collidable.TYPE_STATIC)){
this.resetGravityFall();
+ pos.add(impulses[i].getDirection().mul(impulses[i].getForce()));
}
}
+ if(geom != null){
+ ServerEntityUtils.repositionEntity(parent, pos);
+ }
collidable.setReady(true);
diff --git a/src/main/java/electrosphere/entity/state/gravity/ClientGravityTree.java b/src/main/java/electrosphere/entity/state/gravity/ClientGravityTree.java
index 48a4341b..6af877de 100644
--- a/src/main/java/electrosphere/entity/state/gravity/ClientGravityTree.java
+++ b/src/main/java/electrosphere/entity/state/gravity/ClientGravityTree.java
@@ -119,7 +119,9 @@ public class ClientGravityTree implements BehaviorTree {
public boolean hadGroundCollision(){
boolean rVal = false;
- for(Impulse impulse : collidable.getImpulses()){
+ Impulse[] impulses = collidable.getImpulses();
+ for(int i = 0; i < collidable.getImpulseCount(); i++){
+ Impulse impulse = impulses[i];
if(impulse.getType().equals(Collidable.TYPE_STATIC)){
rVal = true;
break;
@@ -142,7 +144,9 @@ public class ClientGravityTree implements BehaviorTree {
public boolean hadEntityCollision(){
boolean rVal = false;
- for(Impulse impulse : collidable.getImpulses()){
+ Impulse[] impulses = collidable.getImpulses();
+ for(int i = 0; i < collidable.getImpulseCount(); i++){
+ Impulse impulse = impulses[i];
if(impulse.getType().equals(Collidable.TYPE_CREATURE)){
rVal = true;
break;
diff --git a/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java b/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java
index 4cd07c26..af0a4c15 100644
--- a/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java
+++ b/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java
@@ -138,7 +138,9 @@ public class ServerGravityTree implements BehaviorTree {
*/
public boolean hadGroundCollision(){
boolean rVal = false;
- for(Impulse impulse : collidable.getImpulses()){
+ Impulse[] impulses = collidable.getImpulses();
+ for(int i = 0; i < collidable.getImpulseCount(); i++){
+ Impulse impulse = impulses[i];
if(impulse.getType().equals(Collidable.TYPE_STATIC)){
rVal = true;
break;
@@ -165,7 +167,9 @@ public class ServerGravityTree implements BehaviorTree {
*/
public boolean hadEntityCollision(){
boolean rVal = false;
- for(Impulse impulse : collidable.getImpulses()){
+ Impulse[] impulses = collidable.getImpulses();
+ for(int i = 0; i < collidable.getImpulseCount(); i++){
+ Impulse impulse = impulses[i];
if(impulse.getType().equals(Collidable.TYPE_CREATURE)){
rVal = true;
break;
diff --git a/src/main/java/electrosphere/entity/state/movement/fall/ClientFallTree.java b/src/main/java/electrosphere/entity/state/movement/fall/ClientFallTree.java
index c44351a8..1c5f5d13 100644
--- a/src/main/java/electrosphere/entity/state/movement/fall/ClientFallTree.java
+++ b/src/main/java/electrosphere/entity/state/movement/fall/ClientFallTree.java
@@ -141,7 +141,10 @@ public class ClientFallTree implements BehaviorTree {
public boolean hadGroundCollision(){
boolean rVal = false;
if(PhysicsEntityUtils.getCollidable(parent) != null){
- for(Impulse impulse : PhysicsEntityUtils.getCollidable(parent).getImpulses()){
+ Collidable collidable = PhysicsEntityUtils.getCollidable(parent);
+ Impulse[] impulses = collidable.getImpulses();
+ for(int i = 0; i < collidable.getImpulseCount(); i++){
+ Impulse impulse = impulses[i];
if(impulse.getType().equals(Collidable.TYPE_STATIC)){
rVal = true;
break;