Spatial or 3D models disappearing and reappering

Hi all! Wazzup. It has been a while since I encountered a problem. I will try my best to describe the problem. It will be best if the video has been watched first then the problem will be understood clearly. I have these NPC cubes that roam around the world. They have their own AI. When I place a Lumberjack Camp the cubes goes there to check it out. Afterwards only three cubes are allowed to take up the job profession as being Lumberjacks. Once they become Lumberjack they set out to find trees to cut.

Here is where the problem starts, when they become lumberjacks and start to move the cubes disappear and reappear. When the player gets close to the cube or sees it from a certain angle the cube will either disappear or reappear. So I went and started to check what was wrong. I reduced the number of AI cubes to 5 (before it was 10). After that there was no problem at all, no 3D model disappearing or reappearing. The moment I increase the AI cubes above 5 then it starts again. This only happens to the cubes and nothing else. I also have other 3D models in the game world such as ground, quest npc, enemy npc(which also has AI), trees and stones. So I am not sure what is causing this and my FPS is 350 - 450.

K Out!

[video]http://youtu.be/Dgd2Bna5tNw[/video]

How are you positioning the cubes?

Using charactercontrol to position them.

I made a node called charNode and added the cube in that node. Then I added a characterControl to charNode.Control(). Afterwards I use the characterControl to move the cube.

Well, from what I can see, your code looks fine.

Then what could be the problem? :-?

I was conducting an experiment to understand the problem better but having load shedding now so must wait for an hour and half to do it -.- .

I did see others with similar or close problems but usually they are using custom mesh like here. After going through that topic I used updateModelBound() but still that problem remains. (To be more clear I called updateModelBound() once after creating the model spatial)

@kamran said: Then what could be the problem? :-?

I was conducting an experiment to understand the problem better but having load shedding now so must wait for an hour and half to do it -.- .

I did see others with similar or close problems but usually they are using custom mesh like here. After going through that topic I used updateModelBound() but still that problem remains. (To be more clear I called updateModelBound() once after creating the model spatial)

I was being silly… you haven’t posted any code so I couldn’t possibly know if it is correct or not. So from here it looks fine.

1 Like

lol ^^

<cite>@kamran said:</cite> Using charactercontrol to position them.

U mean using setWalkdirection on them right? Turn physics debug on, and see if there’s anything obvious. Have you tried the bettercharactercontroller? check if there’s any improvement. It will a least help narrow down the problem. Can’t say I’ve experienced this, but I’ve only ever had 1 main charactercontrol.

@wezrule: Yes I mean using setWalkDirection :slight_smile: . I did turn the physics debug on and the CharacterControl also just disappear and reappear. No I have not try the bettercharactercontroller yet but will try it now (Once the electricity is back -.- , sending posts from my laptop). Is the new charactercontroller called bettercharactercontroller? or something else?(Will google this till get your reply :google: ) Since you mentioned you only ever had 1 main charactercontrol, then does having multiple characterControl cause problem? I used the character control because for me it seems easy to move the NPC cubes, just point them to a Vector location and then they just move there smoothly. :slight_smile:

Ahhh touche @pspeed and here I thought what a good job I did XD . Any way here is the classes and codes for the cube. I am really sorry for so many classes but that’s is the only way I think I can do make the codes much more understandable. Main.java class can be ignored since it only calls for setup but if you want to check it I still provided it. If there are any problems then I would assume it to be in class NPCGenerator.java, TownPeople.java and maybe BasicCharacter.java(though this class only sets up model, node, position and characterControl) .

Ok here is the code(Posting code and classes related to the cubes):

Main.java (This is where every setup is called especially the generators)

[java]

package Main;

import Character.BasicCharacter;
import Character.TownPeople;
import Character.Player;
import Generator.EnemyGenerator;
import Generator.NPCGenerator;
import Generator.QuestGenerator;
import Generator.StoneGenerator;
import Generator.StructureGenerator;
import Generator.TreeGenerator;
import Object.Ground;
import Object.TV;
import Obstacle.Inn;
import Obstacle.LumberCamp;
import Obstacle.Tree;
import Other.Effect;
import Other.Map;
import Other.PlaneConvertion;
import Other.QuestLog;
import Other.Resource;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.input.ChaseCamera;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture.MagFilter;
import com.jme3.texture.Texture.MinFilter;
import com.jme3.texture.Texture2D;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.elements.render.TextRenderer;

/**

  • test

  • @author kamran
    */
    public class Main extends SimpleApplication {

    Ground ground, townGround;
    Player player;
    static TreeGenerator treeGenerator;
    static StoneGenerator stoneGenerator;
    static StructureGenerator structureGenerator;
    static NPCGenerator npcGenerator;
    static QuestGenerator questGenerator;
    static EnemyGenerator enemyGenerator;
    static Resource res;
    static QuestLog questLog;
    Map map;
    PlaneConvertion planeConvertion;
    TV tv;
    Effect effect;

    public Nifty nifty, niftyMesh;
    public static String state = “None”;
    public ViewPort viewPortMesh;

    private BulletAppState bulletAppState;
    private AmbientLight al;
    private DirectionalLight dl;
    private ChaseCamera cc;
    private int loadValue = 0, barWidth = 0, loadOffset = 0;

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

    @Override
    public void simpleInitApp() {
    viewPort.setBackgroundColor(new ColorRGBA(0.7f,0.8f,1f,1f));
    flyCam.setMoveSpeed(10);
    // setDisplayFps(false);
    // setDisplayStatView(false);
    inputManager.deleteMapping( SimpleApplication.INPUT_MAPPING_EXIT );
    setupLight();
    // setupMap();
    loadGUI();
    setupAvatar();
    // setupQuestLog();
    // setupPlayer();
    // setupResource();
    // setupGround();
    // setupCollision();
    // setupTreeGenerator();
    // setupStoneGenerator();
    // setupStructureGenerator();
    // setupNPCGenerator();
    // setupQuestGenerator();
    // setupEnemyGenerator();
    // setupPlaneConvertion();
    // setupCamera();
    }

    //////////////////////Generators/////////////////////
    private void setupTreeGenerator(){
    treeGenerator = new TreeGenerator(assetManager, bulletAppState, res);

     rootNode.attachChild(treeGenerator.rootNode);
    

    }

    private void setupStoneGenerator(){
    stoneGenerator = new StoneGenerator(assetManager, bulletAppState, res);

     rootNode.attachChild(stoneGenerator.rootNode);
    

    }

    private void setupStructureGenerator(){
    structureGenerator = new StructureGenerator(assetManager, bulletAppState,
    res);
    rootNode.attachChild(structureGenerator.rootNode);
    }

    private void setupNPCGenerator(){
    npcGenerator = new NPCGenerator(assetManager, bulletAppState,
    structureGenerator, treeGenerator,
    stoneGenerator,
    player,
    map,
    res);
    rootNode.attachChild(npcGenerator.rootNode);
    }

    private void setupQuestGenerator(){
    questGenerator = new QuestGenerator(assetManager, bulletAppState, nifty,
    questLog, res);
    rootNode.attachChild(questGenerator.rootNode);
    }

    private void setupEnemyGenerator(){
    enemyGenerator = new EnemyGenerator(assetManager, bulletAppState, player,
    npcGenerator);
    rootNode.attachChild(enemyGenerator.rootNode);
    }
    ////////////////////////Screens//////////////////////
    public void loadGUI(){
    flyCam.setDragToRotate(true);

     NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager,
                                                        inputManager, 
                                                        audioRenderer, 
                                                        viewPort);
     nifty = niftyDisplay.getNifty();
     nifty.fromXml("Interface/GameGUI.xml", "mainmenu");
     guiViewPort.addProcessor(niftyDisplay);
    

    }

    public void loadInternalScreen(String newScreen){
    System.out.println(“Before Internal Screen”);
    player.enableInput = true;
    cc.setDragToRotate(false);
    nifty.gotoScreen(newScreen);
    System.out.println(“In Internal Screen”);
    }

    ///////////////////////Nifty Methods/////////////////
    public void placeStructure(String type){

// if(type.equals(“Inn”)){
// structureGenerator.loadTempModel(“Inn”);
// }
structureGenerator.loadTempModel(type);
player.buildMode = true;
// inputManager.setCursorVisible(false);
nifty.gotoScreen(“blank”);
player.structure = true;
}

