EddieRich
JGO n00b  Posts: 21
|
 |
«
on:
2012-01-04 08:58:03 » |
|
Hello everyone,
I am writing a simple abstract game in an attempt to learn java programming, and eventually Android apps. I have been a windows/C++/C# programmer for over 20 years, but I am new to java. I have a solid understanding of the language, threads, GUI, etc.
My question is, how do I implement the state machine logic for a game where there is an initial welcome screen, which switches to the game screen, and allows the user to make a move, then the computer, then the user, etc.
I'm looking for a tutorial that goes beyond "Hello World" or "How to start a background thread". I just can't seem to get my head around the state machine logic for a simple game like tic-tac-toe.
I'm hoping someone has a link to a tutorial for a "your turn/my turn" type of game.
Ed
|
|
|
|
|
StonePickaxes
Full Member   Posts: 204 Medals: 3
Nathan Kramber
|
 |
«
Reply #1 on:
2012-01-04 09:07:42 » |
|
What I did for my game I'm working on is I just have 2 booleans: inGame and inMainmenu, and I flip the values when I switch from menus to game, or vice-versa. In your main game loop, just put the logic for each one there (or use an interface and put the logic for each one in it's own class) 1 2 3 4 5
| while (running) while (inGame) while (inMainMenu) |
I'm new to java too. I feel weird being the one giving advice for once x:
|
|
|
|
EddieRich
JGO n00b  Posts: 21
|
 |
«
Reply #2 on:
2012-01-04 09:22:44 » |
|
I'm new to java too. I feel weird being the one giving advice for once x:
Don't feel weird, it's good advice, and appreciated. I had considered a simple boolean flag to notify the computer player thread to actually make it's move. For some reason that seems "amateur" to me, and I thought there might be some other, more elegant solution that I had never seen before. But, sometimes the simplest solution is the best.
|
|
|
|
|
Games published by our own members! Go get 'em!
|
|
|
|
theagentd
JGO Wizard     Posts: 1393 Medals: 88
|
 |
«
Reply #4 on:
2012-01-04 10:26:45 » |
|
You could use a state engine, which I believe is pretty much standard for this. I don't know how advanced your knowledge of Java is or anything, but it simplifies a lot of things and allow you to add as many different "states" as you want without having to change the main loop. It's pretty easy, but it relies heavily on object orientation, but as you have experience with C/C++ it should be a piece of cake. Create a small State interface: 1 2 3 4 5
| package somewhere.meaningful;
public interface State{ public void update(); } |
Then create a class that implements this interface for each "state" in the game; main menu, playing, pause menu, options menu, ending credits, e.t.c. 1 2 3 4 5 6 7
| package somewhere.meaningful;
public class MainMenu implements State{ public void update(){ } } |
1 2 3 4 5 6 7
| package somewhere.meaningful;
public class GameRunning implements State{ public void update(){ } } |
E.t.c. Your main class then looks something like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| private State state; private boolean running = true;
public void gameloop(){ while(running){ state.update(); } }
public void setState(State state){ this.state = state; }
public void endGame(){ running = false; } |
You also need to let each State keep a reference to the main class so they can actually access the setState() and endGame() functions.
|
There is no god.
|
|
|
ReBirth
JGO Wizard     Posts: 1279 Medals: 19
|
 |
«
Reply #5 on:
2012-01-04 10:36:33 » |
|
adding to above post, by using State interface you can share main objects like Graphics or sometimes keyEvent.
|
Follow me, your mastah, on TWITTAH!
|
|
|
EddieRich
JGO n00b  Posts: 21
|
 |
«
Reply #6 on:
2012-01-04 11:45:52 » |
|
I think I finally have my "head around it" now. That is the type of solution I was looking for. I'll have to add some thread sync, but I think I'm off and running again.
Thank you everyone for your quick answers.
Ed
|
|
|
|
|
theagentd
JGO Wizard     Posts: 1393 Medals: 88
|
 |
«
Reply #7 on:
2012-01-04 11:51:55 » |
|
Have fun! 
|
There is no god.
|
|
|
Gingerious
JGO n00b  Posts: 26 Medals: 2
|
 |
