So here’s the problem. This is all part of a tower defense game. I have code in the GamePlayAppState class that generates towers:
[java]
public void generateTowers(int num){
for(int index = 0; index < num; index++){
Spatial tower_geo = assetManager.loadModel(“Models/tower.j3o”);
int leftOrRight = (index % 2 == 0 ? 1 : -1); // -1 or +1
float offset_x = leftOrRight * 2.5f;
float offset_y = TOWER_HEIGHT * .5f;
float offset_z = index + 2;
Vector3f loc = new Vector3f(offset_x, offset_y, offset_z);
tower_geo.setLocalScale(0.66f,2.0f,0.66f);
tower_geo.setLocalTranslation(loc);
tower_geo.setUserData(“towerHeight”, TOWER_HEIGHT);
tower_geo.setUserData(“towerammo”, chargesNum);
tower_geo.setUserData(“index”, index);
tower_geo.addControl(new TowerControl(this));
towerNode.attachChild(tower_geo);
}
}
[/java]
I recently switched over from Cubes to tower.j3o
So then I have code in the main class that allows the player to left click a tower and hit the ‘G’ key to load a charge/bullet. I have this all in an actionlistener and intialized so everything works. I tested it before with cubes geometries.
[java]
if(mapping.equals(“Select”) && !keyDown){
System.out.println(“Check 1”);
//TODO:deselects previous tower
CollisionResults results = new CollisionResults();
Vector2f click2d = inputManager.getCursorPosition();
Vector3f click3d = cam.getWorldCoordinates(new Vector2f(click2d.getX(), click2d.getY()), 0f);//maybe add clone()
Vector3f dir = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d);
//cast the ray
Ray ray = new Ray(click3d, dir);
//check for collisions with towers(collideWith check for collisions)
rootNode.getChild(“tower node”).collideWith(ray, results);
System.out.println(“Check 2”);
//determine what user selected
if(results.size() > 0){
// ray collided with a tower
CollisionResult closest = results.getClosestCollision();
//selected tower number
Spatial spatial = closest.getGeometry();
TowerControl control = spatial.getControl(TowerControl.class);
selected = control.getIndex();//BUG
System.out.println(“Check 4”);
//tower is selected. Load charge
//check budget
}else{
//ray doesn't hit anything
selected = -1;
}
}[/java]
The problem comes in on the line with :
selected = control.getIndex();//BUG
It seems like as soon as I switch from cubes to models this line just doesn’t work and throws an error. The getIndex method is in the TowerControl control class and each tower that is generated has an index. This all worked when I had Geometry cubes.
getIndex method in towercontrol class:
public int getIndex() {
return (Integer) spatial.getUserData(“index”);
}
I have no idea what is going on. If anyone can help me then I would appreciate it. Thanks!
Sorry, what do you mean by indes. If you accidentally meant indexes: the indexes are generated in the generateTower method. I have been told this is a Spatial, parent, child node problem. A spatial can be a Geometry or a node. I’ve tried .getParent() two times after getGeometry on line 18 in the key input code. Why is this?
-> does hav index? if yes return it (if controll != null)
-> if no call method on parent
-> if no parent exists, you and no index was yet found, abort throw exception / return null.
This should really be in the FAQ since it seems we get this one two times a week now instead of just once a week.
[java]
for( Spatial s = collisions.getClosestGeometry(); s != null; s = s.getParent() ) {
TowerControl control = s.getControl(TowerControl.class);
if( s != null ) {
// do something with s or control
break;
}
}
[/java]
@pspeed Apparently this has got something to do with Spatials and nodes. When I call
System.out.println(closest.getGeometry().getParent().getParent()); it prints out tower.blend which is the blend file i used to convert to j3o.
Yea but the problem is that I’m sort of confused right now. I know how to go up using getParent() but I have problem when coming down the scene graph from rootNode. If you could just explain it to me how to do that. I’ve read tutorials and other forums topics and so far none of them were helpful.
getChild() returns a spatial which then you will have to case to Node because only nodes have children… but you don’t really need to do it because getChild() will already check for children so unless you really need only the towers under a specific subnode then you could have just put the tower name in.
Note: if casting is unfamiliar to you then you might consider learning some more Java until that kind of thing becomes easier. JME is tough to learn if you are also still learning Java.
@pspeed
So basically I have this(ray casting for clicks on towers):
[java]
CollisionResult closest = results.getClosestCollision();
selected = closest.getGeometry().getParent().getParent().getControl(TowerControl.class).getIndex();
[/java]
selected will be -1 if the ray casting did not pick up a tower. getIndex is a custom method I made in towercontrol class.
So then I have the code that loads the charges into the selected tower(determined by index):
When I run it it gives me an error on the TowerControl tower =… line. How do I go down the scenegraph from the rootnode so it is equivalent to two getparents on the geometry.
If getChild returns a Spatial, which is a node or geometry and the Textures/tower.blend is a node(I verified by printing in the console), then why doesn’t getChild(“Textures/tower.blend”) work?
closest.getGeometry() doesn’t work and closest.getGeometry().getParent() also doesn’t work.
I remember the hierarchy is like this:
rootnode -> tower node -> Textures/tower.blend (Node) -> tower -> mesh1
First, can I ask why you need to come down from the root?
As to the other, I’m still not sure why the loop I posted doesn’t work for finding the tower from the Geometry. getParent().getParent().etc. will only work until the model changes the next time you edit it and now it has a different hierarchy, where as searching up until TowerControl exists is guaranteed to always work to find the tower with the control in it.
Isn’t everything on the scenegraph a subnode of the rootnode. I’m actually following a tutorial Jmonkeyengine 3.0 for beginners
[link removed - normen]
on pg 122-123 where it asks you to load models into the tower defense game.
What I’m basically doing is:
getting the closest tower and getting its index/tower number
Load a charge into Tower X
@pspeed So the loop basically asking me to check through the entire chain/hierarchy until i find the one with the TowerControl?
I’ll try that actually?
EDIT: Not sure if this will help but I opened tower.j3o(the model I’m using for towers in the game) in the SceneExplorer view so I can get its hierarchy. Textures/tower.blend is a node. tower is a subnode of that.
@kevin.shen18 said:
Isn't everything on the scenegraph a subnode of the rootnode. I'm actually following a tutorial Jmonkeyengine 3.0 for beginners
[link removed - normen]
on pg 122-123 where it asks you to load models into the tower defense game.
What I’m basically doing is:
getting the closest tower and getting its index/tower number
Load a charge into Tower X
@pspeed So the loop basically asking me to check through the entire chain/hierarchy until i find the one with the TowerControl?
I’ll try that actually?
EDIT: Not sure if this will help but I opened tower.j3o(the model I’m using for towers in the game) in the SceneExplorer view so I can get its hierarchy. Textures/tower.blend is a node. tower is a subnode of that.
Yes, but as a general rule your model could have any number of Geometries and any number of indirections in the hierarchy. The for loop I showed walks up from the geometry to the first parent that has a TowerControl.
Yes, all attached things in the scene graph are available from the root node. But if I knew why you were trying to traverse down then I could potentially show you a better way.
@author normenhansen
*/
public class Main extends SimpleApplication {
public static void main(String[] args) {
AppSettings settings = new AppSettings(true);
settings.setTitle(“BasicTowerDefense”);
settings.useInput();
Main app = new Main();
app.setSettings(settings);
app.start();
}
//private GamePlayAppState game;
private int selected = -1;
private GamePlayAppState state = new GamePlayAppState();
@Override
public void simpleInitApp() {
// GamePlayAppState state = new GamePlayAppState();
stateManager.attach(state);
flyCam.setDragToRotate(true);
inputManager.setCursorVisible(true);
inputManager.addMapping("Select", new MouseButtonTrigger(0));//click select
inputManager.addMapping("LoadCharge", new KeyTrigger(KeyInput.KEY_G));
inputManager.addListener(actionListener, "Select", "LoadCharge");