Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Actions  (Read 1737 times)
0 Members and 1 Guest are viewing this topic.
Offline stef569

Junior Member





« Posted 2009-03-16 18:32:53 »

Can't sleep at night cus of this action mess that looked promosing at the start... let me explain.
I have an action object for each 'action' in my game like selecting a unit, moving from a to b, Attacking,etc
Each action has a doAction and undoAction method.
The idea for this was to allow to go back 1 step in a undo list, this worked using the swing Undomanager.

An example of that
Before the action is executed I set the (first) clicked tile in session, actions are stored in a map by name:
1  
2  
3  
4  
5  
session.setClick(1,tile)
Action selectAction = actions.get("Select")
selectAction.doAction()
if selectAction.canUndo()
  undoManager.add(selectAction)


selectAction.java
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
/**
 * Select a unit and make it the active unit in the game. This is the first action
 * for a unit.
 */

public class SelectAction extends AbstractAction {
  private MapRenderer mapRenderer;
  private InGameSession inGameSession;
  private Game game;

  public SelectAction(Game game, MapRenderer mapRenderer, InGameSession inGameSession) {
    super("Select");
    this.game = game;
    this.inGameSession = inGameSession;
    this.mapRenderer = mapRenderer;
  }

  public void doAction() {
    selectUnit((Unit) inGameSession.getClick(1).getUnit());
    inGameSession.setMode(InGameSession.MODE.UNIT_SELECT);
  }

  private void selectUnit(Unit selectedUnit) {
    game.setActiveUnit(selectedUnit);
    mapRenderer.setActiveUnit(selectedUnit);
    mapRenderer.removeZones();
    mapRenderer.showMoveZone();
    mapRenderer.showArrows(true);
  }

  public void undoAction() {
    deselectActiveUnit();
    inGameSession.setMode(InGameSession.MODE.DEFAULT);
  }

  private void deselectActiveUnit() {
    game.setActiveUnit(null);
    mapRenderer.setActiveUnit(null);
    mapRenderer.removeZones();
    mapRenderer.showArrows(false);
  }
}


Now I want to replay the actions that happened in the game.
But I always reuse the same Action, I don't create new action objects... Action objects have a lot of constructor parameters and I want to execute actions @ places that don't have access to these objects.
Also the actions get their input from a session object limiting it's use. a MoveAction can only move from session tile 1 to session tile 2.
Following the Command pattern an Action can't have setters, it should get all information from the constructor parameters that's why I used the session object.

When I would save a replay it probably look like
Select 0 0
Move 0 0 11
Select 2 2
....
Every game has a replay system, how do they do it? & how can I use Action objects to replay all the actions.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #1 - Posted 2009-03-16 19:33:43 »

Typically you don't need to store every single "Action" if all you want is a replay feature. Pretty much you need to know only those things that will affect graphical playback. Lots of logic and whatnot can be completely cut out. Typically the way to do this is simply to have one object that you can call basically a State or something like that. Every second or so (or more often if you like), you create a new State and then append that to a list. A State holds all relevant information for that given moment, like what X/Y position everything has, what animation it is currently playing and what frame in that animation it has, what rotation it has, etc. Then all you need to do later when you're playing back your game is to iterate over the States and simply draw what you see within it.

See my work:
OTC Software
Offline stef569

Junior Member





« Reply #2 - Posted 2009-03-17 13:20:34 »

I didn't say but the game doesn't change unless through an action.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline cylab

JGO Ninja


Medals: 38



« Reply #3 - Posted 2009-03-17 14:55:08 »

Just create new action instances. You could treat actions.get() as a factory method, so you don't have to invoke the constructor. Either make your actions instance hold the needed context for your Actions constructors or store prototypes in actions and return the clone() result of the stored prototype in get().

And if you differ your Actions by subclassing them, you can have a typesafe lookup:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
public class ActionsMap
{
  private final HashMap<Class, Action> prototypeMap = new HashMap<Class, Action>();

  public <ActionType extends Action> void registerPrototype(Class<ActionType> type, ActionType action)
  {
    prototypeMap.put(type, action);
  }

  public <ActionType extends Action> ActionType get(Class<ActionType> type)
  {
    Action prototype = prototypeMap.get(type);
    return (ActionType) prototype==null?null:prototype.clone();
  }
}


So you can do

1  
2  
  SelectAction action = actions.get(SelectAction.class);
  action.click(1);


without casting or weaving your logic into a generic doAction() method which needs to get it's arguments backdoor via the session.

Edit:
Having said that, it would probably be even better to dump your actions down, so you only have simple constructors expecting only values you know at places you would execute them and hold the additional context you need for execution in the session. Then you can do something along the lines of this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
  public class ClickAction extends Action
  {
     private int clickCount;
     public ClickAction(int clickCount)
     {
          this.clickCount = clickCount;
     }
     public Action invoke(Session session)
     {
          session.get(<whatever you need here>);
          // do something with the clickCount.
         (...)

          // return this for convinience
         return this;
     }
  }


1  
2  
   // invoke a single action
  new ClickAction(2).invoke(currentSession);


1  
2  
3  
4  
5  
6  
7  
8  
9  
   // invoke some actions and store them in the replay
  LinkedList<Action> replay = LinkedList<Action>();
   replay.add(new ClickAction(1).invoke(currentSession));
   replay.add(new SpeakAction("Hello you!").invoke(currentSession));
   replay.add(new FooAction(4711).invoke(currentSession));
   replay.add(new BarAction(42).invoke(currentSession));
   // ...
  // save it
  save(replay);


1  
2  
3  
4  
5  
6  
7  
   // load a replay
  List<Action> replay = load("savegamename");
   // invoke them all
  for(Action a : replay)
   {
       a.invoke(currentSession);
   }


I would use "context" instead of "session" though Wink

Mathias - I Know What [you] Did Last Summer!
Offline Jono
« Reply #4 - Posted 2009-03-17 21:09:31 »

You may want to consider only storing actions that affect the game at the model level, rather than at the view level which you currently seem to have it at. Say your game is an RTS, then you would not bother storing "select" actions, but would store model-changing actions like "move". Unless, of course, you expect replays to be in a specific player's viewpoint, and that you want it to follow the player's view exactly.

And cylab's second approach gets my vote. Just a simple stack of actions that you can move the game back and forward through seems sufficient. Oh yeah, don't forget timestamps.
Offline stef569

Junior Member





« Reply #5 - Posted 2009-03-19 15:51:28 »

That's awesome cylab, you come up with 2 solutions! I had to read them a couple of times to understand what you are saying but I got it now.
Actually storing all these game objects into 1 context object really simplified code on other places as well, think 1 parameter instead of 6...

and Jono you already came to the conclusion, I want to replay from the user perspective, and time is not an issue since it is an tbs, maybe i'll save the turn.
Solved!
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CogWheelz (14 views)
2014-07-30 21:08:39

Riven (21 views)
2014-07-29 18:09:19

Riven (14 views)
2014-07-29 18:08:52

Dwinin (12 views)
2014-07-29 10:59:34

E.R. Fleming (32 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (42 views)
2014-07-24 01:59:36

Riven (42 views)
2014-07-23 21:16:32

Riven (29 views)
2014-07-23 21:07:15

Riven (30 views)
2014-07-23 20:56:16
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!