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.

I'm developing a game where the player changes states as their health decreases. Below 50, it should trigger animation1. Below 30, it should trigger animation2.

The problem is, I only want to trigger animation1 once. But my game timer is checking every "frame", so it's triggering animation1 every cycle below 50. I only want it to trigger once, then not again until it's gone over 50 and then naturally decreased back to below 50.

Are there any tried and true strategies for triggering state changes as a timer counts down (without the over-triggering problem)?

I thought I could say:

if (health == 50)
 animation1.play();

but sometimes, health never equals exactly 50, so it will skip right past that statement.

share|improve this question
add comment

3 Answers

up vote 2 down vote accepted

Really, this comes down to your given implementation of game-logic.
There's nothing in particular that is right or wrong, here.

Personally, I'd be using some sort of event-driven system (like a Moderator/Publisher+Subscriber), inside of my player/enemy/vehicle, and using components like a health component and an animation component.

Inside of a takeDamage method, I might do my regular health stuff, and while doing the regular checks (ie: not dead), add in one additional set of checks to see if that particular instance passed a "pain threshold".

In an enumerator or an array or any other way you're going to store your states, you might do a check like:

if (this.current_health > pain_threshold_1 &&
    this.current_health - damage_amount < pain_threshold_1) {
    this.mediator.notify("player_state_change", "hurt");
}

The animation module would be listening for the "player_state_change" event, and would change the current animation.

The opposite check could be added to an addHealth method.

This might be overkill for a Pong-clone...

share|improve this answer
    
Ha- Not overkill for me- Sounds like a good idea. Hadn't thought of the publisher/subscriber method, but that's exactly the kind of general idea I was hoping to find. Thanks for the idea- Cheers! –  Hairgami_Master Nov 26 '12 at 18:56
add comment

If you use a flag to track whether your threshold has been crossed, and another to indicate whether you should play the animation in the current frame, you can do what you're trying to accomplish. If you start out like this:

// start of program
bool play_animation1 = false;
bool greater_than_50 = true;

Then in your game's loop do this every frame:

// game loop
if(health <= 50){
    if(greater_than_50){
        play_animation1 = true;
        greater_than_50 = false;
    }
}
else if(health > 50){
    greater_than_50 = true;
}

...

// animations
if(play_animation1){ 
    // animation1.play() is called ONCE:
    // play_animation1 = false; 
    animation1.play();
}

...

// cleanup
if(animation1.over()){
    // animation1.play() is called CONTINUOUSLY:
    play_animation1 = false;
}

So going into the game loop, if play_animation1 and greater_than_50 start false and true, respectively. Their values then both invert, and the animation starts playing. When the animation is finished, the play_animation1 flag is set to false. They'll now both stay false until the player's health rises above 50, and then the process is able to repeat. The flags should probably be private members of your player class, if that's applicable.

share|improve this answer
    
That sounds like a good solution, Eric- thanks! I'll wait here a few more hours and see if there's something else that works. Cheers –  Hairgami_Master Nov 24 '12 at 16:21
    
The code as written has serious issues - it will try to call animation1.play() every tick until that animation is over! Ideally this won't be a problem, depending on how the Animation::play() method is written, but in practice it could be a legitimate issue. With this approach you probably want to smack play_animation1 to false in the same code that plays the animation. –  Steven Stadnicki Nov 26 '12 at 7:36
    
@StevenStadnicki I assumed that was the intention, but I edited the answer a bit just in case. –  Eric B Nov 26 '12 at 15:45
add comment

What Eric has suggested to you is basically a FSM implementation without the framework. If you find yourself in a situation where you often need actions to occur when state is changing, implementing (or using) a FSM framework is a good idea. Given the right setup then you would simply run the update method on your state machine, and it would trigger the actions you would need per the state in your application.

You could also implement a TrueOnce object that takes a predicate that is checked each frame. In pseudo/c#:

//given TrueOnce playAnimation1 = new TrueOnce(()=>health<=50);
if (playAnimation1.isTrue()) {
    //play the animation
}

This uses a lambda function, I could help you write an implementation if you tell me what language you're using.

The other thing you could do if this is not likely to become a pattern and you just want something quick that works, try this:

//given animation1 and animation2 are global variables initialized to null
if (health<=50 && animation1==null) {
    animation1= new Animation1(); //whatever
    animation1.play();
} else if (health<=30 && animation2==null) {
    animation2= new Animation2(); //whatever
    animation2.play();
} 
share|improve this answer
    
Many thanks- I think the Finite State Machine was the term I was looking for, though Googling FSM brings up to many overly complex concepts for my humble gaming brain. I normally code in C#, though this game is unfortunately in Flash (not my choice). I like the lambda solution- very cool. –  Hairgami_Master Nov 26 '12 at 19:26
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.