/* * Copyright (c) 2009-2012 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'jMonkeyEngine' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package jme3test.bullet; import com.jme3.asset.AssetManager; import com.jme3.bullet.PhysicsSpace; import com.jme3.bullet.PhysicsTickListener; import com.jme3.bullet.collision.PhysicsCollisionEvent; import com.jme3.bullet.collision.PhysicsCollisionListener; import com.jme3.bullet.collision.PhysicsCollisionObject; import com.jme3.bullet.collision.shapes.CollisionShape; import com.jme3.bullet.collision.shapes.SphereCollisionShape; import com.jme3.bullet.control.RigidBodyControl; import com.jme3.bullet.objects.PhysicsGhostObject; import com.jme3.bullet.objects.PhysicsRigidBody; import com.jme3.effect.ParticleEmitter; import com.jme3.effect.ParticleMesh.Type; import com.jme3.effect.shapes.EmitterSphereShape; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import java.io.IOException; import java.util.Iterator; /** * * @author normenhansen */ public class BombControl extends RigidBodyControl implements PhysicsCollisionListener, PhysicsTickListener { private float explosionRadius = 10; private PhysicsGhostObject ghostObject; private Vector3f vector = new Vector3f(); private Vector3f vector2 = new Vector3f(); private float forceFactor = 1; private ParticleEmitter effect; private float fxTime = 0.5f; private float maxTime = 4f; private float curTime = -1.0f; private float timer; public BombControl(CollisionShape shape, float mass) { super(shape, mass); createGhostObject(); } public BombControl(AssetManager manager, CollisionShape shape, float mass) { super(shape, mass); createGhostObject(); prepareEffect(manager); } public void setPhysicsSpace(PhysicsSpace space) { super.setPhysicsSpace(space); if (space != null) { space.addCollisionListener(this); } } private void prepareEffect(AssetManager assetManager) { int COUNT_FACTOR = 1; float COUNT_FACTOR_F = 1f; effect = new ParticleEmitter("Flame", Type.Triangle, 32 * COUNT_FACTOR); effect.setSelectRandomImage(true); effect.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (float) (1f / COUNT_FACTOR_F))); effect.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f)); effect.setStartSize(1.3f); effect.setEndSize(2f); effect.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f)); effect.setParticlesPerSec(0); effect.setGravity(0, -5f, 0); effect.setLowLife(.4f); effect.setHighLife(.5f); effect.setInitialVelocity(new Vector3f(0, 7, 0)); effect.setVelocityVariation(1f); effect.setImagesX(2); effect.setImagesY(2); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png")); effect.setMaterial(mat); } protected void createGhostObject() { ghostObject = new PhysicsGhostObject(new SphereCollisionShape(explosionRadius)); } public void collision(PhysicsCollisionEvent event) { if (space == null) { return; } if (event.getObjectA() == this || event.getObjectB() == this) { space.add(ghostObject); ghostObject.setPhysicsLocation(getPhysicsLocation(vector)); space.addTickListener(this); if (effect != null && spatial.getParent() != null) { curTime = 0; effect.setLocalTranslation(spatial.getLocalTranslation()); spatial.getParent().attachChild(effect); effect.emitAllParticles(); } space.remove(this); spatial.removeFromParent(); } } public void prePhysicsTick(PhysicsSpace space, float f) { space.removeCollisionListener(this); } public void physicsTick(PhysicsSpace space, float f) { //get all overlapping objects and apply impulse to them for (Iterator<PhysicsCollisionObject> it = ghostObject.getOverlappingObjects().iterator(); it.hasNext();) { PhysicsCollisionObject physicsCollisionObject = it.next(); if (physicsCollisionObject instanceof PhysicsRigidBody) { PhysicsRigidBody rBody = (PhysicsRigidBody) physicsCollisionObject; rBody.getPhysicsLocation(vector2); vector2.subtractLocal(vector); float force = explosionRadius - vector2.length(); force *= forceFactor; force = force > 0 ? force : 0; vector2.normalizeLocal(); vector2.multLocal(force); ((PhysicsRigidBody) physicsCollisionObject).applyImpulse(vector2, Vector3f.ZERO); } } space.removeTickListener(this); space.remove(ghostObject); } @Override public void update(float tpf) { super.update(tpf); if(enabled){ timer+=tpf; if(timer>maxTime){ if(spatial.getParent()!=null){ space.removeCollisionListener(this); space.remove(this); spatial.removeFromParent(); } } } if (enabled && curTime >= 0) { curTime += tpf; if (curTime > fxTime) { curTime = -1; effect.removeFromParent(); } } } /** * @return the explosionRadius */ public float getExplosionRadius() { return explosionRadius; } /** * @param explosionRadius the explosionRadius to set */ public void setExplosionRadius(float explosionRadius) { this.explosionRadius = explosionRadius; createGhostObject(); } public float getForceFactor() { return forceFactor; } public void setForceFactor(float forceFactor) { this.forceFactor = forceFactor; } @Override public void read(JmeImporter im) throws IOException { throw new UnsupportedOperationException("Reading not supported."); } @Override public void write(JmeExporter ex) throws IOException { throw new UnsupportedOperationException("Saving not supported."); } }