Bare-bones shooting framework

I finally coded a bulletproof framework for shooting things. It’s basically the HelloPicking tutorial, except instead of just printing the name, it runs a damage method on the first thing you hit without searching through the array. Also, the dead things are actually removed properly and don’t exist in the physics space. This is only an accomplishment if you’re as stupid as me, but I thought I would share it because it could be a helpful start for people to make their own games.



What the program does isn’t that impressive. Right-click to spawn boxes and left-click to shoot them. Wow!



Edit: see below for the better way to do this.



[java]import java.util.ArrayList;

import com.jme3.app.SimpleApplication;

import com.jme3.bullet.BulletAppState;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.collision.CollisionResults;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.MouseButtonTrigger;

import com.jme3.light.PointLight;

import com.jme3.material.Material;

import com.jme3.math.Ray;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;

import com.jme3.util.TangentBinormalGenerator;

public class TempStage extends SimpleApplication

{

private BulletAppState bulletAppState;

private PointLight light = new PointLight();

private ArrayList<BoxGuy> list = new ArrayList<BoxGuy>();

private boolean shooting, spawning;

public static void main(String args[])

{

TempStage stage = new TempStage();

stage.start();

}

public void simpleInitApp()

{

bulletAppState = new BulletAppState();

stateManager.attach(bulletAppState);

rootNode.addLight(light);

flyCam.setMoveSpeed(10);

Material monkey = new Material(getAssetManager(), “Common/MatDefs/Light/Lighting.j3md”);

monkey.setTexture(“DiffuseMap”, getAssetManager().loadTexture(“Interface/Logo/Monkey.jpg”));

Box box = new Box(Vector3f.ZERO, 15, 1, 15);

Geometry floor = new Geometry(“floor”, box);

floor.setMaterial(monkey);

TangentBinormalGenerator.generate(floor);

floor.setLocalTranslation(0, -2.5f, 0);

getRootNode().attachChild(floor);

RigidBodyControl floor_control = new RigidBodyControl(0);

floor.addControl(floor_control);

bulletAppState.getPhysicsSpace().add(floor_control);

getInputManager().addMapping(“shoot”, new MouseButtonTrigger(0));

getInputManager().addListener(actionListener, “shoot”);

getInputManager().addMapping(“spawn”, new MouseButtonTrigger(1));

getInputManager().addListener(actionListener, “spawn”);

for (int i = 0; i < 5; i ++)

{

list.add(new BoxGuy(this, list.size()));

}

}

private ActionListener actionListener = new ActionListener()

{

public void onAction(String name, boolean keyPressed, float tpf)

{

if (name.equals(“shoot”))

shooting = keyPressed;

if (name.equals(“spawn”) && keyPressed)

spawning = true;

}

};

public void simpleUpdate(float tpf)

{

light.setPosition(cam.getLocation());

for(BoxGuy b : list)

{

b.simpleUpdate(tpf);

}

if (shooting)

{

CollisionResults results = new CollisionResults();

Ray ray = new Ray(getCamera().getLocation(), getCamera().getDirection());

getRootNode().collideWith(ray, results);

// for (int i = 0; i < results.size(); i++)

int i = 0;

{

try

{

System.out.println(Integer.parseInt(results.getCollision(i).getGeometry().getName()));

list.get(Integer.parseInt(results.getCollision(i).getGeometry().getName())).hurt();

}

catch(Exception e)

{

System.out.println("You can’t shoot this. " + e.getMessage());

}

}

}

if (spawning)

{

list.add(new BoxGuy(this, list.size()));

spawning = false;

}

}

public BulletAppState getBulletAppState()

{

return bulletAppState;

}

}[/java]

[java]import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.material.Material;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;

import com.jme3.util.TangentBinormalGenerator;

public class BoxGuy

{

TempStage stage;

Geometry guy;

RigidBodyControl guy_control;

int health = 100;

public BoxGuy(TempStage s, int i)

{

stage = s;

Material monkey = new Material(s.getAssetManager(), “Common/MatDefs/Light/Lighting.j3md”);

monkey.setTexture(“DiffuseMap”, s.getAssetManager().loadTexture(“Interface/Logo/Monkey.jpg”));

Box box = new Box(Vector3f.ZERO, 2, 2, 2);

guy = new Geometry(Integer.toString(i), box);

guy.setMaterial(monkey);

TangentBinormalGenerator.generate(guy);

guy.setLocalTranslation((float)(Math.random() * 20) - 10, 7, (float)(Math.random() * 20) - 10);

stage.getRootNode().attachChild(guy);

guy_control = new RigidBodyControl(10);

guy.addControl(guy_control);

stage.getBulletAppState().getPhysicsSpace().add(guy_control);

}

public void simpleUpdate(float tpf)

{

}

public void hurt()

{

guy.setLocalScale((float)Math.random() * .25f + .75f);

health --;

if (health < 1)

{

guy.removeFromParent();

stage.getBulletAppState().getPhysicsSpace().remove(guy_control);

}

}

public int getId()

{

return Integer.parseInt(guy.getName());

}

}[/java]

1 Like

very nice, looks really nice when you pull away and see the bottom Jmonkey image and boxs falling on it,

If I could make a suggestion…



This might be better done with a custom Control. You can remove some code if you go with this approach and potentially refactor into something much simpler if you keep going.



Make the logic for the hit stuff a control and attach it to your box guy’s geometry. Then when you detect a hit just grab the control from your hit geometry and if not-null call hurt().



With some further rearranging you might be able to move much of the box guy setup into a control, too… and get rid of the manual calls to simpleUpdate() since controls will already get that call. But the above suggestion would at least keep you from having to keep a list and search it just to do hit processing.



Edit: P.S.: if you want to go the extra step after you’ve gotten some ‘control’ experience, I can explain further.

Changes I made so far using controls:

-results.getCollision(i).getGeometry().getControl(MyControl.class).hurt(value); instead or parseInt() stuff (I KNEW I was doing it wrong!)

-name for mesh doesn’t matter

-way of storing stuff doesn’t matter


you might be able to move much of the box guy setup into a control, too


By this, do you mean I could have a control that applies the material to the Geometry? It seems like it would be less useful when everything isn't monkey colored. Thanks for the help.

Ultra simple control:

[java]import com.jme3.export.Savable;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;

public class MyControl extends AbstractControl implements Savable, Cloneable
{
BoxGuy thing;

public MyControl(BoxGuy t)
{
thing = t;
}

public Control cloneForSpatial(Spatial arg0)
{
return null;
}

protected void controlRender(RenderManager arg0, ViewPort arg1) {}

public void hurt()
{
thing.hurt();
}

@Override
protected void controlUpdate(float arg0) {}
}[/java]
kidneytrader said:
By this, do you mean I could have a control that applies the material to the Geometry? It seems like it would be less useful when everything isn't monkey colored. Thanks for the help.


Sorry... it's been long enough that I don't even remember anymore. :) Looks like you are on the right path, though.