Messing up with AppStates…
I have one main class with two defined app states class called state1 (for example) and state2. Each of them extends AbstractAppState.
Code for state1
[java]public class STATE1 extends AbstractAppState {
…
}[/java]
Code for state2
[java]public class STATE2 extends AbstractAppState {
…
}
[/java]
And the main app class has:
[java]…
private STATE1 s1;
private STATE2 s2;
…
[/java]
In the main app class there should be a public function, which acts as a order issuer to change one state to another, and this function purpose is to be able to be called from inside any existing state. So to do it, I have added to main main app class 3 variables:
[java]
…
private boolean needStateChange = false;
private Class<AbstractAppState> changeStateFrom;
private Class<AbstractAppState> changeStateTo;
…
[/java]
and a procedure, which writes down the information from which state it was called (so to put it on pause) and what state to unpause:
[java]
public void setState(Class<AbstractAppState> stateClass_from, String stateClass_to) {
needStateChange = true;
changeStateFrom = stateClass_from;
if (stateClass_to.equals("lets switch to state 2")) { changeStateTo = STATE2.class.cast(AbstractAppState); }
else {
log.log("Main: Failed to determine order to change states!!");
needStateChange = false;
}
}
[/java]
… and then this information is used in the update loop by:
[java]
@Override
public void update() {
// update states
if (!needStateChange)
stateManager.update(tpf);
else {
needStateChange=false;
changeStateFrom.cast(AbstractAppState.class).setEnabled(false);
changeStateTo.cast(AbstractAppState.class).setEnabled(true);
}
// simple update and root node
simpleUpdate(tpf);
rootNode.updateLogicalState(tpf);
guiNode.updateLogicalState(tpf);
rootNode.updateGeometricState();
guiNode.updateGeometricState();
…
}
[/java]
Well… it seems that passing the first parameter the way I wrote seems to be ok, but how do I correctly set the second variable??
Maybe I am doing it completely noob-way?
Maybe you can explain what behavior you want to achieve, then someone might be able to explain ou how its done (roughly).
I don’t really get what you actually want to do, whats the purpose?
No need to involve the update loop at all - just change the states directly.
These lines look weird:
changeStateFrom.cast(AbstractAppState.class).setEnabled(false);
What’s that bit about the cast()? Seems unnecessary. And I’m confused because it looks like changeStateFrom is a class and setEnabled() is a method on an instance. Is there a reason you are dealing with classes directly instead of actually creating some AppStates?
Also, I don’t see anywhere where you actually interact with the state manager.
And it looks like you are extending Application directly which is super-duper-super-super-bad unless you are a super-JME expert. Just extend SimpleApplication and let it do its proper update loop. You will save yourself a ton of issues in the future. I still want to rename Application to NeverExtendThisDirectly and then rename SimpleApplication to Application.
Maybe you can explain what behavior you want to achieve, then someone might be able to explain ou how its done (roughly).
I don’t really get what you actually want to do, whats the purpose?
The purpose is to be able to switch states from one to another, but the command to do so should come from inside one of the state. For example inside state1 I should be able to write "change to state2", and I thought it was only achievable not directly inside my state1, but from the main update loop only. But:
as @ancalagon said:
No need to involve the update loop at all - just change the states directly.
gives me some thoughts that it is possible to switch them not only through the update in main class.
These lines look weird:
changeStateFrom.cast(AbstractAppState.class).setEnabled(false);
Yeah.. well, I wasn't quite sure how correctly pass the parameters... the solution was to write it like so:
[java]
private AbstractAppState changeStateFrom;
private AbstractAppState changeStateTo;
..
private void changeStates() {
changeStateFrom.setEnabled(false);
changeStateTo.setEnabled(true);
needStateChange = false;
}
..
public void setState(AbstractAppState stateClass_from, String stateClass_to) {
needStateChange = true;
changeStateFrom = stateClass_from;
if (stateClass_to.equals("SectorMap")) { changeStateTo = stateManager.getState(appstateSectorMap.class); }
else {
log.log("Main: Failed to determine order to change states!!");
needStateChange = false;
}
}
..
and in the main class in update():
public void update() {
...
if (!needStateChange)
stateManager.update(tpf);
else
changeStates();
...
[/java]
and so I can use the changeState function from inside any state by calling:
[java]appRef.setState(this, "SectorMap");[/java]
Looks complicated, but rather logical, because, as I said before, only one state should be active at any moment, and others should be paused, so it's better to write one function inside main class that pauses all states, and unpauses the one I need, rather than write the same code inside each state class :)
Also, I don’t see anywhere where you actually interact with the state manager.
It's in the setState() function.
And it looks like you are extending Application directly which is super-duper-super-super-bad unless you are a super-JME expert. Just extend SimpleApplication and let it do its proper update loop. You will save yourself a ton of issues in the future. I still want to rename Application to NeverExtendThisDirectly and then rename SimpleApplication to Application.
Well.. using SimpleApplication is good when you are quite ok with the stuff inside it, like the default controls, and camera behavior. In my case, I do not use FlyByCamera, I have keyboard and mouse control redifinition for each state, and many many more (one of my state uses very complicated camera system when camera always stay at (0,0,0) and the scene moves around it, and the very far objects gets compacted to "condensed" space so that they would be closer to camera, but looks the same as they would be in "real" space) - if I would use SimpleApplication, I would need to disable more than 50% of what's inside there, so I extended Application and added there what I need :)
Anyway in the end I should say that the problem is solved atm. :) thanks for replies!
@KayTrance said:
It’s in the setState() function.
I didn't realize originally that you were just trying to disable and re-enable the states. By "switch app states", I thought you meant detaching one and attaching another.
@KayTrance said:
Well.. using SimpleApplication is good when you are quite ok with the stuff inside it, like the default controls, and camera behavior. In my case, I do not use FlyByCamera, I have keyboard and mouse control redifinition for each state, and many many more (one of my state uses very complicated camera system when camera always stay at (0,0,0) and the scene moves around it, and the very far objects gets compacted to "condensed" space so that they would be closer to camera, but looks the same as they would be in "real" space) - if I would use SimpleApplication, I would need to disable more than 50% of what's inside there, so I extended Application and added there what I need :)
I do almost all of those things which is why I fixed SimpleApplication in SVN to allow more easily disabling all of that stuff... but I still use SimpleApplication because it's better than having my code break with future releases. Really, all you need to do is disable flyCam, clear all mappings, and set stats disabled (if you want). 100x easier than rolling your own update() and hoping it doesn't break as the framework changes.
As to your original problem, given how generic all of the from state, to state stuff is, I'm not sure if you need the from later or not... but a pattern more like this is what I might have used:
[java]
private AppState activeState;
public void setActiveState( AppState newState ) {
if( this.activeState != null ) {
this.activeState.setEnabled(false);
}
this.activeState = activateState;
if( this.activeState != null ) {
this.activeState.setEnabled(true);
}
}
[/java]
...I don't know what you are using these app states for but the from/to stuff you had seemed so generic that I guessed you were not using it for other application stuff and somehow just using it to perform the transition. And that your "active app state" must be from a larger set of states than just those two app states or you could easily have just used changeStates() all the time.