Here are the 3 most relevant classes. I can add Player Class if you want. If you come across a method that you can’t find the declaration of, it was removed to conserve space and is not important.
Mastermind Class (extends Badguy)
public class Mastermind extends Badguy {
public static final String MASTERMIND_TYPE_ID = "mastermind";
private float spawnDelay = 0;
Mastermind() {
super();
//setSpeed(20);
//setWalkDirection(Vector3f.UNIT_Z.mult(getSpeed()));
}
@Override
protected void build(AssetManager manager) {
Spatial spat = manager.loadModel("Models/dudes/StickMan.j3o");
Material mat = new Material(manager, "Common/MatDefs/Light/Lighting.j3md");
mat.setBoolean("UseMaterialColors", true);
mat.setColor("Diffuse", ColorRGBA.Blue);
mat.setColor("Ambient", new ColorRGBA(0, 0, 0.3f, 1));
mat.setColor("Specular", ColorRGBA.Yellow);
spat.setMaterial(mat);
spat.setLocalScale(3);
spat.setLocalTranslation(0, -1, 0);
spat.setShadowMode(RenderQueue.ShadowMode.Cast);
bodyNode.attachChild(spat);
//walkDirection.set(Vector3f.UNIT_Z.mult(getSpeed()));
}
@Override
protected void setMove() {}
@Override
protected void rigging(Node collidables) {
//if (getWalkDirection().x == 0 && getWalkDirection().z == 0) setWalkDirection(Vector3f.UNIT_Z.mult(getSpeed()));
Vector3f n = new Vector3f().set(masterNode.getLocalTranslation());
CollisionResults results = new CollisionResults();
Ray ray = new Ray(n, getWalkDirection());
collidables.collideWith(ray, results);
if (results.size() > 0) {
Vector3f contact = results.getClosestCollision().getContactPoint();
if (contact.distance(n.add(getWalkDirection())) < getBound()) {
setWalkDirection(new Vector3f(
(float)ThreadLocalRandom.current().nextDouble(-10, 10), 0,
(float)ThreadLocalRandom.current().nextDouble(-10, 10)
).normalize().mult(getSpeed()));
}
}
}
@Override
protected boolean willMinion() {
// this method decides minion spawning (probably not important)
spawnDelay--;
boolean will = spawnDelay <= 0;
if (will) spawnDelay = 400;
return will;
}
@Override
protected String getTypeId() {
return MASTERMIND_TYPE_ID;
}
}
relevant parts of Badguy Class
public class Badguy {
public static final String BADGUY_TYPE_ID = "badguy";
private Vector3f pos;
private String id = "badguy", masterId = "master", bodyId = "body", exploId = "explosion";
final Node masterNode = new Node(), bodyNode = new Node(), exploNode = new Node();
private Player plr = null;
private Vector3f walkDirection = Vector3f.ZERO;
private float speed = 0.2f, bound = 3;
private float damage = 0.1f;
private boolean remove = false, exploded = false;
private ParticleEmitter debrisEffect;
Badguy() {}
Badguy(Vector3f pos) {
this.pos = pos;
}
Badguy(String id, Vector3f pos) {
this.id = id;
this.pos = pos;
}
protected void build(AssetManager manager) {
Spatial spat = manager.loadModel("Models/dudes/StickMan.j3o");
Material mat = new Material(manager, "Common/MatDefs/Light/Lighting.j3md");
mat.setBoolean("UseMaterialColors", true);
mat.setColor("Diffuse", ColorRGBA.Red);
mat.setColor("Ambient", new ColorRGBA(0.3f, 0, 0, 1));
mat.setColor("Specular", ColorRGBA.Orange);
spat.setMaterial(mat);
spat.setLocalScale(3);
spat.setLocalTranslation(0, -1, 0);
spat.setShadowMode(RenderQueue.ShadowMode.Cast);
bodyNode.attachChild(spat);
}
protected void initNodes() {
bodyId = id+" "+bodyId;
bodyNode.setName(bodyId);
masterNode.attachChild(bodyNode);
masterId = id+" "+masterId;
masterNode.setName(masterId);
masterNode.setLocalTranslation(pos);
}
protected void setMove() {
Vector3f n = new Vector3f().set(masterNode.getLocalTranslation());
walkDirection = plr.getPos().subtract(n).normalize().mult(speed).setY(0);
}
protected void debuncMove(Node collidables) {
// set rotation
Quaternion rotToPlr = new Quaternion();
rotToPlr.lookAt(walkDirection, Vector3f.UNIT_Y);
masterNode.setLocalRotation(rotToPlr);
// detect collision
Vector3f n = new Vector3f().set(masterNode.getLocalTranslation());
CollisionResults results = new CollisionResults();
Ray ray = new Ray(n, walkDirection);
collidables.collideWith(ray, results);
if (results.size() > 0) {
Vector3f contact = results.getClosestCollision().getContactPoint();
if (contact.distance(n.add(walkDirection)) < bound) walkDirection = Vector3f.ZERO;
}
}
protected void move() {
// move
masterNode.setLocalTranslation(masterNode.getLocalTranslation().add(walkDirection));
}
protected void rigging(Node collidables) {
// for special movement
}
protected boolean purge() {
return remove;
}
protected void setSpeed(float s) {
speed = s;
}
protected void setWalkDirection(Vector3f w) {
walkDirection.set(w);
}
protected Node getMasterNode() {
return masterNode;
}
protected float getSpeed() {
return speed;
}
protected Vector3f getWalkDirection() {
return walkDirection;
}
protected String getTypeId() {
return BADGUY_TYPE_ID;
}
}
relavent parts of GameState Class
public class GameState extends SceneAppState {
public static final String ENVIRO_NAME = "enviro", ENEMY_NODE_NAME = "enemy node";
private BulletAppState bulletAppState;
private Node guiNode;
private Camera cam;
private AssetManager assetManager;
private ViewPort viewPort;
private InputManager inputManager;
private Player player = new Player("player");
private final char BLOCK = '#';
private final char START = 'P';
private final char END = '@';
private final char WINDOW = '+';
private final char OVER_HEAD = '^';
private final char ENEMY = '!';
private final char NONE = '-';
int size = 20;
int mapSize = 25;
int paths = 20;
int pathLength = 20;
int startPosX = 0;
int startPosZ = 0;
Node world = new Node("world");
ArrayList<ArrayList> map = new ArrayList<>();
Node enviro = new Node(ENVIRO_NAME);
ArrayList<Badguy> enemyList = new ArrayList<>();
Node enemyNode = new Node(ENEMY_NODE_NAME);
int enemyId = 0;
ArrayList<Goal> goalList = new ArrayList<>();
Node goalNode = new Node("goals");
private static final String PLAYING = "playing", PAUSED = "paused";
AudioNode background;
GameState(String id, Node root) {
super(id, root);
}
@Override
protected void initialize(Application app) {
bulletAppState = app.getStateManager().getState(BulletAppState.class);
cam = app.getCamera();
assetManager = app.getAssetManager();
viewPort = app.getViewPort();
inputManager = app.getInputManager();
//masterNode = ((SimpleApplication)app).getRootNode();
guiNode = ((SimpleApplication)app).getGuiNode();
//bulletAppState.setDebugEnabled(true);
viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
//flyCam.setMoveSpeed(100);
setUpSky();
setUpLight();
//reset();
//initMap();
playBackgroundMusic("Sounds/DST-RailJet-LongSeamlessLoop.ogg");
}
@Override
protected void cleanup(Application app) {
clean();
}
@Override
protected void onEnable() {
init();
//background.play();
}
@Override
protected void onDisable() {
clean();
//background.pause();
}
@Override
public void update(float tpf) {
if (isEnabled()) {
player.update(tpf);
player.setMove(cam);
player.detectCollision(enviro);
player.move(cam);
player.shoot(cam, world);
player.aim();
player.detectEnemy(enemyList);
player.detectGoal(goalList);
player.displayDashboard(assetManager, guiNode);
player.pause();
if (player.getPause()) setEnabled(false);
ArrayList<Badguy> removables = new ArrayList<>(), addables = new ArrayList<>();
for (Badguy i : enemyList) {
// movement
i.setMove();
i.rigging(enviro);
i.debuncMove(enviro);
i.move();
// special
if (i.willMinion()) {
Badguy b = i.minion();
b.setPos(i.getMasterNode().getLocalTranslation());
//b.setTarget(player);
addables.add(b);
}
// death anim
i.doExplosion(assetManager);
i.cleanExplosion();
if (i.purge()) removables.add(i);
}
for (Badguy i : removables) {
enemyList.remove(i);
enemyNode.detachChildNamed(i.getMasterId());
}
for (Badguy i : addables) spawnEnemy(i);
if (isComplete()) reset();
}
}
private void initMap() {
setMapData();
// maze blocks
for (int i = 0; i < map.size(); i++) {
ArrayList<Character> row = map.get(i);
for (int j = 0; j < row.size(); j++) {
switch (row.get(j)) {
case BLOCK:
makeBlock(j*size, i*size, 0);
break;
case START:
startPosX = j*size;
startPosZ = i*size;
//makeOverHead(j*size, i*size);
break;
case END:
if (Maze.GAME_TYPE.equals(Maze.TYPE_GET_END)) makeEnd(j*size, i*size);
else {
Mastermind mind = new Mastermind();
mind.setPos(new Vector3f(j*size, 0, i*size));
//mind.setTarget(player);
spawnEnemy(mind);
}
break;
case WINDOW:
makeBlock(j*size, i*size, 0);
break;
case OVER_HEAD:
//makeOverHead(j*size, i*size);
break;
case ENEMY:
Badguy[] enemyTypes = createEnemyArray();
int type = ThreadLocalRandom.current().nextInt(enemyTypes.length);
Badguy enemy = enemyTypes[type];
enemy.setPos(new Vector3f(j*size, 0, i*size));
//enemy.setTarget(player);
spawnEnemy(enemy);
break;
}
}
}
// border blocks
for (int i = 0; i < map.get(0).size(); i++) makeBlock(i*size, 0, 0);
for (int i = 0; i < map.get(0).size(); i++) makeBlock(i*size, map.size()*size, 0);
for (int i = 0; i < map.size(); i++) makeBlock(0, i*size, 0);
for (int i = 0; i < map.size(); i++) makeBlock(map.get(0).size()*size, i*size, 0);
// floor
Box b = new Box(map.get(0).size()*size/2, 5, map.size()*size/2);
b.scaleTextureCoordinates(new Vector2f(100, 100));
Geometry g = new Geometry("BoxFloor", b);
g.setLocalTranslation(map.get(0).size()*size/2, -5-5, map.size()*size/2);
Material m = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
Texture t = assetManager.loadTexture("Textures/metal_floor.jpg");
t.setWrap(Texture.WrapMode.Repeat);
m.setTexture("DiffuseMap", t);
/*m.setBoolean("UseMaterialColors", true);
m.setColor("Ambient", ColorRGBA.Gray);
m.setColor("Diffuse", ColorRGBA.Orange);*/
g.setMaterial(m);
g.setShadowMode(RenderQueue.ShadowMode.Receive);
enviro.attachChild(g);
world.attachChild(enviro);
world.attachChild(enemyNode);
world.attachChild(goalNode);
masterNode.attachChild(world);
player.build(assetManager);
player.initKeys(inputManager);
player.setPos(new Vector3f(startPosX, 0, startPosZ));
masterNode.attachChild(player.getNode());
//bulletAppState.getPhysicsSpace().add(player.getPhys());
}
private void spawnEnemy(Badguy b) {
b.setId("enemy#"+enemyId);
enemyId++;
enemyList.add(b);
enemyNode.attachChild(b.getMasterNode());
b.build(assetManager);
b.initNodes();
b.setTarget(player);
}
private boolean isComplete() {
boolean complete = true;
if (Maze.GAME_TYPE.equals(Maze.TYPE_SHOOT_MASTERS)) {
if (!player.getStatus().equals(Player.DEAD)) for (Badguy i : enemyList) {
if (i.getTypeId().equals(Mastermind.MASTERMIND_TYPE_ID)) {
complete = false;
break;
}
}
}
else if (!player.getStatus().equals(Player.DEAD) && !player.getStatus().equals(Player.VICTOR)) {
complete = false;
}
return complete;
}
private void reset() {
clean();
init();
}
private void clean() {
masterNode.detachAllChildren();
guiNode.detachAllChildren();
world.detachAllChildren();
enviro.detachAllChildren();
enemyNode.detachAllChildren();
goalNode.detachAllChildren();
map.clear();
enemyList.clear();
goalList.clear();
enemyId = 0;
}
private void init() {
player = new Player("player");
mapSize = ThreadLocalRandom.current().nextInt(15, 30);
paths = ThreadLocalRandom.current().nextInt(2, mapSize);
setUpSky();
initMap();
}
public static Badguy[] createEnemyArray() {
Badguy[] list = {
new Badguy(),
new Badbot(),
new Badcopter(),
};
return list;
}
}