1/*
2 * To change this template, choose Tools | Templates
3 * and open the template in the editor.
4 */
5package jme3test.bullet;
6
7import com.jme3.asset.AssetManager;
8import com.jme3.bullet.PhysicsSpace;
9import com.jme3.bullet.PhysicsTickListener;
10import com.jme3.bullet.collision.PhysicsCollisionEvent;
11import com.jme3.bullet.collision.PhysicsCollisionListener;
12import com.jme3.bullet.collision.PhysicsCollisionObject;
13import com.jme3.bullet.collision.shapes.CollisionShape;
14import com.jme3.bullet.collision.shapes.SphereCollisionShape;
15import com.jme3.bullet.control.RigidBodyControl;
16import com.jme3.bullet.objects.PhysicsGhostObject;
17import com.jme3.bullet.objects.PhysicsRigidBody;
18import com.jme3.effect.ParticleEmitter;
19import com.jme3.effect.ParticleMesh.Type;
20import com.jme3.effect.shapes.EmitterSphereShape;
21import com.jme3.export.JmeExporter;
22import com.jme3.export.JmeImporter;
23import com.jme3.material.Material;
24import com.jme3.math.ColorRGBA;
25import com.jme3.math.Vector3f;
26import java.io.IOException;
27import java.util.Iterator;
28
29/**
30 *
31 * @author normenhansen
32 */
33public 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