Need help with class structure/hierarchy

So at this point I have a working game, with a player, enemies, AI, networking, the works, but the code is just sloppy. I am a huge stickler for encapsulation and good object oriented design, so this problem has been bugging me for a while now. I’m not in too deep, as I “only” have around 1000 lines of code in my Main class (which extends simple application), but I am doing things in here that I really want to move out, I just don’t quite see the best way to go about it. For instance, I’ll post my main loop, which more of less takes care of two hardcoded enemies AI, as well as doing an on-death action (he drops a “power up”), AND applying falling damage to my character.



[java]

public void simpleUpdate(float tpf) {



progressbar.setProgress(player.getHealth());



halfSecond += tpf;

halfSecond2 += tpf;



if (fallSpeed < -44f && player.onGround()) {

player.setHealth(player.getHealth() - ((-fallSpeed) / 80f));

progressbar.setProgress(player.getHealth());

fallSpeed = 0.0f;

}

Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);

Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);

walkDirection.set(0, 0, 0);

enemyDirection.set(0, 0, 0);

enemyDirection2.set(0, 0, 0);



if (left) {

sendMessage(player.getPhysicsLocation().toString());

walkDirection.addLocal(camLeft.mult(player.getSpeed()).x, 0, camLeft.mult(player.getSpeed()).z);

}

if (right) {

sendMessage(player.getPhysicsLocation().toString());

walkDirection.addLocal(camLeft.negate().mult(player.getSpeed()).x, 0, camLeft.negate().mult(player.getSpeed()).z);

}

if (up) {

sendMessage(player.getPhysicsLocation().toString());

walkDirection.addLocal(camDir.mult(player.getSpeed()).x, 0, camDir.mult(player.getSpeed()).z);

}

if (down) {

sendMessage(player.getPhysicsLocation().toString());

walkDirection.addLocal(camDir.negate().mult(player.getSpeed()).x, 0, camDir.negate().mult(player.getSpeed()).z);

}

player.setWalkDirection(walkDirection);

cam.setLocation(player.getPhysicsLocation());

listener.setLocation(cam.getLocation());

listener.setRotation(cam.getRotation());

if (!player.onGround()) {

if (enemy.getHealth() > 0) {

enemy.jump();

}



if (fallSpeed > (player.getPhysicsLocation().y - prevPlayerPos) / tpf) {

fallSpeed = (player.getPhysicsLocation().y - prevPlayerPos) / tpf;

}

prevPlayerPos = player.getPhysicsLocation().y;

} else {

fallSpeed = 0.0f;

}



if (enemy.getHealth() > 0) {

// velocity

float dx = ((player.getPhysicsLocation().x) - enemy.getPhysicsLocation().x);

float dy = ((player.getPhysicsLocation().y) - enemy.getPhysicsLocation().y);

float dz = ((player.getPhysicsLocation().z) - enemy.getPhysicsLocation().z);

float hyp = (float) Math.sqrt(dx * dx + dy * dy + dz * dz);

dx /= hyp;

dz /= hyp;

dy /= hyp;

if (hyp > 20) {

enemyDirection.addLocal((new Vector3f(dx, dy, dz).divide(3)));



//enemyDirection.addLocal(enemy.getPhysicsLocation().addLocal(new Vector3f(dx, dy, dz).divide(3)));

}

enemy.setWalkDirection(enemyDirection);

enemy.setViewDirection(new Vector3f(dx, dy, dz));

if (halfSecond > .2) {

//enemyBulletControl(enemy.getPhysicsLocation(), enemy.getViewDirection());

halfSecond = 0;

}

} else {

if (enemy.isDead() == false) {

//initInfiniteAmmo(enemy.getPhysicsLocation().addLocal(2,10,0));

///initSpeedBoost(enemy.getPhysicsLocation().addLocal(4,10,0));

//initReverseGravity(enemy.getPhysicsLocation().addLocal(2,10,2));

initStatBoost(enemy.getPhysicsLocation().addLocal(2, 10, 4));



enemy.setDead(true);

}

enemy.setWalkDirection(enemyDirection);

final Quaternion PITCH090 = new Quaternion().fromAngleAxis(FastMath.PI / 2, new Vector3f(1, 0, 0));

enemy.setViewDirection(new Vector3f(0, enemy.getPhysicsLocation().y + 10, 0));



}



if (enemy2.getHealth() > 0) {

// velocity

float dx = ((player.getPhysicsLocation().x) - enemy2.getPhysicsLocation().x);

float dy = ((player.getPhysicsLocation().y) - enemy2.getPhysicsLocation().y);

float dz = ((player.getPhysicsLocation().z) - enemy2.getPhysicsLocation().z);



float hyp = (float) Math.sqrt(dx * dx + dy * dy + dz * dz);



dx /= hyp;

dz /= hyp;

dy /= hyp;



if (enemy2.onGround()) {

System.out.println(“ONGROUND” + enemy2.getPhysicsLocation().y);

enemy2.jump();



player.getPhysicsLocation().add(new Vector3f(0, 0, 0), jumpTo);

dirx = 2 * ((jumpTo.x) - enemy2.getPhysicsLocation().x);

//diry = ((jumpTo.y) - enemy2.getPhysicsLocation().y);

dirz = 2 * ((jumpTo.z) - enemy2.getPhysicsLocation().z);

hyp2 = (float) Math.sqrt(dirx * dirx + diry * diry + dirz * dirz);

dirx /= hyp2;

dirz /= hyp2;

//diry /= hyp2;

} else {



if (hyp2 > 20) {

enemyDirection2.addLocal((new Vector3f(dirx / 3f, 0, dirz / 3f)));

}

}

//enemyDirection.addLocal(enemy.getPhysicsLocation().addLocal(new Vector3f(dirx, diry, dirz).divide(3)));



enemy2.setPhysicsLocation(enemy2.getPhysicsLocation().add(enemyDirection2));

enemy2.setViewDirection(new Vector3f(dx, dy, dz));

if (halfSecond2 > .2) {

// enemyBulletControl(enemy2.getPhysicsLocation(), enemy2.getViewDirection());



halfSecond2 = 0;

}

} else {

if (enemy2.isDead() == false) {

//initInfiniteAmmo(enemy2.getPhysicsLocation().addLocal(2,10,0));

//initSpeedBoost(enemy2.getPhysicsLocation().addLocal(4,10,0));

//initStatBoost(enemy.getPhysicsLocation().addLocal(2,10,4));

initReverseGravity(enemy2.getPhysicsLocation().addLocal(2, 10, 2));

enemy2.setDead(true);

}

enemy2.setWalkDirection(enemyDirection2);

final Quaternion PITCH090 = new Quaternion().fromAngleAxis(FastMath.PI / 2, new Vector3f(1, 0, 0));

enemy2.setViewDirection(new Vector3f(0, enemy2.getPhysicsLocation().y + 10, 0));

}



}[/java]



So the dilemma. I tried moving the AI into the enemy class, which worked decently, but then I couldn’t do any on-death actions without explicitly doing them in the update statement, which was the original problem. The reason being I have to attach items to the rootnode, and this can’t be done statically. Also I have a few bullet control methods in my Main class, which I can’t move out because I have to attach geometries to the root node.



So I hope I made my dilemma clear, I just want more encapsulation without compromising the conciseness my Main class. If you have any tips at all, I will gladly take them. Thanks in advance.

Read the Documentation, especially “Best Practices” and “AppStates and Controls”.

1 Like

Don’t know how I missed this! 100% exactly what I’m looking for. Thanks a lot normen.