public void startGame(){
    state = "Load";
}

public void changeToHud(){
    player.changeToHud = true;
}

public void checkLog(){
    int id = Integer.parseInt(getElement("textQuestId").getRenderer(TextRenderer.class).getOriginalText());
    if(!questLog.isActive(id)){
        questLog.makeActive(id);
    }
    questGenerator.setupCondition(id);
    changeToHud();
}
//////////////////////////END////////////////////////

private void setupAvatar(){

// tv = new TV(assetManager, new Vector3f(1.5f, -1, 6), “TV”, 1.52f);
tv = new TV(assetManager, new Vector3f(0, 0, 0), “TV”, -0.52f);
tv.rootNode.setLocalTranslation(new Vector3f(1.5f, -1, 6));
// rootNode.attachChild(tv.rootNode);

    viewPortMesh = renderManager.createPreView("NiftyView", new Camera(1024, 768));
    viewPortMesh.setClearFlags(true, true, true);
    NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager,
                                                      inputManager,
                                                      audioRenderer,
                                                      viewPortMesh);
    niftyMesh = niftyDisplay.getNifty();
    niftyMesh.fromXml("Interface/ProfileInfo.xml", "profile");
    viewPortMesh.addProcessor(niftyDisplay);

    Texture2D depthTex = new Texture2D(1024, 768, Format.Depth);
    FrameBuffer fb = new FrameBuffer(1024, 768, 1);
    fb.setDepthTexture(depthTex);

    Texture2D tex = new Texture2D(1024, 768, Format.RGBA8);
    tex.setMinFilter(MinFilter.Trilinear);
    tex.setMagFilter(MagFilter.Bilinear);

    fb.setColorTexture(tex);
    viewPortMesh.setClearFlags(true, true, true);
    viewPortMesh.setOutputFrameBuffer(fb);

    tv.matScreen.setTexture("ColorMap", tex);
    rootNode.attachChild(tv.rootNode);

// Box b = new Box(new Vector3f(1, -0.04f, 6.045f), 0.95f, 0.95f, 0.01f);
// Geometry geom = new Geometry(“Box”, b);
// Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
// mat.setTexture(“ColorMap”, tex);
// geom.setMaterial(mat);
// geom.rotate(0, -0.52f, 0);
// rootNode.attachChild(geom);

}

private void initGame(){
    flyCam.setDragToRotate(false);
    
    setupLight();
    setupMap();
    setupQuestLog();
    setupPlayer();
    setupResource();
    setupGround();
    setupCollision();
    setupTreeGenerator();
    setupStoneGenerator();
    setupStructureGenerator();
    setupNPCGenerator();
    setupQuestGenerator();
    setupEnemyGenerator();
    setupPlaneConvertion();
    setupCamera();
    
    state = "Play";
    nifty.gotoScreen("hud");
}

private void setupQuestLog(){
    questLog = new QuestLog();
}

private void setupResource(){
    res = new Resource(nifty, player);
}

private void setupPlaneConvertion(){
    planeConvertion = new PlaneConvertion(inputManager);
}

private void setupCamera(){
    cc = new ChaseCamera(cam, player.model, inputManager);
    cc.setDragToRotate(false);
    cc.setDefaultDistance(3);
    cc.setMinDistance(3);
    cc.setMaxDistance(4);
    cc.setMinVerticalRotation(0.523f);
    cc.setMaxVerticalRotation(0.785f);
}

private void setupMap(){
    map = new Map();
}

private void setupPlayer(){
    player = new Player(inputManager ,assetManager, "Player", 
            new Vector3f(2, 3, 0), 0, nifty);
    rootNode.attachChild(player.rootNode);
}

private void setupGround(){
    ground = new Ground(assetManager, Vector3f.ZERO, "Ground");
    townGround = new Ground(assetManager, new Vector3f(0, 0.01f, 0), "TownGround");
    rootNode.attachChild(ground.rootNode);
    rootNode.attachChild(townGround.rootNode);
}

private void setupCollision(){
    bulletAppState = new BulletAppState();
    stateManager.attach(bulletAppState);

// bulletAppState.getPhysicsSpace().enableDebug(assetManager); //<-----for debugging only
bulletAppState.getPhysicsSpace().add(ground.rigid);
bulletAppState.getPhysicsSpace().add(townGround.rigid);
bulletAppState.getPhysicsSpace().add(player.control);

    ///////Temp Colision for testing/////
}

private void setupLight(){
    al = new AmbientLight();
    al.setColor(ColorRGBA.White.mult(1.3f));
    rootNode.addLight(al);

    dl = new DirectionalLight();
    dl.setColor(ColorRGBA.White);
    dl.setDirection(new Vector3f(2.8f,-2.8f,-2.8f).normalizeLocal());
    rootNode.addLight(dl);

}

public Element getElement(final String id)
{
    return nifty.getCurrentScreen().findElementByName(id);
}

public void exitNow(){

// stop();
System.exit(0);
}

@Override
public void simpleUpdate(float tpf) {
    if(state.equals("Play")){
        UpdatePlayer();
        UpdateResource();
        UpdateNPCGenerator();
        UpdateQuestGenerator();
        UpdateEnemyGenerator();
        UpdateTreeGeneratro();
        UpdateStoneGenerator();
        UpdateStructureGenerator();

// effect.Update(); //<---------------------Test Effects
}else{
UpdateLoadMenu();
}

// if(state.equals(“Init”)){
// state = “None”;
// getElement(“barGlow”).setWidth((int)1);
// loadAmount = 1;
// initGame();
// }

    if(state.equals("Load")){
        nifty.gotoScreen("load");
        flyCam.setDragToRotate(false);
        state = "SetupMap";
        barWidth = getElement("barGlow").getWidth();
        loadOffset = barWidth / 14;
        getElement("barGlow").setWidth(loadOffset);
        rootNode.detachChild(tv.rootNode);
        viewPortMesh = null;
        niftyMesh.exit();
        niftyMesh = null;
    }
}

// setupLight();
// setupMap();
// setupQuestLog();
// setupPlayer();
// setupResource();
// setupGround();
// setupCollision();
// setupTreeGenerator();
// setupStoneGenerator();
// setupStructureGenerator();
// setupNPCGenerator();
// setupQuestGenerator();
// setupEnemyGenerator();
// setupPlaneConvertion();
// setupCamera();

private void UpdateLoadMenu(){
    if(state.equals("SetupMap")){
        setupMap();
        state = "SetupQuestLog";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupQuestLog")){
        setupQuestLog();
        state = "SetupPlayer";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupPlayer")){
        setupPlayer();
        state = "SetupResource";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupResource")){
        setupResource();
        state = "SetupGround";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupGround")){
        setupGround();
        state = "SetupCollision";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupCollision")){
        setupCollision();
        state = "SetupTreeGenerator";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupTreeGenerator")){
        setupTreeGenerator();
        state = "SetupStoneGenerator";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupStoneGenerator")){
        setupStoneGenerator();
        state = "SetupStructureGenerator";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupStructureGenerator")){
        setupStructureGenerator();
        state = "SetupNPCGenerator";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupNPCGenerator")){
        setupNPCGenerator();
        state = "SetupQuestGenerator";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupQuestGenerator")){
        setupQuestGenerator();
        state = "SetupEnemyGenerator";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupEnemyGenerator")){
        setupEnemyGenerator();
        state = "SetupPlaneConvertion";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(loadValue);
    }else if(state.equals("SetupPlaneConvertion")){
        setupPlaneConvertion();
        state = "SetupCamera";
        loadValue += loadOffset;
        getElement("barGlow").setWidth(barWidth);
    }else if(state.equals("SetupCamera")){
        setupCamera();
        state = "Play";
        nifty.gotoScreen("hud");
        loadValue = 0;

// effect = new Effect(assetManager, new Vector3f(0, 0.5f, 0));
// effect.setupCharge();
// rootNode.attachChild(effect.rootNode);
}
}