«
Reply #8 on:
2012-02-06 17:21:26 » |
|
Should each state implement its own key listener, or is that a bad idea?
|
|
|
|
|
UprightPath
Full Member   Posts: 214 Medals: 9
|
 |
«
Reply #9 on:
2012-02-06 23:21:02 » |
|
Should each state implement its own key listener, or is that a bad idea?
Probably not. They can, but it's probably not the best idea. A better idea would be to have a key listener that forwards commands to your state, and allow the state to handle it some how. This doesn't mean the state itself has just that some member there should perform the logic. Otherwise, you'll have to be adding/removing listeners all of the time to make sure that each state only receives the keystrokes when they're the active one.
|
I am filled with despair... About how far people think about ideas they propose, about the state of my teams in classes when people do not understand what an assumption is...
|
|
|
Games published by our own members! Go get 'em!
|
|
gbeebe
Full Member   Posts: 145 Medals: 5
|
 |
«
Reply #10 on:
2012-02-07 00:15:54 » |
|
My solution to listeners was to have the main class handle the actual "listening" and then sending the event to the current State. My State interface: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public interface State { public void next(Graphics g); public void mouseClicked(MouseEvent evt); public void mouseEntered(MouseEvent evt); public void mouseExited(MouseEvent evt); public void mousePressed(MouseEvent evt); public void mouseReleased(MouseEvent evt); public void mouseDragged(MouseEvent evt); public void mouseWheelMoved(MouseWheelEvent evt); public void mouseMoved(MouseEvent evt); public void keyPressed(KeyEvent evt); public void keyReleased(KeyEvent evt); public void keyTyped(KeyEvent evt); } |
Then my main class has the listeners and simply forwards the event; my keyPressed event in the main Class: 1 2 3 4
| @Override public void keyPressed(KeyEvent evt) { state.keyPressed(evt); } |
You can set state to be any class implementing State. I am passing 'this' to my classes when creating them, and they set it to an internal variable of the main class called 'me' Then I can change state by doing a me.state = ... I do not have my main class implement State, the examples probably do so to make sure you have all the procedures necessary. Or maybe there's another reason, I dunno.
|
|
|
|
|
theagentd
JGO Wizard     Posts: 1393 Medals: 88
|
 |
«
Reply #11 on:
2012-02-07 05:32:24 » |
|
1 2 3 4
| public interface State extends KeyListener, MouseListener, MouseMotionListener{ public void next(Graphics g); } |
And then just register the current state as a listener and you won't have to pass events through to the current state in your state handling code. 
|
There is no god.
|
|
|
Waterwolf
JGO n00b  Posts: 36 Medals: 2
|
 |
«
Reply #12 on:
2012-02-07 06:18:29 » |
|
1 2 3 4
| public interface State extends KeyListener, MouseListener, MouseMotionListener{ public void next(Graphics g); } |
And then just register the current state as a listener and you won't have to pass events through to the current state in your state handling code.  Whaaat. I didn't know interfaces can extend multiple interfaces. Life quality improved!
|
|
|
|
|
theagentd
JGO Wizard     Posts: 1393 Medals: 88
|
 |
«
Reply #13 on:
2012-02-07 06:35:30 » |
|
I was just as surprised as you were when I noticed it but it does make sense though. Name and argument collisions don't matter because there's no actual implementation of them, the "blueprints" just happened match up.
|
There is no god.
|
|
|
Gingerious
JGO n00b  Posts: 26 Medals: 2
|
 |
«
Reply #14 on:
2012-02-07 10:24:44 » |
|
1 2 3 4
| public interface State extends KeyListener, MouseListener, MouseMotionListener{ public void next(Graphics g); } |
And then just register the current state as a listener and you won't have to pass events through to the current state in your state handling code.   EDIT: Also, I'm assuming this, but it makes the most sense to me: I have a canvas that I'm adding my listeners to. When you say register, then when we change states, we'll have to remove the current state's listeners from the canvas, change the state, then add the new state's listeners to the canvas, right?
|
|
|
|
|
gbeebe
Full Member   Posts: 145 Medals: 5
|
 |
