Hello, I realize dyn4j isn’t directly supported by jme but the dyn4j forum is dead and a few people here use dyn4j so I was hoping I might get pointed in the right direction.
I have dyn4j running physics and collision detection in my simple space asteroids game, and on occasion my projectiles won’t register collisions with the asteroids. Here’s a quick image showing several projectiles, 2 of which register a hit and 2 which do not. The actual frequency of failed hits is probably <10% but as you can see here it tends to happen in waves.
I’ll try to get all the related code in an easy to read order:
first, the projectile movement and detection code
public void physUpdate(double tpf) {
if(projectiles.applyChanges());
List<ConvexCastResult> results = new ArrayList<>();
for(Entity e : projectiles){
//raycast the next position, if we can move there do so
Transform trans = e.get(Transform.class);
Projectile projectile = e.get(Projectile.class);
Vector2 startPos = trans.getPosition();
Vector2 vel = projectile.getVelocity().product(tpf);
Vector2 nextPos = startPos.sum(vel);
ed.setComponent(e.getId(), new Transform(nextPos));
CollisionMask mask = e.get(CollisionMask.class);
Filter filter = new CategoryFilter(mask.getGroup(), mask.getMask());
//Collisions are still being iffy, convex and ray casting both miss collisions occaisionally
org.dyn4j.geometry.Transform worldTrans = new org.dyn4j.geometry.Transform();
worldTrans.setTranslation(startPos);
Convex convex = new Circle(projectile.getSize());
if(world.convexCast(convex, worldTrans, vel, 0, filter, true, true, true, results)){
for(ConvexCastResult result : results){
EntityId id = (EntityId)result.getBody().getUserData();
long power = e.get(Attack.class).getAttack();
ed.setComponents(ed.createEntity(), new Damage(id, power), e.get(Parent.class));
}
ed.setComponents(ed.createEntity(),
new SoundEffect(e.get(ImpactEffect.class).getSoundEffect()),
new Decay(1)
);
ed.removeEntity(e.getId());
}
}
}
Collision groups
public static final long PLAYERGROUP = 1;
public static final long ASTEROIDGROUP = 1 << 1;
public static final long PROJECTILEGROUP = 1 << 2;
public static final long PICKUPGROUP = 1 << 3;
spawning of projectiles
@Override
public void fire(Entity parent, EntityData ed) {
hasFired = true;
Transform pTrans = parent.get(Transform.class);
Vector2 pos = pTrans.getPosition().sum(new Vector2(0,1).rotate(pTrans.getRotation()));
Vector2 velocity = new Vector2(0,10).rotate(pTrans.getRotation());
EntityId id = ed.createEntity();
ed.setComponents(id,
new Projectile(velocity, 0.25),
new Attack(3),
new Transform(pos),
new Model(Model.BLASTER),
new Color(ColorRGBA.Red),
new Decay(3f),
new Parent(parent.getId()),
new CollisionMask(CollisionMask.PROJECTILEGROUP, CollisionMask.ASTEROIDGROUP),
new SoundEffect("Sounds/BlasterShoot.wav"),
new ImpactEffect("Sounds/BlasterHit.wav")
);
projectiles[curProjectile] = id;
curProjectile = -1;
}
spawning of asteroids
public EntityId spawnAsteroid(int size, Vector2 position, double dir){
EntityId id = ed.createEntity();
Vector2 vel = new Vector2(0, 1+random.nextDouble()*4);
vel.rotate(random.nextDouble()*Math.PI*2);
ed.setComponents(id,
new Model(Model.ASTEROID),
new Color(ColorRGBA.Brown),
new Transform(position, dir),
new Size(size),
new Health(size*3),
new InitialVelocity(vel, 0),
new Attack(1),
new Bounded(Bounded.Behaviour.WRAP, 20),
new Collider(1, 0, false, new Circle(size)),
new CollisionMask(CollisionMask.ASTEROIDGROUP,
CollisionMask.PLAYERGROUP|CollisionMask.PROJECTILEGROUP)
);
LOG.log(Level.FINE, "Spawning an asteroid at {0}", position);
return id;
}
very last, adding of collisions objects to the world
private void addBody(Entity e){
Body b = new Body();
Collider col = e.get(Collider.class);
Transform trans = e.get(Transform.class);
double density = col.getDensity();
CollisionMask mask = e.get(CollisionMask.class);
CategoryFilter filter = new CategoryFilter(mask.getGroup(), mask.getMask());
for(Convex c : col.getShapes()){
BodyFixture bf = b.addFixture(c, density);
bf.setFilter(filter);
}
b.setUserData(e.getId());
b.setMass(col.getMassType());
b.setLinearDamping(col.getDamping());
b.setAngularDamping(col.getDamping());
b.getTransform().setTranslation(trans.getPosition());
b.getTransform().setRotation(trans.getRotation());
InitialVelocity vel = ed.getComponent(e.getId(), InitialVelocity.class);
if(vel != null){
b.setLinearVelocity(vel.getLinVel());
b.setAngularVelocity(vel.getAngVel());
}
bodyMap.put(e.getId(), b);
world.addBody(b);
}
I have been fighting these disappearing collisions for a while now. Before I was using raycasts, but I switched to convex casting to make sure it wasn’t the rays. I imagine it might have something to do with the collision masking but as far as I can tell the mask is mirrored correctly so either body can initiate against the other. Has anyone else had these sort of missed collisions before?