private void UpdateStructureGenerator(){
    structureGenerator.Update();
}

private void UpdateTreeGeneratro(){
    treeGenerator.Update();
}

private void UpdateStoneGenerator(){
    stoneGenerator.Update();
}

private void UpdateNPCGenerator(){
    npcGenerator.Update();
}

private void UpdateQuestGenerator(){
    questGenerator.Update();
    if(player.interact){
        player.interact = false;
        
        if(questGenerator.npcCollidable(player.collidable)){
            player.enableInput = false;
            cc.setDragToRotate(true);
        }
    }
    
    if(player.changeToHud){
        nifty.gotoScreen("hud");
        player.changeToHud = false;
        player.enableInput = true;
        cc.setDragToRotate(false);
        res.UpdateAllValue();
    }
}

private void UpdateEnemyGenerator(){
    enemyGenerator.Update();
}

private void UpdateResource(){
    res.Update();
}

private void UpdatePlayer(){
    
    if(!player.structure){
        player.Update(
                cam.getDirection().clone().multLocal(player.speed),
                cam.getLeft().clone().multLocal(player.speed),
                cam.getRotation().clone());

    if(player.build){
        player.build = false;
        if(!nifty.getCurrentScreen().getScreenId().equals("build")){
            nifty.gotoScreen("build");
            player.enableInput = false;

// player.buildMode = true;
cc.setDragToRotate(true);
}else{
nifty.gotoScreen(“hud”);
player.enableInput = true;
// player.buildMode = false;
cc.setDragToRotate(false);
}
}
}else{
planeConvertion.structureSpotPosition(cam, townGround.rootNode, structureGenerator);
if(player.leftClick){
structureGenerator.addStructure();
player.structure = false;
player.enableInput = true;
// player.buildMode = false;
cc.setDragToRotate(false);
nifty.gotoScreen(“hud”);
}
}

    if(player.esc){
        if(!nifty.getCurrentScreen().getScreenId().equals("right")){
            nifty.gotoScreen("right");
            player.enableInput = false;
            cc.setDragToRotate(true);
            player.esc = false;
        }else{
            nifty.gotoScreen("hud");
            player.enableInput = true;
            cc.setDragToRotate(false);
            player.esc = false;
        }
    }
    listener.setLocation(player.control.getPhysicsLocation());
    listener.setRotation(cam.getRotation());

// System.out.println("Listener Location: " + listener.getLocation());
// System.out.println("Listener Rotation: " + listener.getRotation());
// getElement(“text”).getRenderer(TextRenderer.class).setText("Position: " + player.control.getPhysicsLocation());
}

@Override
public void simpleRender(RenderManager rm) {
    //TODO: add render code
}

}
[/java]

NPCGenerator.java (This is the class where the cubes are created and their Updates are called)
[java]
package Generator;

import Character.Player;
import Character.TownPeople;
import Other.Map;
import Other.Resource;
import com.jme3.asset.AssetManager;
import com.jme3.bullet.BulletAppState;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.elements.render.TextRenderer;
import java.util.Random;

public class NPCGenerator {
public Node rootNode;
public TownPeople [] npcs;

private Resource res;
private AssetManager assetManager;
private BulletAppState bulletAppState;
private Random random;
public NPCGenerator(AssetManager assetManager, 
        BulletAppState bulletAppState, StructureGenerator sg, 
        TreeGenerator tg, StoneGenerator stng, Player player, Map map, 
        Resource res){
    this.assetManager = assetManager;
    this.bulletAppState = bulletAppState;
    this.res = res;
    
    rootNode = new Node("NPCGenerator");
    random = new Random();
    setupBasicNPC(sg, tg, stng, player, map);
}

private void setupBasicNPC(StructureGenerator sg, 
        TreeGenerator tg, StoneGenerator stng, Player player, Map map){
    npcs = new TownPeople[6];
    res.addResource("pop", npcs.length);
    
    for(int i = 0; i &lt; npcs.length; i++){
        if(random.nextInt(10) &lt; 5){
            npcs[i] = new TownPeople(assetManager, "Blue", 
                    new Vector3f(i, 1, i), i, sg, tg, stng, player, map);
        }else{
            npcs[i] = new TownPeople(assetManager, "Red", 
                    new Vector3f(i, 1, i), i, sg, tg, stng, player, map);
        }
        rootNode.attachChild(npcs[i].rootNode);
        bulletAppState.getPhysicsSpace().add(npcs[i].control);
    }
}

private void removeNPC(int i){
    rootNode.detachChild(npcs[i].rootNode);
    bulletAppState.getPhysicsSpace().remove(npcs[i].control);
    npcs[i].removed = true;
    res.decreaseResource("pop", 1);
}

public void Update(){
    for(int i = 0; i &lt; npcs.length; i++){
        if(npcs[i].alive){
            npcs[i].Update();
        }else if(!npcs[i].removed){
            removeNPC(i);
        }
    }
}

}
[/java]

BasicCharacter.java (This is where the cube model and characterControl is created. This class is mainly for setting up the Nodes, Spatial, Position and CharacterControl)

[java]
package Character;

import Other.BasicSound;
import Other.Effect;
import com.jme3.asset.AssetManager;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import java.awt.geom.CubicCurve2D;

public class BasicCharacter {
public Node rootNode, charNode;
public CharacterControl control;
public Spatial model;
public float speed, hp;
public boolean alive = true, removed = false;

protected Effect effect;
protected BasicSound sound;
protected AssetManager assetManager;
protected Vector3f position, walkDirection;
protected String type;
protected int number;
protected Material matModel;

public BasicCharacter(AssetManager assetManager, String type, 
        Vector3f position, int number){
    this.assetManager = assetManager;
    this.type = type;
    this.position = position;
    this.number = number;
    
    walkDirection = new Vector3f(0, 0, 0);
    rootNode = new Node(type + number);
    charNode = new Node("Char " + type + number);
    speed = 0;
    init();
    setupControl();
    setupEffect();
    setupSound();
    charNode.attachChild(model);
    charNode.setLocalTranslation(position);
    charNode.addControl(control);
    rootNode.attachChild(charNode);
}

private void setupSound(){
    sound = new BasicSound(assetManager);
    charNode.attachChild(sound.rootNode);
}

private void setupEffect(){
    effect = new Effect(assetManager, new Vector3f(0, 0, 0));
    charNode.attachChild(effect.rootNode);
}

private void init(){
    if(type.equals("Player")){
        model = assetManager.loadModel("Models/Cubes/Cube/Cube.mesh.j3o").clone();
        model.scale(0.1f, 0.1f, 0.1f);
        matModel = assetManager.loadMaterial("Materials/Cubes/Cube/Yellow.j3m");
        model.setMaterial(matModel);
        model.setLocalTranslation(new Vector3f(0, -0.15f, 0));
    }
    
    if(type.equals("Blue")){
        model = assetManager.loadModel("Models/Cubes/Cube/Cube.mesh.j3o").clone();
        model.scale(0.1f, 0.1f, 0.1f);
        matModel = assetManager.loadMaterial("Materials/Cubes/Cube/Blue.j3m");
        model.setMaterial(matModel);
        model.setLocalTranslation(new Vector3f(0, -0.15f, 0));
    }
    
    if(type.equals("Red")){
        model = assetManager.loadModel("Models/Cubes/Cube/Cube.mesh.j3o").clone();
        model.scale(0.1f, 0.1f, 0.1f);
        matModel = assetManager.loadMaterial("Materials/Cubes/Cube/Red.j3m");
        model.setMaterial(matModel);
        model.setLocalTranslation(new Vector3f(0, -0.15f, 0));
    }
    
    if(type.equals("Green")){
        model = assetManager.loadModel("Models/Cubes/Cube/Cube.mesh.j3o").clone();
        model.scale(0.1f, 0.1f, 0.1f);
        matModel = assetManager.loadMaterial("Materials/Cubes/Cube/Green_Smile.j3m");
        model.setMaterial(matModel);
        model.setLocalTranslation(new Vector3f(0, -0.15f, 0));
    }
    
    if(type.equals("PurpleEnemy")){
        model = assetManager.loadModel("Models/Cubes/Cube/Cube.mesh.j3o").clone();
        model.scale(0.1f, 0.1f, 0.1f);
        matModel = assetManager.loadMaterial("Materials/Cubes/Cube/Purple_Enemy.j3m");
        model.setMaterial(matModel);
        model.setLocalTranslation(new Vector3f(0, -0.15f, 0));
    }
}

private void setupControl(){
    CapsuleCollisionShape shape = new CapsuleCollisionShape(0.15f, 0.07f, 1);
    control = new CharacterControl(shape, 0.05f);
    control.setJumpSpeed(2f);
    control.setGravity(4f);
    control.setFallSpeed(5f);

// control.setPhysicsLocation(position);
}

public Spatial getModel(){
    return model;
}

}

