Skip to content

Instantly share code, notes, and snippets.

@capdevon
Last active December 3, 2023 20:47
Show Gist options
  • Save capdevon/5ddb980c8ff68eee79e4172303d6acf1 to your computer and use it in GitHub Desktop.
Save capdevon/5ddb980c8ff68eee79e4172303d6acf1 to your computer and use it in GitHub Desktop.
Testing Minie 7.7.1-SNAPSHOT
package mygame.physics;
import java.util.Arrays;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.ContactListener;
import com.jme3.bullet.collision.PhysicsCollisionObject;
/**
*
* @author capdevon
*/
public class MyContactListener implements ContactListener {
// PhysicsSpace whose notifications are being managed.
private final PhysicsSpace space;
public MyContactListener(PhysicsSpace space) {
this.space = space;
}
@Override
public void onContactEnded(long manifoldId) {
System.out.printf("%s onContactEnded: %d%n", toHexString(this), manifoldId);
System.out.println(Arrays.toString(space.listManifoldIds()));
}
@Override
public void onContactProcessed(PhysicsCollisionObject pcoA, PhysicsCollisionObject pcoB, long manifoldPointId) {
System.out.printf("%s onContactProcessed: %d%n", toHexString(this), manifoldPointId);
}
@Override
public void onContactStarted(long manifoldId) {
System.out.printf("%s onContactStarted: %d%n", toHexString(this), manifoldId);
System.out.println(Arrays.toString(space.listManifoldIds()));
}
private String toHexString(Object obj) {
if (obj != null) {
return obj.getClass().getSimpleName() + '@' + Integer.toHexString(obj.hashCode());
}
return null;
}
}
package mygame.physics;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import com.jme3.bullet.ContactManager;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.ContactListener;
import com.jme3.bullet.collision.PersistentManifolds;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.bullet.collision.PhysicsCollisionObject;
/**
*
* @author capdevon
*/
public class MyContactManager implements ContactManager {
public boolean doEnded = true;
public boolean doProcessed = true;
public boolean doStarted = true;
private final Deque<PhysicsCollisionEvent> ongoingEvents = new ArrayDeque<>(99);
private final Deque<PhysicsCollisionEvent> startedEvents = new ArrayDeque<>(99);
private final Collection<PhysicsCollisionListener> ongoingListeners = new ArrayList<>(4);
private final Collection<PhysicsCollisionListener> startedListeners = new ArrayList<>(4);
private final List<ContactListener> immediateListeners = new ArrayList<>(4);
// PhysicsSpace whose notifications are being managed.
private final PhysicsSpace space;
public MyContactManager(PhysicsSpace space) {
this.space = space;
}
@Override
public void onContactEnded(long manifoldId) {
for (ContactListener listener : immediateListeners) {
listener.onContactEnded(manifoldId);
}
}
@Override
public void onContactProcessed(PhysicsCollisionObject pcoA, PhysicsCollisionObject pcoB, long pointId) {
for (ContactListener listener : immediateListeners) {
listener.onContactProcessed(pcoA, pcoB, pointId);
}
if (!ongoingListeners.isEmpty()) {
PhysicsCollisionEvent event = new PhysicsCollisionEvent(pcoA, pcoB, pointId);
// Queue the event to be handled later by distributeEvents().
ongoingEvents.add(event);
}
}
@Override
public void onContactStarted(long manifoldId) {
for (ContactListener listener : immediateListeners) {
listener.onContactStarted(manifoldId);
}
if (!startedListeners.isEmpty()) {
int numPoints = PersistentManifolds.countPoints(manifoldId);
if (numPoints > 0) {
long bodyAId = PersistentManifolds.getBodyAId(manifoldId);
PhysicsCollisionObject pcoA = PhysicsCollisionObject.findInstance(bodyAId);
long bodyBId = PersistentManifolds.getBodyBId(manifoldId);
PhysicsCollisionObject pcoB = PhysicsCollisionObject.findInstance(bodyBId);
for (int i = 0; i < numPoints; ++i) {
long pointId = PersistentManifolds.getPointId(manifoldId, i);
PhysicsCollisionEvent event = new PhysicsCollisionEvent(pcoA, pcoB, pointId);
// Queue the event to be handled later by distributeEvents().
startedEvents.add(event);
}
}
}
}
/**
* Distribute queued collision events to registered listeners.
*/
@Override
public void distributeEvents() {
while (!startedEvents.isEmpty()) {
PhysicsCollisionEvent event = startedEvents.pop();
for (PhysicsCollisionListener listener : startedListeners) {
listener.collision(event);
}
}
while (!ongoingEvents.isEmpty()) {
PhysicsCollisionEvent event = ongoingEvents.pop();
for (PhysicsCollisionListener listener : ongoingListeners) {
listener.collision(event);
}
}
}
@Override
public void update(float timeInterval, int maxSteps) {
space.update(timeInterval, maxSteps, doEnded, doProcessed, doStarted);
}
@Override
public void addCollisionListener(PhysicsCollisionListener listener) {
startedListeners.add(listener);
}
@Override
public void addOngoingCollisionListener(PhysicsCollisionListener listener) {
ongoingListeners.add(listener);
}
@Override
public void addContactListener(ContactListener listener, boolean doEnded, boolean doProcessed, boolean doStarted) {
// ignore flags
immediateListeners.add(listener);
}
@Override
public void removeCollisionListener(PhysicsCollisionListener listener) {
startedListeners.remove(listener);
}
@Override
public void removeOngoingCollisionListener(PhysicsCollisionListener listener) {
ongoingListeners.remove(listener);
}
@Override
public void removeContactListener(ContactListener listener) {
immediateListeners.remove(listener);
}
@Override
public int countCollisionListeners() {
return ongoingListeners.size() + startedListeners.size();
}
public void clearContactListeners() {
immediateListeners.clear();
}
public void clearCollisionListeners() {
startedListeners.clear();
}
public void clearOngoingCollisionListeners() {
ongoingListeners.clear();
}
}
package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.GhostControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.objects.PhysicsBody;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.Trigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.system.AppSettings;
import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
import mygame.physics.MyContactListener;
import mygame.physics.MyContactManager;
/**
*
* @author capdevon
*/
public class Test_Main2 extends SimpleApplication implements ActionListener {
/**
*
* @param args
*/
public static void main(String[] args) {
Test_Main2 app = new Test_Main2();
AppSettings settings = new AppSettings(true);
settings.setResolution(1280, 720);
app.setSettings(settings);
app.setShowSettings(false);
app.setPauseOnLostFocus(false);
app.start();
}
private BulletAppState physics;
private RigidBodyControl ball;
private BitmapText hud;
@Override
public void simpleInitApp() {
// viewPort.setBackgroundColor(new ColorRGBA(0.5f, 0.6f, 0.7f, 1.0f));
hud = makeTextUI(20, 10);
configCamera();
initPhysics();
createFloor();
createSphere();
createCube();
setupKeys();
}
private void configCamera() {
float aspect = (float) cam.getWidth() / cam.getHeight();
cam.setFrustumPerspective(45, aspect, 0.01f, 1000f);
flyCam.setDragToRotate(true);
flyCam.setMoveSpeed(25f);
cam.setLocation(new Vector3f(32, 32, 32));
cam.lookAt(new Vector3f(0, 2, 0), Vector3f.UNIT_Y);
}
private void initPhysics() {
physics = new BulletAppState();
stateManager.attach(physics);
physics.setDebugEnabled(true);
PhysicsSpace pSpace = physics.getPhysicsSpace();
// MyContactManager manager = new MyContactManager(pSpace);
// manager.doProcessed = false;
// pSpace.setContactManager(manager);
// pSpace.addContactListener(new MyContactListener(pSpace));
pSpace.addContactListener(new MyContactListener(pSpace), false, false, true);
pSpace.addContactListener(new MyContactListener(pSpace), true, false, false);
}
private BitmapText makeTextUI(float xPos, float yPos) {
BitmapText bmp = new BitmapText(guiFont);
bmp.setColor(ColorRGBA.Red);
bmp.setSize(guiFont.getCharSet().getRenderedSize());
bmp.setLocalTranslation(xPos, settings.getHeight() - yPos, 0);
guiNode.attachChild(bmp);
return bmp;
}
private void createFloor() {
float boxSize = 140f;
Box box = new Box(boxSize, 0.5f, boxSize);
Geometry geo = new Geometry("Floor", box);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Green);
geo.setMaterial(mat);
rootNode.attachChild(geo);
addStaticRigidBody(geo);
}
private void createCube() {
Box box = new Box(4, 4, 4);
Geometry geo = new Geometry("Box", box);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Red);
mat.getAdditionalRenderState().setWireframe(true);
geo.setMaterial(mat);
rootNode.attachChild(geo);
GhostControl ghost = addGhostControl(geo);
geo.addControl(new AbstractControl() {
@Override
protected void controlUpdate(float tpf) {
for (PhysicsCollisionObject pco : ghost.getOverlappingObjects()) {
System.out.println("ghostOverlapping: " + pco.getUserObject());
}
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
});
geo.setLocalTranslation(new Vector3f(0, 20, 0));
//ghost.setPhysicsLocation(new Vector3f(0, 20, 0));
}
private void createSphere() {
Sphere sphere = new Sphere(32, 32, 4);
sphere.setTextureMode(Sphere.TextureMode.Projected);
Geometry geo = new Geometry("Ball", sphere);
MikktspaceTangentGenerator.generate(geo);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
geo.setMaterial(mat);
geo.setLocalTranslation(new Vector3f(0, 5, 0));
rootNode.attachChild(geo);
ball = addDynamicRigidBody(geo, 1f);
}
private GhostControl addGhostControl(Spatial sp) {
CollisionShape shape = CollisionShapeFactory.createBoxShape(sp);
GhostControl ghost = new GhostControl(shape);
sp.addControl(ghost);
physics.getPhysicsSpace().add(ghost);
return ghost;
}
private RigidBodyControl addStaticRigidBody(Spatial sp) {
CollisionShape shape = CollisionShapeFactory.createMeshShape(sp);
RigidBodyControl rb = new RigidBodyControl(shape, PhysicsBody.massForStatic);
sp.addControl(rb);
physics.getPhysicsSpace().add(rb);
return rb;
}
private RigidBodyControl addDynamicRigidBody(Spatial sp, float mass) {
CollisionShape shape = CollisionShapeFactory.createDynamicMeshShape(sp);
RigidBodyControl rb = new RigidBodyControl(shape, mass);
sp.addControl(rb);
physics.getPhysicsSpace().add(rb);
return rb;
}
@Override
public void simpleUpdate(float tpf) {
int m = physics.getPhysicsSpace().countManifolds();
hud.setText("countManifolds: " + m);
}
private void setupKeys() {
addMapping("JUMP", new KeyTrigger(KeyInput.KEY_SPACE));
}
public void addMapping(String bindingName, Trigger... triggers) {
inputManager.addMapping(bindingName, triggers);
inputManager.addListener(this, bindingName);
}
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("JUMP") && isPressed) {
ball.applyCentralImpulse(Vector3f.UNIT_Y.mult(10));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment