1 /* 2 * To change this template, choose Tools | Templates 3 * and open the template in the editor. 4 */ 5 package jme3test.bullet; 6 7 import com.jme3.asset.AssetManager; 8 import com.jme3.bullet.PhysicsSpace; 9 import com.jme3.bullet.PhysicsTickListener; 10 import com.jme3.bullet.collision.PhysicsCollisionEvent; 11 import com.jme3.bullet.collision.PhysicsCollisionListener; 12 import com.jme3.bullet.collision.PhysicsCollisionObject; 13 import com.jme3.bullet.collision.shapes.CollisionShape; 14 import com.jme3.bullet.collision.shapes.SphereCollisionShape; 15 import com.jme3.bullet.control.RigidBodyControl; 16 import com.jme3.bullet.objects.PhysicsGhostObject; 17 import com.jme3.bullet.objects.PhysicsRigidBody; 18 import com.jme3.effect.ParticleEmitter; 19 import com.jme3.effect.ParticleMesh.Type; 20 import com.jme3.effect.shapes.EmitterSphereShape; 21 import com.jme3.export.JmeExporter; 22 import com.jme3.export.JmeImporter; 23 import com.jme3.material.Material; 24 import com.jme3.math.ColorRGBA; 25 import com.jme3.math.Vector3f; 26 import java.io.IOException; 27 import java.util.Iterator; 28 29 /** 30 * 31 * @author normenhansen 32 */ 33 public class BombControl extends RigidBodyControl implements PhysicsCollisionListener, PhysicsTickListener { 34 35 private float explosionRadius = 10; 36 private PhysicsGhostObject ghostObject; 37 private Vector3f vector = new Vector3f(); 38 private Vector3f vector2 = new Vector3f(); 39 private float forceFactor = 1; 40 private ParticleEmitter effect; 41 private float fxTime = 0.5f; 42 private float maxTime = 4f; 43 private float curTime = -1.0f; 44 private float timer; 45 46 public BombControl(CollisionShape shape, float mass) { 47 super(shape, mass); 48 createGhostObject(); 49 } 50 51 public BombControl(AssetManager manager, CollisionShape shape, float mass) { 52 super(shape, mass); 53 createGhostObject(); 54 prepareEffect(manager); 55 } 56 57 public void setPhysicsSpace(PhysicsSpace space) { 58 super.setPhysicsSpace(space); 59 if (space != null) { 60 space.addCollisionListener(this); 61 } 62 } 63 64 private void prepareEffect(AssetManager assetManager) { 65 int COUNT_FACTOR = 1; 66 float COUNT_FACTOR_F = 1f; 67 effect = new ParticleEmitter("Flame", Type.Triangle, 32 * COUNT_FACTOR); 68 effect.setSelectRandomImage(true); 69 effect.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (float) (1f / COUNT_FACTOR_F))); 70 effect.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f)); 71 effect.setStartSize(1.3f); 72 effect.setEndSize(2f); 73 effect.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f)); 74 effect.setParticlesPerSec(0); 75 effect.setGravity(0, -5f, 0); 76 effect.setLowLife(.4f); 77 effect.setHighLife(.5f); 78 effect.setInitialVelocity(new Vector3f(0, 7, 0)); 79 effect.setVelocityVariation(1f); 80 effect.setImagesX(2); 81 effect.setImagesY(2); 82 Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); 83 mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png")); 84 effect.setMaterial(mat); 85 } 86 87 protected void createGhostObject() { 88 ghostObject = new PhysicsGhostObject(new SphereCollisionShape(explosionRadius)); 89 } 90 91 public void collision(PhysicsCollisionEvent event) { 92 if (space == null) { 93 return; 94 } 95 if (event.getObjectA() == this || event.getObjectB() == this) { 96 space.add(ghostObject); 97 ghostObject.setPhysicsLocation(getPhysicsLocation(vector)); 98 space.addTickListener(this); 99 if (effect != null && spatial.getParent() != null) { 100 curTime = 0; 101 effect.setLocalTranslation(spatial.getLocalTranslation()); 102 spatial.getParent().attachChild(effect); 103 effect.emitAllParticles(); 104 } 105 space.remove(this); 106 spatial.removeFromParent(); 107 } 108 } 109 110 public void prePhysicsTick(PhysicsSpace space, float f) { 111 space.removeCollisionListener(this); 112 } 113 114 public void physicsTick(PhysicsSpace space, float f) { 115 //get all overlapping objects and apply impulse to them 116 for (Iterator<PhysicsCollisionObject> it = ghostObject.getOverlappingObjects().iterator(); it.hasNext();) { 117 PhysicsCollisionObject physicsCollisionObject = it.next(); 118 if (physicsCollisionObject instanceof PhysicsRigidBody) { 119 PhysicsRigidBody rBody = (PhysicsRigidBody) physicsCollisionObject; 120 rBody.getPhysicsLocation(vector2); 121 vector2.subtractLocal(vector); 122 float force = explosionRadius - vector2.length(); 123 force *= forceFactor; 124 force = force > 0 ? force : 0; 125 vector2.normalizeLocal(); 126 vector2.multLocal(force); 127 ((PhysicsRigidBody) physicsCollisionObject).applyImpulse(vector2, Vector3f.ZERO); 128 } 129 } 130 space.removeTickListener(this); 131 space.remove(ghostObject); 132 } 133 134 @Override 135 public void update(float tpf) { 136 super.update(tpf); 137 if(enabled){ 138 timer+=tpf; 139 if(timer>maxTime){ 140 if(spatial.getParent()!=null){ 141 space.removeCollisionListener(this); 142 space.remove(this); 143 spatial.removeFromParent(); 144 } 145 } 146 } 147 if (enabled && curTime >= 0) { 148 curTime += tpf; 149 if (curTime > fxTime) { 150 curTime = -1; 151 effect.removeFromParent(); 152 } 153 } 154 } 155 156 /** 157 * @return the explosionRadius 158 */ 159 public float getExplosionRadius() { 160 return explosionRadius; 161 } 162 163 /** 164 * @param explosionRadius the explosionRadius to set 165 */ 166 public void setExplosionRadius(float explosionRadius) { 167 this.explosionRadius = explosionRadius; 168 createGhostObject(); 169 } 170 171 public float getForceFactor() { 172 return forceFactor; 173 } 174 175 public void setForceFactor(float forceFactor) { 176 this.forceFactor = forceFactor; 177 } 178 179 180 @Override 181 public void read(JmeImporter im) throws IOException { 182 throw new UnsupportedOperationException("Reading not supported."); 183 } 184 185 @Override 186 public void write(JmeExporter ex) throws IOException { 187 throw new UnsupportedOperationException("Saving not supported."); 188 } 189 } 190