[/java]

TownPeople.java (This is the main cube class. This class defines the cubes. Here it loads the axe and other models needed for the cube)

[java]
package Character;

import Generator.StoneGenerator;
import Generator.StructureGenerator;
import Generator.TreeGenerator;
import Other.Brain;
import Other.Map;
import com.jme3.animation.LoopMode;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import java.util.Random;

public class TownPeople extends BasicAnimation{

public float townSize;
public String jobType = "None";

protected Vector3f target;
protected boolean move = false, isWorking = false, toggle = false;
protected float happiness = 50;

private Spatial weapon, jobObject;
private Brain brain;
private Random random;
private int ranX, ranZ, workTime = 1000;
private Material smile, sad, matWeapon, matJO;
private float jobRot = 0f;

public TownPeople(AssetManager assetManager, String type, Vector3f position, 
        int number, StructureGenerator structureGenerator, 
        TreeGenerator treeGenerator, StoneGenerator sg, Player player, Map map){
    super(assetManager, type, position, number);
    
    brain = new Brain(structureGenerator, treeGenerator, sg, player, map);
    townSize = 5;
    speed = 0.005f;
    hp = 100;
    random = new Random();
    target = new Vector3f(0, 0, 0);
    setupMaterials();
    setupAllSound();
}

private void setupAllSound(){
    sound.setupWalk();
    sound.setupJump(1);
}

private void setupMaterials(){
    if(type.equals("Blue")){
        smile = assetManager.loadMaterial("Materials/Cubes/Cube/BlueSmile.j3m");
        sad = assetManager.loadMaterial("Materials/Cubes/Cube/BlueSad.j3m");
    }
    
    if(type.equals("Red")){
        smile = assetManager.loadMaterial("Materials/Cubes/Cube/RedSmile.j3m");
        sad = assetManager.loadMaterial("Materials/Cubes/Cube/RedSad.j3m");
    }
}

public void Update(){
    brain.Update();
    UpdateMovement();
    brainStatus();
}

/**
 * Updates the .updateModelBound of the object
 */
private void UpdateModel(){
    model.updateModelBound();
}

/**
 * Updates The Movement of the town cubes.
 */
public void UpdateMovement(){
    //Random Movement
    if(brain.state.equals("Random Movement")){
        if(!move){
            if(random.nextInt(1000) == 1){
                move = true;
                if(random.nextInt(6) &lt; 3){
                    ranX = random.nextInt(5);
                }else{
                    ranX = -1 * random.nextInt(5);
                }

                if(random.nextInt(6) &lt; 3){
                    ranZ = random.nextInt(5);
                }else{
                    ranZ = -1 * random.nextInt(5);
                }
                target = new Vector3f(ranX, 0, ranZ);
                animWalk(1, 1.5f);
            }

            if(random.nextInt(1000) == 2){
                control.jump();
                animJump(1, 0.9f);
                sound.jump.play();
            }
        }else{
            Vector3f toTarget = target.subtract(control.getPhysicsLocation());
            control.setWalkDirection(new Vector3f(toTarget.x * speed, 
                                                  0, 
                                                  toTarget.z * speed));
            control.setViewDirection(new Vector3f(toTarget.x, 
                                                  0,
                                                  toTarget.z));
            
            sound.walk.play();
            
            if(toTarget.length() &lt; 2){
                target.set(0,0,0);
                control.setWalkDirection(target);
                move = false;
                animStand(1, 1);
            }
        }
        
        if(!jobType.equals("None")){
            if(workTime &lt; 0){
                workTime = 1000;
                brain.gotoWork(jobType);
                animWalk(1, 1.5f);
            }
            workTime--;
        }
    }
    
    if(brain.state.equals("Map Out")){
        brain.findMin();
        if(!channel.getAnimationName().equals("Walk1")){
            animWalk(1, 1.5f);
        }
    }
    
    //Moves towards job site example: tree
    if(brain.state.equals("Job Site")){
        Vector3f toTarget = brain.target.subtract(control.getPhysicsLocation());
        control.setWalkDirection(new Vector3f(toTarget.x * speed, 
                                              0, 
                                              toTarget.z * speed));
        control.setViewDirection(new Vector3f(toTarget.x, 
                                              0,
                                              toTarget.z));
        sound.walk.play();
        
        if(toTarget.length() &lt; 1f){
            if(brain.nextPos()){
                target.set(0,0,0);
                control.setWalkDirection(target);
                animStand(1, 1);
                brain.state = "Do Work";
            }

// brain.decesionMode = true;
// doWork();
}
}

    //Does Work
    if(brain.state.equals("Do Work")){
        doWork();
    }
    
    //Checks out the new place/s like structure/s
    if(brain.state.equals("New Place")){
        if(!channel.getAnimationName().equals("Walk1")){
            animWalk(1, 1.5f);
        }
        Vector3f toTarget = brain.target.subtract(control.getPhysicsLocation());
        control.setWalkDirection(new Vector3f(toTarget.x * speed, 
                                              0, 
                                              toTarget.z * speed));
        control.setViewDirection(new Vector3f(toTarget.x, 
                                              0,
                                              toTarget.z));
        sound.walk.play();
        
        if(toTarget.length() &lt; 2){
            target.set(0,0,0);
            control.setWalkDirection(target);
            brain.decesionMode = true;
            animStand(1, 1f);
        }
    }
    
    //Goes to Job Building
    
    if(brain.state.equals("Job Building")){
        if(!channel.getAnimationName().equals("Walk1")){
            animWalk(1, 1.5f);
        }
        
        Vector3f toTarget = brain.target.subtract(control.getPhysicsLocation());
        control.setWalkDirection(new Vector3f(toTarget.x * speed, 
                                              0, 
                                              toTarget.z * speed));
        control.setViewDirection(new Vector3f(toTarget.x, 
                                              0,
                                              toTarget.z));
        sound.walk.play();
        
        if(toTarget.length() &lt; 2){
            if(brain.prePos()){
                brain.state = "Random Movement";
                brain.addResource("None", 10);
                brain.resetPath();
                animStand(1, 1);
                if(jobType.equals("Lumberjack") || jobType.equals("Miner")){
                    charNode.detachChild(jobObject);
                }
            }
        }
        
    }
}


private void brainStatus(){
    if(brain.status.equals("Lower Happiness")){
        lowerHappiness();
        loadMaterial();
        brain.status = "None";
    }
    if(brain.status.equals("Increase Happiness")){
        increaseHappiness();
        loadMaterial();
        brain.status = "None";
    }
    if(brain.status.equals("Lumberjack")){
        jobType = brain.status;
        increaseHappiness();
        loadMaterial();
        loadWeapon();
        loadJobObject();
        brain.status = "None";
    }
    if(brain.status.equals("Miner")){
        jobType = brain.status;
        increaseHappiness();
        loadMaterial();
        loadWeapon();
        loadJobObject();
        brain.status = "None";
    }
}

private void loadJobObject(){
    if(jobType.equals("Lumberjack")){
        jobObject = assetManager.loadModel("Models/Obstacles/Plank/Plank.mesh.j3o").clone();
        jobObject.scale(0.07f, 0.005f, 0.5f);
        matJO = assetManager.loadMaterial("Materials/Obstacles/Plank/Plank.j3m");
        jobObject.setMaterial(matJO);
        jobObject.setLocalTranslation(-0.08f, 0.05f, 0);

// charNode.attachChild(jobObject);
}

    if(jobType.equals("Miner")){
        jobObject = assetManager.loadModel("Models/Obstacles/Stone/Stone.mesh.j3o").clone();
        jobObject.scale(0.05f, 0.05f, 0.05f);
        matJO = assetManager.loadMaterial("Materials/Obstacles/Stone/Stone.j3m");
        jobObject.setMaterial(matJO);
        jobObject.setLocalTranslation(-0.08f, 0.05f, 0);

// charNode.attachChild(jobObject);
}
}

private void loadWeapon(){
    if(brain.status.equals("Lumberjack")){
        weapon = assetManager.loadModel("Models/Weapons/Axe/Axe.mesh.j3o").clone();
        weapon.scale(0.01f, 0.15f, 0.01f);
        matWeapon = assetManager.loadMaterial("Materials/Weapons/Axe/Axe.j3m");
        weapon.setMaterial(matWeapon);
        weapon.setLocalTranslation(0.1f, -0.1f, 0);
        weapon.rotate(-0.79f, 0, 0);
        charNode.attachChild(weapon);
        
        effect.setupDebris2(Vector3f.ZERO);
        sound.setupWood(1);
    }
    
    if(brain.status.equals("Miner")){
        weapon = assetManager.loadModel("Models/Weapons/PickAxe/PickAxe.mesh.j3o").clone();
        weapon.scale(0.01f, 0.15f, 0.01f);
        matWeapon = assetManager.loadMaterial("Materials/Weapons/PickAxe/PickAxe.j3m");
        weapon.setMaterial(matWeapon);
        weapon.setLocalTranslation(0.1f, -0.1f, 0);
        weapon.rotate(-0.79f, 0, 0);
        charNode.attachChild(weapon);
        
        effect.setupDebris2(Vector3f.ZERO);
        sound.setupStone(1);
    }
}

private void lowerHappiness(){
    happiness -= 20;
}

private void increaseHappiness(){
    happiness += 20;
}

private void loadMaterial(){
    if(happiness &lt; 50){
        model.setMaterial(sad);
    }else if(happiness &gt; 60){
        model.setMaterial(smile);
    }else if(happiness &gt;= 50 &amp;&amp; happiness &lt;= 60){
        model.setMaterial(matModel);
    }
}

private void doWork(){
    if(jobType.equals("Lumberjack")){
        if(!isWorking){
            weapon.rotate(0.79f, 0, 0);
            weapon.rotate(0, 0, -1.57f);
            isWorking = true;
        }
        if(jobRot &lt;= -1.57f){
            toggle = true;
            sound.wood.play();
            effect.onceEmit();
            brain.decreaseObjectHP(jobType);
        }
        
        if(jobRot &gt;= 1.57f){
            toggle = false;
        }
        
        if(toggle){
            jobRot+=0.002f;
            Quaternion tempRot = rootNode.getLocalRotation();
            tempRot.fromAngleAxis(jobRot, new Vector3f(0, 1, 0));
            rootNode.setLocalRotation(tempRot);
        }else{
            jobRot-=0.002f;
            Quaternion tempRot = rootNode.getLocalRotation();
            tempRot.fromAngleAxis(jobRot, new Vector3f(0, 1, 0));
            rootNode.setLocalRotation(tempRot);
        }
        
        if(!brain.isObjectAlive(jobType)){
            isWorking = false;
            Quaternion tempRot = rootNode.getLocalRotation();
            tempRot.fromAngleAxis(0, new Vector3f(0, 1, 0));
            rootNode.setLocalRotation(tempRot);
            weapon.rotate(-0.79f, 0, 0);
            weapon.rotate(0, 0, 1.57f);
            weapon.setLocalRotation(tempRot);
            weapon.rotate(-0.79f, 0, 0);
            charNode.attachChild(jobObject);
            brain.state = "Job Building";
        }
    }
    
    if(jobType.equals("Miner")){
        if(!isWorking){
            weapon.rotate(0.79f, 0, 0);
            weapon.rotate(0, 0, -1.57f);
            isWorking = true;
        }
        if(jobRot &lt;= -1.57f){
            toggle = true;
            sound.stone.play();
            effect.onceEmit();
            brain.decreaseObjectHP(jobType);
        }
        
        if(jobRot &gt;= 1.57f){
            toggle = false;
        }
        
        if(toggle){
            jobRot+=0.002f;
            Quaternion tempRot = rootNode.getLocalRotation();
            tempRot.fromAngleAxis(jobRot, new Vector3f(0, 1, 0));
            rootNode.setLocalRotation(tempRot);
        }else{
            jobRot-=0.002f;
            Quaternion tempRot = rootNode.getLocalRotation();
            tempRot.fromAngleAxis(jobRot, new Vector3f(0, 1, 0));
            rootNode.setLocalRotation(tempRot);
        }
        
        if(!brain.isObjectAlive(jobType)){
            isWorking = false;
            Quaternion tempRot = rootNode.getLocalRotation();
            tempRot.fromAngleAxis(0, new Vector3f(0, 1, 0));
            rootNode.setLocalRotation(tempRot);
            weapon.rotate(-0.79f, 0, 0);
            weapon.rotate(0, 0, 1.57f);
            weapon.setLocalRotation(tempRot);
            weapon.rotate(-0.79f, 0, 0);
            charNode.attachChild(jobObject);
            brain.state = "Job Building";
        }
    }
}

public void setupTownSize(float townSize){
    this.townSize = townSize;
}

public void decreaseHP(float amount){
    hp -= amount;
    
    if(hp &lt;= 0){
        alive = false;
        target.set(0,0,0);
        control.setWalkDirection(target);
    }
}

public void increaseHP(float amount){
    hp += amount;
}

}
[/java]

