Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

1 decade ago by drhayes

Here's the project on GitHub.

I got tired of the cascade of if-then-else that was showing up in my code, particuarly around animations (e.g. if player just crouched but hasn't finished the crouching animation and isn't crawling yet then show the "crouching" animation unless the player is blah blah blah), so I made this library.

Now I can do things like have a "crouching" state that doesn't transition to a "crouched" state until the animation is done and handles all the corner cases. It also lets me separate the animation logic from the movement logic in my entities so that they respond to velocity changes without explicit animation code.

Let me know if anything isn't clear or if it's missing some feature or other that you might find useful.

1 decade ago by Neeko

Once again drhayes, you've saved me from having to create some fairly standard boilerplate code! Thanks for posting your state machine implementation.

1 decade ago by drhayes

Glad to hear it. I'm going on the theory that more open source code means more, better games. ( =

1 decade ago by graph1ZzLle

Hey,

Just wanted to say thank you for this state machine, I turned it into a class for my project and I made it works like a charm. This has really helped me as I was going to write one :D

1 decade ago by stahlmanDesign

This sounds great and I'm going to try it out.

In my own project I came up with a different solution. Instead of all the complex code for managing animation and states, I created 4 different player entities:

1) normal (jump n' run)
2) swimming (different size, different sprites, different collision, breath meter etc.)
3) crouching (different size, pushing up stands up instead of climbing or jumping)
4) climbing (no gravity, different collision etc., ladder logic, etc.)

When transitioning from say, normal to climbing, I spawn playerClimbing and .kill() playerNormal. The effect is seamless. But you have to hold your player stats and inventory, health and everything in main.js instead of in player.js

This way, each state has simple code, and I think there are far fewer calculations than having a state machine or lots of complex exceptions.

But if your state machine is as well thought out as your event chain, then it's probably worth a try.

1 decade ago by drhayes

Yeah, you are totally right. I'm doing the same thing in my RPGish game: I made a swapEntity method that looks like this:

swapEntity: function(entityName, settings)

It works way better for managing complex interactions and makes a very clean design than a big tangle of if/then/else or a state machine. ( =

When my EntityPlayer's velocity exceeds a certain threshold I swapEntity into the EntityPlayerFallingDeath. Since the camera is set up to track entities of type EntityPlayer, the camera slides to a stop as the player falls off the screen at the bottom.

Same thing with EnitiyPlayerDying: when the player does something that kills them I swapEntity to EntityPlayerDying. When its animation is done I kill the entity and call a method on my game to spawn the player at the last checkpoint.

I made the state machine mostly for animation transitions (idle to walking to jumping to landing to idle, idle to crouching to crouched to hiding to standing to idle, etc). I'm experimenting with using it for enemy AI but if it gets too complicated I'm going to use the multiple entity approach like you did.

1 decade ago by Neeko

Quote from drhayes
Glad to hear it. I'm going on the theory that more open source code means more, better games. ( =


That's very sound logic! I agree, and why most of my games are always on GitHub.

1 decade ago by MoArtis

Thanks drhayes!

I tried to use your stateMachine library today but I wasn't able to figure out how to change the current state.

I feel really stupid because I read your entire code and its documentation several times but I wasn't able to use it...

Could you provide some examples to illustrate how to use your library?

Thanks again.

1 decade ago by drhayes

@MoArtis: Don't feel stupid; it's my job to make my stuff understandable. ( =

I didn't make it explicit in the documentation, but it's the transitions that change the current state. Here's the call to add a transition:

transition('transitionName', 'fromStateName', 'toStateName', function() {})

Let's say you have this code:

this.ghostAI = new StateMachine();

var self = this; // Needed because you lose this in callbacks.

this.ghostAI.state('chasing', {
  enter: function() { self.currentAnim = self.anims.chasing; },
  update: function() { console.log('chasing'); }
});

this.ghostAI.state('running', {
  enter: function() { self.currentAnim = self.anims.turnBlue; }, 
  update: function() { console.log('running'); }
});

The first state that you add is the initial state, set for you automatically. So the ghostAI state machine is going to be in state chasing at first.

Here are the transitions:

ghostAI.transition('getScared', 'chasing', 'running', function() {
  return player.justAtePowerPellet();
});

ghostAI.transition('getBrave', 'running', 'chasing', function() {
  // Time given in seconds.
  return player.powerPelletElapsed > 5;
});

Then, in your EntityGhost's update method, you would call:

update: function() {
// ... other update stuff...
  this.ghostAI.update();
}

Every time you call ghostAI.update() the state machine executes the update method of the current state. Initially, that's chasing. The first time through the state machine will call enter on state chasing which will set the current animation to chasing and then start logging 'chasing' to the console (your real AI would go there, of course).

After the state machine calls the state's update method, it checks every transition out of the current chasing state and calls the transition's function. If the transition's function returns true then the state will change to the new state. In our example, if the player just ate a power pellet then the getScared transition will run, changing the current state from chasing to running.

That will call running's enter method, changing the animation to turnBlue... and on and on.

Each state can have multiple transitions into and out of it. I just realized that the order the transitions are checked isn't well defined in the code, so try to make your transitions not depend on the order they're called in.

Does that make sense?

1 decade ago by m1neral

Just wanted to thank you for this.

I've just translated my ugly nested if/else update method into a beautiful & clean state machine. Wow.
Page 1 of 1
« first « previous next › last »