3
\$\begingroup\$

I want to run a animation until it has gone through all the frames, even when the activation key is no longer held. After the animation is completely finished, it goes back to walking state. I also want to force the animation to finish first before the player can trigger the new animation.

     if (mCurrentState == State.Walking)
        {
            action = "stand";
            Update_Stand(gameTime);

            if (aCurrentKeyboardState.IsKeyDown(Keys.Left) == true)
            {
                action = "run";
                feetPosition.X += MOVE_LEFT;
                effect = SpriteEffects.None;

                Update_Run(gameTime);

            }
            else if (aCurrentKeyboardState.IsKeyDown(Keys.Right) == true)
            {
                action = "run";
                feetPosition.X += MOVE_RIGHT;
                effect = SpriteEffects.FlipHorizontally;

                Update_Run(gameTime);
            }

            if (aCurrentKeyboardState.IsKeyDown(Keys.Z) == true)
            {
                mCurrentState = State.Hitting;
            }
        }

        if (mCurrentState == State.Hitting)
        {
            action = "hit";

            Update_Hit(gameTime);

            mCurrentState = State.Walking;
        }

My Update_Hit(GameTime gameTime) method is something like that.

// Amount of time between frames 
TimeSpan frameInterval_Hit; 
// Time passed since last frame 
TimeSpan nextFrame_Hit; 

 public void Update_Hit(GameTime gameTime)
    {
        // Check if it is a time to progress to the next frame
        if (nextFrame_Hit >= frameInterval_Hit)
        {
            // Progress to the next frame in the row
            currentFrame_Hit.X++;

            // If reached end of the row advance to the next row, reset to the first frame 
            if (currentFrame_Hit.X >= sheetSize_Hit.X)
            {
                currentFrame_Hit.X = 0;
                currentFrame_Hit.Y++;
            }

            // If reached last row in the frame sheet, jump to the first row again
            if (currentFrame_Hit.Y >= sheetSize_Hit.Y)
                currentFrame_Hit.Y = 0;

            // Reset time interval for next frame
            nextFrame_Hit = TimeSpan.Zero;
        }
        else
        {
            // Wait for the next frame
            nextFrame_Hit += gameTime.ElapsedGameTime;
        }
    }
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

A simple generic approach should work. You should really consider making your animations more generic by making them objects, instead of all that hard coding you're doing now. Once you do, add an attribute to your animations and some simple code for handling animations.

Each animation should have a boolean flag indicating if it requires finishing, like your punching animation. Then when a new animation is requested, you can do a simple check:

public void changeAnimation(Animation next) {
    if(currentAnimation.IsPlaying() && currentAnimation.RequiresFinish())
       nextAnimation = next;
    else
       currentAnimation = next;
}

Then, have some code that handles the transition.

private void onAnimationEnd() {
    if(nextAnimation != null) {
        currentAnimation = nextAnimation;
        nextAnimation = null;
    } else {
        currentAnimation = getIdleAnimation();
    }
}

Where currentAnimation and nextAnimation are instances of a animation class. Something like:

class Animation {
    // Amount of time between frames 
    TimeSpan frameInterval; 
    // Time passed since last frame 
    TimeSpan nextFrameInterval; 
    Vec2 currentFrame;
    Vec2 sheetSize;

    public Animation (Vec2 currentFrame, Vec2 sheetSize) {
        this.currentFrame = currentFrame;
        this.sheetSize = sheetSize;
        this.frameInterval = new TimeSpan();
        this.nextFrameInterval = new TimeSpan();
    }

    public void update(GameTime gameTime) {
        // Check if it is a time to progress to the next frame
        if (nextFrameInterval>= frameInterval)
        {
            // Progress to the next frame in the row
            currentFrame.X++;

            if (currentFrame.X >= sheetSize_Hit.X)
            {
                currentFrame.X = 0;
                currentFrame.Y++;
            }

            // If reached last row in the frame sheet, jump to the first row again
            if (currentFrame.Y >= sheetSize.Y)
                currentFrame.Y = 0;

            // Reset time interval for next frame
            nextFrameInterval = TimeSpan.Zero;
        }
        else
        {
            // Wait for the next frame
            nextFrameInterval+= gameTime.ElapsedGameTime;
        }
    }
}

Using an object like this makes it reusable for other animations, instead of just being used for the hit animation. Now when you want to change animations, you can easily just set the currentAnimation to whatever animation object you want, and use all the same code for updating the animation.

\$\endgroup\$
7
  • \$\begingroup\$ Can u show me how does Animation next, nextAnimation and currentAnimation work? \$\endgroup\$
    – optimisez
    Feb 26, 2013 at 0:28
  • \$\begingroup\$ Yes, I've updated the answer. \$\endgroup\$
    – House
    Feb 26, 2013 at 0:42
  • \$\begingroup\$ I still not understand about how public void changeAnimation(Animation next) function works. Why assign next to nextAnimation and currentAnimation and what is the purpose of putting else? \$\endgroup\$
    – optimisez
    Feb 27, 2013 at 23:25
  • \$\begingroup\$ It means that if the current animation is still playing and it's not allowed to be canceled early, then trying to apply a new animation gets applied to next. Otherwise it gets set to the current animation. It's a way of protecting the current animation from being changed if it's still playing. \$\endgroup\$
    – House
    Feb 28, 2013 at 0:07
  • \$\begingroup\$ Sorry. I'm happy to answer questions on the site, but if you want my one on one programming support, I charge by the hour. \$\endgroup\$
    – House
    Feb 28, 2013 at 5:49
1
\$\begingroup\$

You could create a bool variable like so

 bool isPunching = false;

then wrap a an if loop around Update_Hit(gameTime);, and a if not loop around your mCurrentState = "walking";

  if (mCurrentState == State.Hitting)
    {
        action = "hit";
        isPunching = true;

        if (isPunching)
        {
            Update_Hit(gameTime);
        }

        if (!isPunching)
        {
            mCurrentState = State.Walking;
        }
    }

now in your Update_Hit() method, at the end of the loop add a

 isPunching = false;

Hope this helped.

\$\endgroup\$
1
  • \$\begingroup\$ Sorry for my misunderstanding. Question updated. \$\endgroup\$
    – optimisez
    Feb 25, 2013 at 13:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .