Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Please stay with me as I explain my question.

I'm creating a multiplayer game. My design pattern follows broadly thoughts described in the post here.

The idea is that each actor whether be it a (local) player or a npc does what a GameAction attached to this actor tells it to do. These GameActions are obtained by reacting to a received GameEvent. This enables only sending GameEvents through network and each client logic will obtain own GameActions for e.g. moving local copies of remote players themselves and also getting sanity checks from time to time.

How should these actions be composed then? Who takes responsibility stopping actions?

My problem right now is that if a LocalInputHandler produces on keyDown() a CHARACTER_INPUT event it will be delivered to and consumed by a parent node the local player is living in. The parent node obtains a CHARACTER_MOVE GameAction and attaches it to the specific local player. On update() the player/character excecutes the GameAction. It moves, by itself. Like a small script interpreter. Isn't that awesome? No it isn't because if I didn't release the button (aka holding it) no new CHARACTER_INPUT will be emitted and the player excecuted it's action and nothing happens.

To solve this problem I came up with 6 classifications or types of GameActions:

  • Unstoppable - loops forever, can only be stopped by itself
  • OneTimeLooper - loops until getting stopped, always finishes task before getting interrupted
  • Looper - loops until getting stopped, can be interrupted any time
  • OneTimer - performs action only once and can't be interrupted while doing it
  • WeakWorker - Performs action once but can always be interrupted
  • Stopper - AntiAction: interrupts all types except unstoppables. Is a OneTimer

This would lead having a CHARACTER_MOVE action be a OneTimeLooper. It moves the attached actor until a CHARACTER_MOVE_STOP action tells it to do, being created because of an event originating from a keyUp() call.

But this solution smells bad to me, because then each Character/Actor/Player has to have more than one GameAction it can hold to. A Stopper must have access to it's counterpart to know if it is allowed to stop. Also shouldn't higher order classes like parent nodes have the power to stop an GameAction since they also created them? Why not give LocalInputHandler power? How to change input style if you have a menu opened on top of the screen representing everything that happens in your world?


Clarifications and optional text:

LocalInputHandler and localPlayer are coupled by handing over LocalInputHandler the ID (represented by UUIDs, which I'm still not sure using because they are so big for networking applications) of localPlayer in construction. Each InputHandler whether be it a remote or ai InputHandler will only now by ID which actor they are handling and will refer to this ID when creating a CHARACTER_INPUT event by writing recepient = actorID into the event. The message of this event is a int[] keymap which holds information about which key is held down. keymap is a member variable of a InputHandler It could be a boolean[] but for now it's an int[] array. Parentnode of an actor takes these informations (recepientID and keymap) and packs a CHARACTER_MOVE GameAction into the event passing it down to the actor for consumption. In this process the keymap is being copied by calling .copy()on keymap because this will prevent opening a channel of direct communication from the InputHandler to the GameAction by not letting it just copy a reference but the array as a whole.

share|improve this question
    
Have you considered FSM or variants like HSM, or did I misread and all these actions feed into your machine? –  Patrick Hughes Jul 4 '13 at 17:18
    
Sorry, I don't understand what you mean. –  Alex Goldstein Jul 4 '13 at 17:47
add comment

1 Answer 1

up vote 3 down vote accepted

Your GameActions and GameEvents are a pretty classic Finite State Machine (FSM). But not quite yet. An FSM is neatly described by what each state (action) does and exactly what inputs (events) produce a new state as output. It helps when faced with structural problems like this to keep interaction in precise terms.

Note that a game character will typically have a lot of states that it can go into but always only one current state that it is in, which implies a lot of input types to the FSM to change states. An example would be "Idle" changing to "Walk" when the "Idle" state sees a movement_key_press event, at some point later this "Walk" state sees a movement_key_release and changes to "Idle."

Your engine is producing a lot of different inputs: time, key events, world events like collison, movement speed, getting hit for damage, etc... And your single active GameAction in your FSM should consume these and react only to the ones it's interested in to change to another GameAction (like the idle->walk->idle states above).

HSM (hierarchical state machine) is just an elaboration on FSM which you may find useful once your designs become more advanced.

So in answer to what I think your question is: it's OK for a character to have a large number of states it can get into, as long as there's a clean organization like FSM/HSM to handle what it's currently doing. This is why commercial component systems have a big "character controller component" instead of a bunch of little components flying around.

Current actions are responsible for stopping themselves based on inputs, the outside world only knows that it's feeding your FSM input and only the current action in the FSM knows what that input means. Most accurately it's not the action stopping itself, it's the action telling the FSM to change to another action in one, big and endless cycle.

Your list of action types is very good, you can use those as a pattern to build your individual states from.

While this may sound like a lot of responsibility to cram into a simple component, remember that this component is only handling one thing (character state) and trying to break it up further would most likely result in a big mess.

share|improve this answer
    
Thank you for your sophisticated answer, I've never heard of FSM/HSM. The key lacking here was exactly what you said - the GameAction needs to consume events itself. I've changed it so that keyDown()and keyUp()create only KEY_UP and KEY_DOWN events with message being the actual key pressed. The GameAction/FSM CHARACTER_MOVE is now entity's master and is therefore also allowed to read events which are sent to entity. Based on input CHARACTER_MOVE will flag itself to finished = trueand will then be taken away from entity by parent node. You're brilliant. –  Alex Goldstein Jul 4 '13 at 22:49
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.