i'm pretty far into developing a game w/ many hundreds of lines of code. everything about jme is great. however, during beta testing i'm noticing a few unpredictable exceptions. these are things that are not static or necessarily repeatable, but happen "out in the field" w/ my users. it appears that a number of jme methods throw exceptions. some examples that are routinely crashing my game:
ArrayIndexOutOfBoundsException thrown by Node.attachChild(…)
ArrayIndexOutOfBoundsException thrown by Spatial.removeController(…)
IndexOutOfBoundsException thrown by Node.detachAllChildren()
my question is: does this mean i need to add try/catch to some/most/all jme methods?? do i really need to do try/catch on every instance of attachChild or detachAllChildren in my code? why is something like Node.detachAllChildren() crashing my game – that seems like a design flaw to me, no?
sorry if my question is so general in nature
ps – i'm using CVS version from about a month or so ago. is this something that would have been addressed since then?
l---l said:
my question is: does this mean i need to add try/catch to some/most/all jme methods??
no
These exceptions are most likely caused by muti-threading or reentrance: You are not allowed to modify Node.children and Spatial.controllers while the scenegraph is processed by jME (e.g. in updateGeometricState). To avoid this you can use locks - if multithreaded - or defer the modification to a later point in time (after update) - if your calls are nested calls.
that seems like a design flaw to me, no?
this is no more a design flaw than
Object o = null;
o.toString();
which throws an exception as well.
(hey, calm down, HamsterofDeath :))
They don't call him HamsterOfDeath for nothin'!
i tried to be helpful in a funny and ironic way. i cut off the text where i explained what might cause the problems because irrisor already did it and only left the part you are seeing now. yes, i agree, it may be looking like the "death" part of me took over for a moment.
this is awkward. i will hide in a dark hole now until everyone forgets about this.
irrisor said:
defer the modification to a later point in time (after update)
thanks -- is there a tutorial for this? i'm using standard game and game states. are you saying i should call updateGeometricState first inside my gamestate's update method, then do my other stuff? how do i defer the modification to a later point in time? i'm using my update methods as a way to stack a series of method calls (updating spatials, moving things, etc.) -- is that not the way to do it?
anyone?
do i use game.lock()? if so where do i call it, inside update()?
basically i have a bunch of gamestates, all of which use update to transform/process all my game stuff
public void update(float tpf) {
[…a number of method calls here…]
}
so how/where do i lock and unlock?
Doing your stuff inside the GameStates.update() method is the right way to do it, that way you don't need to lock() anything.
But you shouldn't remove or add things to the Scenegraph in a Controllers.update() method.
A controller is updated then upateGeometricstate() is called. (which is usually once at the end of a update cycle).
thanks. does calling spatial.removeController(this) count as removing from the scenegraph? if yes, then what is the proper way to remove a controller? here's what i'm doing now:
mycontroller = new Controller() {
public void update(float tpf) {
[...do stuff...]
if(isDone) {
spatial.removeController(this);
}
}
};
spatial.addController(mycontroller);
do i use game.lock()? if so where do i call it, inside update()?
i don't think he meant the jme lock, but the java lock.
Look at the Method Spatial.updateWorldData() (which is called from inside updateGeometricState())
If our Spatial has two Controllers and the first controllers removes himself, you will run into the IndexOutOfBounds Exception when the 2nd controllers should be updated (since geometricalControllers.get(1) will fail).
public void updateWorldData(float time) {
// update spatial state via controllers
if(geometricalControllers != null) {
for (int i = 0, gSize = geometricalControllers.size(); i < gSize; i++) {
try {
Controller controller = geometricalControllers.get( i );
if ( controller != null ) {
if (controller.isActive()) {
controller.update( time );
}
}
} catch ( IndexOutOfBoundsException e ) {
// a controller was removed in Controller.update (note: this may skip one controller)
break;
}
}
}
So i think that only the last controllers can safely remove himself inside its own update() method.
You could mark Objects who should be removed from the Scenegraph with a boolean isDead or isActive.
And then in a 2nd Step, remove those unused objects from the Scene in the Gamestates update method.
now that i actually think about it ( ) i always separate my logic functions/controllers in 2 lists: active and removequeue. when a controller decides to commit suicide, it adds itself to the removequeue which i iterate over at the end of an update cycle and remove the controllers from the active list.
sometimes i do this:
for (int i = 0;i<size();i++)
{
boolean shouldremove = list.get(i).doItAndShouldRemove();
if (shouldremove)
{
list.remove(i--);
}
}
don't do it. it will probably confuse you later on. :P