Brain.java (This class does all the decisions for the cube)

[java]
package Other;

import Character.Player;
import Database.BrainDB;
import Generator.StoneGenerator;
import Generator.StructureGenerator;
import Generator.TreeGenerator;
import com.jme3.math.Vector3f;
import java.util.Random;

public class Brain {

public BrainDB [] database;
public Vector3f target, posHome, posJob;
public boolean home = false, job = false, jobTime = false;
public boolean newPlace = false, decesionMode = false;
public String status = "None", state = "Random Movement";
public Vector3f [] storedPoints;
public int pointStored = 0;

private StructureGenerator structureGenerator;
private TreeGenerator treeGenerator;
private StoneGenerator sg;
private Map map;
private Player player;
private int newPointer = 0, timer = 1000, indexTree = 0, jobPointer = -1, 
        homePointer = -1, indexStone = 0;
private Random random;

public Brain(StructureGenerator structureGenerator, 
        TreeGenerator treeGenerator, StoneGenerator sg,
        Player player, Map map){
    this.structureGenerator = structureGenerator;
    this.treeGenerator = treeGenerator;
    this.sg = sg;
    this.player = player;
    this.map = map;
    database = new BrainDB[0];
    target = new Vector3f(0, 0, 0);
    random = new Random();
    storedPoints = new Vector3f[0];
}

private void increaseDB(){
    BrainDB [] temp = database;
    database = new BrainDB[structureGenerator.database.length];
    for(int i = 0; i &lt; temp.length; i++){
        database[i] = temp[i];
    }
    temp = null;
}

private void checkDatabase(){
    if(database.length != structureGenerator.database.length){
        newPlace = true;
        state = "New Place";
        increaseDB();
        for(int i = 0; i &lt; database.length; i++){
            if(database[i] == null){
                database[i] = new BrainDB(structureGenerator.database[i].name, 
                                          structureGenerator.database[i].number, 
                                          structureGenerator.database[i].position);
            }
        }
    }
}

private void pointerUpdate(){
    for(int i = 0; i &lt; database.length; i++){
        if(!database[i].visit){
            newPointer = i;
            target = database[i].position;
            state = "New Place";
        }
    }
}

private void decide(){
    if(database[newPointer].name.equals("Inn")){
        if(!home){
            if(structureGenerator.database[newPointer].obstacle.getAvailabe()){
                home = true;
                homePointer = newPointer;
                addResource("home", 100);
                posHome = database[newPointer].position;
                status = "Increase Happiness";
                state = "Random Movement";
            }else{
                status = "Lower Happiness";
                state = "Random Movement";
            }
        }else{
            state = "Random Movement";
        }
    }
    
    if(database[newPointer].name.equals("LumberCamp")){
        if(!job){
            if(structureGenerator.database[newPointer].obstacle.getAvailabe()){
                job = true;
                jobTime = true;
                jobPointer = newPointer;
                posJob = database[newPointer].position;
                indexTree = random.nextInt(treeGenerator.trees.length - 1); //random selection

// indexTree = 11; //<----- Change this back to random selection
if(treeGenerator.trees[indexTree].getAvailabe()){
target = treeGenerator.trees[indexTree].position;
}else{
for(int i = 0; i < treeGenerator.trees.length; i++){
if(treeGenerator.trees[i].getAvailabe()){
target = treeGenerator.trees[i].position;
indexTree = i;
break;
}
}
}
status = “Lumberjack”;
// state = “Job Site”; //<—Comment it out if Map Out does not work.
state = “Map Out”;
}else{
status = “Lower Happiness”;
state = “Random Movement”;
}
}else{
state = “Random Movement”;
}
}

    if(database[newPointer].name.equals("Quarry")){
        if(!job){
            if(structureGenerator.database[newPointer].obstacle.getAvailabe()){
                job = true;
                jobTime = true;
                jobPointer = newPointer;
                posJob = database[newPointer].position;
                indexStone = random.nextInt(sg.stones.length - 1); //random selection

// indexStone = 5; //<----- Change this back to random selection
if(sg.stones[indexStone].getAvailabe()){
target = sg.stones[indexStone].position;
}else{
for(int i = 0; i < sg.stones.length; i++){
if(sg.stones[i].getAvailabe()){
target = sg.stones[i].position;
indexStone = i;
break;
}
}
}
status = “Miner”;
// state = “Job Site”; //<—Comment it out if Map Out does not work.
state = “Map Out”;
}else{
status = “Lower Happiness”;
state = “Random Movement”;
}
}else{
state = “Random Movement”;
}
}
database[newPointer].visit = true;
decesionMode = false;
newPlace = false;
}

public void gotoWork(String type){
    if(type.equals("Lumberjack")){
        indexTree = random.nextInt(treeGenerator.trees.length - 1); //random selection
        if(treeGenerator.trees[indexTree].alive){
            if(treeGenerator.trees[indexTree].getAvailabe()){
                target = treeGenerator.trees[indexTree].position;
                state = "Map Out";
            }else{
                for(int i = 0; i &lt; treeGenerator.trees.length; i++){
                    if(treeGenerator.trees[indexTree].alive){
                        if(treeGenerator.trees[i].getAvailabe()){
                            target = treeGenerator.trees[i].position;
                            indexTree = i;
                            state = "Map Out";
                            break;
                        }else{
                            state = "Random MOvement";
                        }
                    }
                }
            }
        }else{
            for(int i = 0; i &lt; treeGenerator.trees.length; i++){
                if(treeGenerator.trees[indexTree].alive){
                    if(treeGenerator.trees[i].getAvailabe()){
                        target = treeGenerator.trees[i].position;
                        indexTree = i;
                        state = "Map Out";
                        break;
                    }else{
                        state = "Random MOvement";
                    }
                }
            }
        }
    }
    
    if(type.equals("Miner")){
        indexStone = random.nextInt(sg.stones.length - 1); //random selection
        if(sg.stones[indexStone].alive){
            if(sg.stones[indexStone].getAvailabe()){
                target = sg.stones[indexStone].position;
                state = "Map Out";
            }else{
                for(int i = 0; i &lt; sg.stones.length; i++){
                    if(sg.stones[indexStone].alive){
                        if(sg.stones[i].getAvailabe()){
                            target = sg.stones[i].position;
                            indexStone = i;
                            state = "Map Out";
                            break;
                        }else{
                            state = "Random MOvement";
                        }
                    }
                }
            }
        }else{
            for(int i = 0; i &lt; sg.stones.length; i++){
                if(sg.stones[indexStone].alive){
                    if(sg.stones[i].getAvailabe()){
                        target = sg.stones[i].position;
                        indexStone = i;
                        state = "Map Out";
                        break;
                    }else{
                        state = "Random MOvement";
                    }
                }
            }
        }
    }
}

///////// Related to Map/////////
public void findMin(){

// System.out.println(“Before Null checking”);
// if(target == null){
// System.out.println(“Target: Null”);
// }

// if(map.paths == null){
// System.out.println(“map.path: Null”);
// }
// System.out.println(“After Null checking”);

    Vector3f tempTarget = target.subtract(map.paths[0].position);
    float minDist = tempTarget.length();
    int id = 0;
    for(int i = 1; i &lt; map.paths.length; i++){
        if(target.subtract(map.paths[i].position).length() &lt; minDist){
            id = i;
            minDist = target.subtract(map.paths[i].position).length();
        }
    }

// System.out.println("Shortest Point: " + id);
increasePoints();
storedPoints[storedPoints.length - 1] = posJob;
increasePoints();
storedPoints[1] = map.paths[0].position;
MapOut(map.paths[0], id, -1);
increasePoints();
storedPoints[storedPoints.length - 1] = target;
state = “Job Site”;
target = storedPoints[pointStored];
}

public void resetPath(){
    storedPoints = null;
    storedPoints = new Vector3f[0];
    pointStored = 0;
}

private void MapOut(PathNode point, int destID, int preID){

// if(point.id == destID){
// System.out.println(point.id);
// return;
// }
//
// if(point.size == 1){
// increasePoints();
// storedPoints[storedPoints.length - 1] = point.adjs[0].position;
// MapOut(point.adjs[0], destID, point.id);
// System.out.println(point.id);
// }else{
// float minDist = 0;
// if(point.adjs[0].id != preID){
// minDist = map.paths[destID].position.subtract(point.adjs[0].position).length();
// }else{
// minDist = map.paths[destID].position.subtract(point.adjs[1].position).length();
// }
// int id = 0;
// for(int i = 1; i < point.adjs.length; i++){
// if(map.paths[destID].position.subtract(point.adjs[i].position).length() < minDist){
// minDist = map.paths[destID].position.subtract(point.adjs[i].position).length();
// id = i;
// }
// }
//
// increasePoints();
// storedPoints[storedPoints.length - 1] = point.adjs[id].position;
// MapOut(point.adjs[id], destID, point.id);
// System.out.println(point.id);
// }

    while(true){

// System.out.println(“Inside Loop”);
// System.out.println("Current Point: " + point.id);
// System.out.println("Pre Point: " + preID);
if(point.id == destID){
// System.out.println(“Broke Loop”);
break;
}
float minDist = 0;
int id = 0;
if(point.adjs[0].id != preID){
minDist = map.paths[destID].position.subtract(point.adjs[0].position).length();
}else{
minDist = map.paths[destID].position.subtract(point.adjs[1].position).length();
id = 1;
}

// System.out.println(“Default Min Distance”);
for(int i = 1; i < point.adjs.length; i++){
// System.out.println(“Searching Min Dist”);
if(map.paths[destID].position.subtract(point.adjs[i].position).length() < minDist && point.adjs[i].id != preID){
minDist = map.paths[destID].position.subtract(point.adjs[i].position).length();
id = i;
}
}
// System.out.println(“Increase Size”);
increasePoints();
// System.out.println(“Added”);
storedPoints[storedPoints.length - 1] = point.adjs[id].position;
// System.out.println(“New Point”);
preID = point.id;
point = point.adjs[id];
}
}

public boolean nextPos(){
    boolean reached = false;
    pointStored++;
    if(pointStored &gt;= storedPoints.length){
        reached = true;
        return reached;
    }
    target = storedPoints[pointStored];
    return reached;
}

public boolean prePos(){
    boolean reached = false;
    pointStored--;
    if(pointStored &lt; 0){
        reached = true;
        return reached;
    }
    target = storedPoints[pointStored];
    return reached;
}

private void increasePoints(){
    Vector3f [] temp = storedPoints;
    storedPoints = new Vector3f[storedPoints.length + 1];
    for(int i = 0; i &lt; temp.length; i++){
        storedPoints[i] = temp[i];
    }
    temp = null;
}


///////////////END////////////

public void addResource(String type, float amount){

// System.out.println(“Brain: AddResource”);
if(!type.equals(“home”)){
structureGenerator.database[jobPointer].obstacle.addResource(amount);
}else{
structureGenerator.database[homePointer].obstacle.addResource(amount);
}
}

public void Update(){

// if(!decesionMode){
//// if(player.added){
//// player.added = false;
//// checkDatabase();
//// pointerUpdate();
//// newPlace = true;
//// timer = 500;
//// }
//
// if(timer < 0){
// if(!state.equals(“Do Work”) && !state.equals(“Job Site”)
// && !state.equals(“Job Building”)){
// if(!newPlace){
// checkDatabase();
// if(newPlace){
// pointerUpdate();
// }
// }
// }
// timer = 1000;
// }
//
// timer–;
// }else{
// decide();
// }
if(!decesionMode){
if(timer < 0){
if(!state.equals(“Do Work”) && !state.equals(“Job Site”)
&& !state.equals(“Job Building”)){
checkDatabase();
pointerUpdate();
}
timer = 1000;
}
timer–;
}else{
decide();
}
}

public void decreaseObjectHP(String jobTitle){
    if(jobTitle.equals("Lumberjack")){
        treeGenerator.trees[indexTree].decreaseHP(20f);
    }
    
    if(jobTitle.equals("Miner")){
        sg.stones[indexStone].decreaseHP(20f);
    }
}

public boolean isObjectAlive(String jobTitle){
    if(jobTitle.equals("Lumberjack")){
        return treeGenerator.trees[indexTree].alive;
    }
    
    if(jobTitle.equals("Miner")){
        return sg.stones[indexStone].alive;
    }
    
    return false;
}

}