«
Reply #15 on:
2012-02-07 13:10:10 » |
|
My way doesn't change listeners. The main class handles the listening and forwards the events to the current state. I just thought it was easier this way.
|
|
|
|
|
theagentd
JGO Wizard     Posts: 1393 Medals: 88
|
 |
«
Reply #16 on:
2012-02-07 22:25:20 » |
|
@Gingerious and Gbeebe: Yeah, the idea is to do something like this: 1 2 3 4 5 6 7 8 9 10 11 12
| public void changeState(State newState){ if(currentState != null){ canvas.removeKeyListener(currentState); canvas.removeMouseListener(currentState); canvas.removeMouseMotionListener(currentState); }
currentState = newState; canvas.addKeyListener(currentState); canvas.addMouseListener(currentState); canvas.addMouseMotionListener(currentState); } |
|
There is no god.
|
|
|
ReBirth
JGO Wizard     Posts: 1279 Medals: 19
|
 |
«
Reply #17 on:
2012-02-08 07:13:15 » |
|
My way doesn't change listeners. The main class handles the listening and forwards the events to the current state. I just thought it was easier this way.
that's what I do everytime and work fine.
|
Follow me, your mastah, on TWITTAH!
|
|
|
theagentd
JGO Wizard     Posts: 1393 Medals: 88
|
 |
«
Reply #18 on:
2012-02-08 09:47:37 » |
|
My way doesn't change listeners. The main class handles the listening and forwards the events to the current state. I just thought it was easier this way.
that's what I do everytime and work fine. Lot's of things work fine, but that doesn't mean they're optimal or even close to efficient and/or flexible... 
|
There is no god.
|
|
|
ReBirth
JGO Wizard     Posts: 1279 Medals: 19
|
 |
«
Reply #19 on:
2012-02-08 09:57:20 » |
|
@theagentd and not mention about reuseable, extendable and readable  Kev said make it run first.
|
Follow me, your mastah, on TWITTAH!
|
|
|
Gingerious
JGO n00b  Posts: 26 Medals: 2
|
 |
«
Reply #20 on:
2012-02-08 16:24:22 » |
|
Srsly gais, this is really helpful. Also, this implementation seems like it would make sense to have a state manager class. in between the various states and the game class that holds the changeState(State state) method.
|
|
|
|
|
antelopeDJ
JGO n00b  Posts: 49
Java Developer on the Weekends!
|
 |
«
Reply #21 on:
2012-02-13 12:15:42 » |
|
You could use a state engine, which I believe is pretty much standard for this. I don't know how advanced your knowledge of Java is or anything, but it simplifies a lot of things and allow you to add as many different "states" as you want without having to change the main loop. It's pretty easy, but it relies heavily on object orientation, but as you have experience with C/C++ it should be a piece of cake. Create a small State interface: 1 2 3 4 5
| package somewhere.meaningful;
public interface State{ public void update(); } |
Then create a class that implements this interface for each "state" in the game; main menu, playing, pause menu, options menu, ending credits, e.t.c. 1 2 3 4 5 6 7
| package somewhere.meaningful;
public class MainMenu implements State{ public void update(){ } } |
1 2 3 4 5 6 7
| package somewhere.meaningful;
public class GameRunning implements State{ public void update(){ } } |
E.t.c. Your main class then looks something like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| private State state; private boolean running = true;
public void gameloop(){ while(running){ state.update(); } }
public void setState(State state){ this.state = state; }
public void endGame(){ running = false; } |
You also need to let each State keep a reference to the main class so they can actually access the setState() and endGame() functions. Thanks for providing this! It was really helpful, and let me complete a project quicker.
|
|
|
|
|
Blackout
JGO n00b  Posts: 10
|
 |
«
Reply #22 on:
2012-02-15 17:43:29 » |
|
I think this is called a turn system and I believe you can just control the player's turns with booleans. I've actually made a Battleship recently and i've implemented a turn system inside of it. If you wanna see the code, just give me a message. xD
|
|
|
|
|
|