Objects building up (lowering FPS)

I do not understand why objects are building up in this code. I barely modified it, so I’m thinking perhaps that the problem was in the original code.

I modified the TestBrickTower.java in jme3test.bullet so that it would rapid-fire the bombs without having to click repeatedly (just click to turn on/off rapid-fire).

I modified BombControl.java so that the bombs don’t detonate for the first 3 seconds (just roll/bounce).

It seems like the objects build up when the bombs detonate; if you just shoot them all off the stage so they don’t collide at all, the objects don’t build up (are removed correctly).

Thanks for any help

TestBrickTower.java
[java]
/*

  • Copyright © 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;

/*

  • Copyright © 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.
    */

import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.font.BitmapText;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.scene.shape.Sphere.TextureMode;
import com.jme3.shadow.PssmShadowRenderer;
import com.jme3.shadow.PssmShadowRenderer.CompareMode;
import com.jme3.shadow.PssmShadowRenderer.FilterMode;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;

/**
*

  • @author double1984 (tower mod by atom)
    */
    public class TestBrickTower extends SimpleApplication {

    int bricksPerLayer = 8;
    int brickLayers = 30;

    static float brickWidth = .75f, brickHeight = .25f, brickDepth = .25f;
    float radius = 3f;
    float angle = 0;

    Material mat;
    Material mat2;
    Material mat3;
    PssmShadowRenderer bsr;
    private Sphere bullet;
    private Box brick;
    private SphereCollisionShape bulletCollisionShape;

    private BulletAppState bulletAppState;

    public static void main(String args[]) {
    TestBrickTower f = new TestBrickTower();
    f.start();
    }

    @Override
    public void simpleInitApp() {
    bulletAppState = new BulletAppState();
    bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
    // bulletAppState.setEnabled(false);
    stateManager.attach(bulletAppState);
    bullet = new Sphere(32, 32, 0.4f, true, false);
    bullet.setTextureMode(TextureMode.Projected);
    bulletCollisionShape = new SphereCollisionShape(0.4f);

     brick = new Box(Vector3f.ZERO, brickWidth, brickHeight, brickDepth);
     brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
     //bulletAppState.getPhysicsSpace().enableDebug(assetManager);
     initMaterial();
     initTower();
     initFloor();
     initCrossHairs();
     this.cam.setLocation(new Vector3f(0, 25f, 8f));
     cam.lookAt(Vector3f.ZERO, new Vector3f(0, 1, 0));
     cam.setFrustumFar(80);
     inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
     inputManager.addListener(actionListener, "shoot");
     rootNode.setShadowMode(ShadowMode.Off);
     bsr = new PssmShadowRenderer(assetManager, 1024, 2);
     bsr.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
     bsr.setLambda(0.55f);
     bsr.setShadowIntensity(0.6f);
     bsr.setCompareMode(CompareMode.Hardware);
     bsr.setFilterMode(FilterMode.PCF4);
     viewPort.addProcessor(bsr);
    

    }

    private PhysicsSpace getPhysicsSpace() {
    return bulletAppState.getPhysicsSpace();
    }
    boolean fireSwitch = false;
    private ActionListener actionListener = new ActionListener() {

     public void onAction(String name, boolean keyPressed, float tpf) {
         if (name.equals("shoot") && !keyPressed) {
             fireSwitch ^= true;
         }
     }
    

    };
    /* Use the main event loop to trigger repeating actions. */
    float fireTimer = 0f;
    @Override
    public void simpleUpdate(float tpf) {
    // make the player rotate:
    if (fireSwitch == true) {
    fireTimer += tpf;
    if (fireTimer > 0.1f) {
    fireTimer = 0;
    Geometry bulletg = new Geometry(“bullet”, bullet);
    bulletg.setMaterial(mat2);
    bulletg.setShadowMode(ShadowMode.CastAndReceive);
    bulletg.setLocalTranslation(cam.getLocation());
    RigidBodyControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1);
    // RigidBodyControl bulletNode = new RigidBodyControl(bulletCollisionShape, 1);
    bulletNode.setLinearVelocity(cam.getDirection().mult(10));
    bulletg.addControl(bulletNode);
    rootNode.attachChild(bulletg);
    getPhysicsSpace().add(bulletNode);
    }
    }
    }

    public void initTower() {
    double tempX = 0;
    double tempY = 0;
    double tempZ = 0;
    angle = 0f;
    for (int i = 0; i < brickLayers; i++){
    // Increment rows
    if(i!=0)
    tempY+=brickHeight*2;
    else
    tempY=brickHeight;
    // Alternate brick seams
    angle = 360.0f / bricksPerLayer * i/2f;
    for (int j = 0; j < bricksPerLayer; j++){
    tempZ = Math.cos(Math.toRadians(angle))*radius;
    tempX = Math.sin(Math.toRadians(angle))*radius;
    System.out.println(“x=”+((float)(tempX))+" y="+((float)(tempY))+" z="+(float)(tempZ));
    Vector3f vt = new Vector3f((float)(tempX), (float)(tempY), (float)(tempZ));
    // Add crenelation
    if (i==brickLayers-1){
    if (j%2 == 0){
    addBrick(vt);
    }
    }
    // Create main tower
    else {
    addBrick(vt);
    }
    angle += 360.0/bricksPerLayer;
    }
    }

    }

    public void initFloor() {
    Box floorBox = new Box(Vector3f.ZERO, 10f, 0.1f, 5f);
    floorBox.scaleTextureCoordinates(new Vector2f(3, 6));

     Geometry floor = new Geometry("floor", floorBox);
     floor.setMaterial(mat3);
     floor.setShadowMode(ShadowMode.Receive);
     floor.setLocalTranslation(0, 0, 0);
     floor.addControl(new RigidBodyControl(0));
     this.rootNode.attachChild(floor);
     this.getPhysicsSpace().add(floor);
    

    }

    public void initMaterial() {
    mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
    TextureKey key = new TextureKey(“Textures/Terrain/BrickWall/BrickWall.jpg”);
    key.setGenerateMips(true);
    Texture tex = assetManager.loadTexture(key);
    mat.setTexture(“ColorMap”, tex);

     mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
     TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG");
     key2.setGenerateMips(true);
     Texture tex2 = assetManager.loadTexture(key2);
     mat2.setTexture("ColorMap", tex2);
    
     mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
     TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg");
     key3.setGenerateMips(true);
     Texture tex3 = assetManager.loadTexture(key3);
     tex3.setWrap(WrapMode.Repeat);
     mat3.setTexture("ColorMap", tex3);
    

    }

    public void addBrick(Vector3f ori) {
    Geometry reBoxg = new Geometry(“brick”, brick);
    reBoxg.setMaterial(mat);
    reBoxg.setLocalTranslation(ori);
    reBoxg.rotate(0f, (float)Math.toRadians(angle) , 0f );
    reBoxg.addControl(new RigidBodyControl(1.5f));
    reBoxg.setShadowMode(ShadowMode.CastAndReceive);
    reBoxg.getControl(RigidBodyControl.class).setFriction(1.6f);
    this.rootNode.attachChild(reBoxg);
    this.getPhysicsSpace().add(reBoxg);
    }

    protected void initCrossHairs() {
    guiFont = assetManager.loadFont(“Interface/Fonts/Default.fnt”);
    BitmapText ch = new BitmapText(guiFont, false);
    ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
    ch.setText("+"); // crosshairs
    ch.setLocalTranslation( // center
    settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,
    settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
    guiNode.attachChild(ch);
    }
    }
    [/java]

BombControl.java
[java]
/*

  • Copyright © 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 mygame;

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(timer<3f){
    //Don’t do anything
    }
    else 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():wink: {
    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.”);
    }
    }
    [/java]

Then run TestBrickTower.java

For some reason, I cannot edit my initial post.

I accidentally copied the copy I had put into my own project.

Change package mygame; into package jme3test.bullet; in the BombControl.java

Sorry

EDIT: Don’t bother with replacing the BombControl.java code…the objects build up much faster if you do not replace it.