[/java]

That’s a lot of code. You may want to see if you can create a simple test case that illustrates the issue. 9 times out of 10, your test case will be fine and then you can reverse engineer what the crucial difference is.

Random comment: it is interesting how you’ve essentially manually reimplmented AppStates on your application. You might want to look at AppStates as it would simplify your code a bunch.

@pspeed: Sure I will try to create a simple test case for this issue. Not sure what you mean by “reimplement AppStates” :-? but what I did here is that I created a bulletAppState in Main.java class line 301 and then sent it to other classes in this case NPCGenerator.java. In NPCGenerator.java lines 22 and 29, I created BulletAppState object (line 22) and then used this to refer to the original BulletAppState that was sent from Main.java (line 29). I did this so that what ever charactercontrol adding or removing is needed then it can be done in this class rather than going back to Main.java and doing it there which would create lot of confusion but this way this class will handle only things that are related to it thus making less fuss and confusion. So this is why I sent the BulletAppState to these Generator class just to simplify the process. Still not sure what you meant by “reimplement AppStates” but if this was the case what you meant by it then there it is. I will still look at AppStates as you mentioned. :slight_smile: , just so if I misplaced any steps or understood it incorrectly.

Thanks.

You have lots of code that is essentially “initialize all of these classes when I start up” and then “update all of these classes when I update”. That’s precisely what AppStates are for. So instead of snaking a bunch of update methods all over the place you could have just implemented app states and attached them to the state manager.

…that’s what I meant.

You avoid code like:

The just passed through to:

Just make your generators app states and then attach them. Enable or disable them with the state of your game… or just attach/detach them.

Oh cool, I understand now :slight_smile: . Will do that, electricity is back now can start working again :smiley: .

@pspeed: Fortunately I always keep versions(.zip files) after every feature I finish and keep a document what I did in those versions :slight_smile: . So I went through the versions and found that before adding the particle effect everything was fine but when I again started my current version alas the problem was there again :frowning: . Both my cubes and buildings have particle effects in it. I tried to narrow down the problem so I conducted an experiment 8) , as follows:

First Experiment:

  1. Disabled the particle effect for both cubes and building, 10 out of 10 times the game worked without having any problem.
  2. Disabled the particle effect for buildings but not cubes, 9 out of 10 times the game worked without having any problem.
  3. Enabled the particle effect for both cubes and building, 8 out of 10 times the game worked without having any problem.

After the first experiment I thought of doing the experiment again for just to be sure.

Second Experiment:

  1. Disabled the particle effect for both cubes and building, 10 out of 10 times the game worked without having any problem.
  2. Disabled the particle effect for buildings but not cubes, 5 out of 6 times the game worked without having any problem.
  3. Disabled the particle effect for cubes but not building, 6 out of 6 times the game worked without having any problem.
  4. Enabled the particle effect for both cubes and building, 5 out of 6 times the game worked without having any problem.

After conducting the second experiment I narrowed it down even further, the particle effect in the cubes where giving the problem. I am adding the code of the particle effect just to explain what I did.

Effect.java (Particle Effect class)
[java]
package Other;

import com.jme3.asset.AssetManager;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh.Type;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;

public class Effect {
public Node rootNode;

AssetManager assetManager;
boolean isShockwave = false, isDebris = false, isCharge = false,
        isDebris2 = false;
ParticleEmitter shockwave, debris, charge, debris2;
Material matShock, matDebris, matCharge, matDebris2;
Vector3f position;
int timer = 0;

public Effect(AssetManager assetManager, Vector3f position){
    this.assetManager = assetManager;
    this.position = position;
    rootNode = new Node("Effects");
    rootNode.setLocalTranslation(position.x, position.y +0.1f, position.z);
}

public void setupCharge(Vector3f newPos){
    isCharge = true;
    
    charge = new ParticleEmitter("Charge", Type.Triangle, 10);
    matCharge = assetManager.loadMaterial("Materials/Effects/Charge.j3m");
    charge.setMaterial(matCharge);
    charge.setImagesX(2); 
    charge.setImagesY(2); // 2x2 texture animation
    charge.setEndColor(  new ColorRGBA(0.4f, 0.4f, 0f, 1f));
    charge.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f));
    charge.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 0, -2));
    charge.setParticlesPerSec(0);
    charge.setStartSize(0.5f);
    charge.setEndSize(0.3f);
    //charge.setSelectRandomImage(false);
    charge.setGravity(0, 0, 0);
    charge.setLowLife(1f);
    charge.setHighLife(1f);
    charge.getParticleInfluencer().setVelocityVariation(1f);
    charge.setLocalTranslation(newPos);
    charge.killAllParticles();
    rootNode.attachChild(charge);
}

public void setupDebris2(Vector3f newPos){
    isDebris2 = true;
    
    debris2 = new ParticleEmitter("Debris2", Type.Triangle, 15);
    debris2.setSelectRandomImage(true);
    debris2.setRandomAngle(true);
    debris2.setRotateSpeed(FastMath.TWO_PI * 4);
    debris2.setStartColor(new ColorRGBA(0.4f, 0.2f, 0f, 1));
    debris2.setEndColor(new ColorRGBA(0.25f, 0.25f, 0.25f, 0f));
    debris2.setStartSize(.05f);
    debris2.setEndSize(.05f);

// debris.setShape(new EmitterSphereShape(Vector3f.ZERO, .05f));
debris2.setParticlesPerSec(0);
debris2.setGravity(0, 12f, 0);
debris2.setLowLife(1.4f);
debris2.setHighLife(1.5f);
debris2.setInitialVelocity(new Vector3f(0, 15, 0));
debris2.setVelocityVariation(.60f);
debris2.setImagesX(2);
debris2.setImagesY(2);
matDebris2 = assetManager.loadMaterial(“Materials/Effects/Debris2.j3m”);
debris2.setMaterial(matDebris2);
rootNode.attachChild(debris2);
}

public void setupDebris(){
    isDebris = true;
    
    debris = new ParticleEmitter("Debris", Type.Triangle, 15);
    debris.setSelectRandomImage(true);
    debris.setRandomAngle(true);
    debris.setRotateSpeed(FastMath.TWO_PI * 4);
    debris.setStartColor(new ColorRGBA(0f, 1f, 0f, 1));
    debris.setEndColor(new ColorRGBA(0f, 0.5f, 0f, 0f));
    debris.setStartSize(.2f);
    debris.setEndSize(.2f);

// debris.setShape(new EmitterSphereShape(Vector3f.ZERO, .05f));
debris.setParticlesPerSec(0);
debris.setGravity(0, 12f, 0);
debris.setLowLife(1.4f);
debris.setHighLife(1.5f);
debris.setInitialVelocity(new Vector3f(0, 15, 0));
debris.setVelocityVariation(.60f);
debris.setImagesX(3);
debris.setImagesY(3);
matDebris = assetManager.loadMaterial(“Materials/Effects/Debris.j3m”);
debris.setMaterial(matDebris);
rootNode.attachChild(debris);
}

public void setupShockwave(){
    isShockwave = true;
    
    shockwave = new ParticleEmitter("Shockwave", Type.Triangle, 1);
    shockwave.setFaceNormal(Vector3f.UNIT_Y);
    shockwave.setStartColor(new ColorRGBA(.0f, 0.17f, 0f, (float) (.8f / 1)));
    shockwave.setEndColor(new ColorRGBA(.0f, 0.1f, 0.0f, 0f));
    
    shockwave.setStartSize(0f);
    shockwave.setEndSize(7f);
    shockwave.setParticlesPerSec(0);
    shockwave.setGravity(0, 0, 0);
    shockwave.setLowLife(0.5f);
    shockwave.setHighLife(0.5f);
    shockwave.setInitialVelocity(new Vector3f(0, 0, 0));
    shockwave.setVelocityVariation(0f);
    shockwave.setImagesX(1);
    shockwave.setImagesY(1);
    
    matShock = assetManager.loadMaterial("Materials/Effects/Shockwave.j3m");

// matShock = new Material(assetManager, “Common/MatDefs/Misc/Particle.j3md”);
// matShock.setTexture(“Texture”, assetManager.loadTexture(“Textures/Effects/Shockwave.png”));
shockwave.setMaterial(matShock);
rootNode.attachChild(shockwave);
}

public void onceEmit(){
    if(isShockwave){
        shockwave.emitAllParticles();
    }
    
    if(isDebris){
        debris.emitAllParticles();
    }
    
    if(isDebris2){
        debris2.emitAllParticles();
    }
    
    if(isCharge){
        charge.emitAllParticles();
    }
}

public void killEmit(){
    if(isShockwave){
        shockwave.killAllParticles();
    }
    
    if(isDebris){
        debris.killAllParticles();
    }
    
    if(isDebris2){
        debris2.killAllParticles();
    }
    
    if(isCharge){
        charge.killAllParticles();
    }
}

public void Update(){

// if(isShockwave && timer == 0){
// charge.emitAllParticles();
// }
// timer++;
// if(timer > 1000){
// charge.killAllParticles();
// timer = 0;
// }
}
}
[/java]

Okay the thing is that when every cube is created only the constructor of the Effect.java is called. So this means that no particle effect is created yet. Now what I am doing is that when the cubes become a Lumberjack only then is Effect.setupDebris2(Vector3f.ZERO) is called, I did this because every profession will give different kind of particle effect. This method is called during game time. So I conducted another experiment to narrow down the problem even deeper.

Third Experiment:

  1. Calling only the constructor of the Effect.java class and disabling all setup methods(like Effect.setupDebris2()) and emit methods. 10 out of 10 times the game worked without having any problem.
  2. Calling the constructor of the Effect.java class and the Effect.setupDebris2() and disabling all emit methods. 8 out of 10 times the game worked without having any problem.

So after conducting this experiment I now know that the Effect.setupDebris2() was creating the problem. I thought maybe setting up the particle effect during the middle of game time is not a good idea. So I called the Effect.setupDebris2() during cube creation that is in the constructor and conducted another experiment. This time the result made no sense to me at all. Here is the result.

Fourth Experiment (Final Experiment):

  1. Enabled particle effect of both cubes and building with new settings. 5 out of 10 times the game worked without having any problem.

After seeing this result I got confused a bit :-? , I was hoping that this would solve the problem. So now I am thinking and certain that the problem is being caused because of the particle effect but at random times.
Any thoughts on that ? @pspeed :smiley: because I am not sure why that happens at random times :-? . Maybe I am doing something wrong?

Thanks

So in short no particles work fine yes?

I suggest to debug with breakpoints how the state of the game is in the cases it dissappears, vs the cases where it works.
Maybee you have some kind of race condition there.

Also i assume your tests are 100%deterministic, eg all tress workes ect same position, nothing with randomness in it? Cause that coul very well hide the problem statistically else.

@EmpirePhoenix: The particles work fine when there are only 5 cubes in the game but when there are more than 5 then the problem starts. The problem that the particle is doing is that it is making the cubes disappear and reappear but at the same time the particle is working and animating when it is visible, that’s the part that I don’t understand, I mean if it works for 5 cubes shouldn’t it work for 10 cubes, maybe I am doing something wrong and will look into it further.

I will take your advice and debug with breakpoints as you mentioned. This part may take long time to debug

how the state of the game is in the cases it dissappears, vs the cases where it works.
since I can’t tell for sure when the problem will arise since it’s random -.- but have to do it anyway.

Yes the conditions(methods or funtions) are deterministic and the trees are created in same position all the time, they are not created in random places every time the game starts.

Thanks

It is tough for us to help when dealing with pieces of a whole project. Even if we had the whole project, few of us have the time to download and test it.

It’s much better if you can create a simple (preferably one class) test case that illustrates the issue. This is part of your due diligence also because most of the time, the test case will work fine and then you can reverse engineer what the crucial difference is.

Other than that, I think you will be on your own unless someone accidentally spots something by random luck.

@pspeed: I understand, it is difficult to see where the problem is in others project especially big projects. I will try my best to figure out what the problem is and then post it here. Anyway I thank you all for trying to help me out :smiley: . Much appreciated :smiley: .

K Out!