XNA Creators Club Online
Page 1 of 1 (6 items)
Sort Posts: Previous Next

Animation not playing all the way through

Last post 7/21/2009 3:51 AM by GlaphanKing. 5 replies.
  • 7/19/2009 8:35 AM

    Animation not playing all the way through

    I have a little problem with some animations. Probably a simple fix but I would like some input on the subject.

    Using the platform kit I am successfully adding shooting and bullets into it with little error. However I am noticing the animations aren't working correctly.

    For example,

    When the player shoots it is supposed to play the entire animation. My animations are set at 64x64. The shooting animation is 8 frames long and the idle animation is 6 frames long.

    Yes as soon as I press the button and let go it plays a fraction of the animation and reverts to the idle. Is there a way for the animation to play all the way and then play the idle?

    Forgive me but its late. I know I know this but its getting to be an annoyance really.
  • 7/19/2009 9:25 AM In reply to

    Re: Animation not playing all the way through

    Well you might want to show us the code, which does not work correct, so we can have a look at it.
  • 7/19/2009 3:41 PM In reply to

    Re: Animation not playing all the way through

    using System; 
    using System.Collections.Generic; 
    using Microsoft.Xna.Framework; 
    using Microsoft.Xna.Framework.Audio; 
    using Microsoft.Xna.Framework.Graphics; 
    using Microsoft.Xna.Framework.Input; 
     
    namespace RushNAttack 
        public enum PlayerDirection 
        { 
            Left, 
            Right 
        } 
        /// <summary> 
        /// Our fearless adventurer! 
        /// </summary> 
        class Player 
        { 
            // Animations 
            private Animation idleAnimation; 
            private Animation runAnimation; 
            private Animation jumpAnimation; 
            private Animation celebrateAnimation; 
            private Animation dieAnimation; 
            private Animation shootAnimation; 
            private SpriteEffects flip = SpriteEffects.None; 
            private AnimationPlayer sprite; 
     
            // Sounds 
            private SoundEffect killedSound; 
            private SoundEffect jumpSound; 
            private SoundEffect fallSound; 
            private SoundEffect shootSound; 
     
            // Handles all the Bullet  stuff 
            public Texture2D bulletTexture; 
            public Bullet bullet; 
            public List<Bullet> playerBullets = new List<Bullet>(); 
            int bulletDelay; 
     
            public Level Level 
            { 
                get { return level; } 
            } 
            Level level; 
     
            public bool IsAlive 
            { 
                get { return isAlive; } 
            } 
            bool isAlive; 
     
            // Physics state 
            public Vector2 Position 
            { 
                get { return position; } 
                set { position = value; } 
            } 
            Vector2 position; 
     
            private float previousBottom; 
     
            public Vector2 Velocity 
            { 
                get { return velocity; } 
                set { velocity = value; } 
            } 
            Vector2 velocity; 
    #if ZUNE 
            // Constants for controling horizontal movement 
            private const float MoveAcceleration = 7000.0f; 
            private const float MaxMoveSpeed = 1000.0f; 
            private const float GroundDragFactor = 0.38f; 
            private const float AirDragFactor = 0.48f; 
     
            // Constants for controlling vertical movement 
            private const float MaxJumpTime = 0.35f; 
            private const float JumpLaunchVelocity = -2000.0f; 
            private const float GravityAcceleration = 1700.0f; 
            private const float MaxFallSpeed = 450.0f; 
            private const float JumpControlPower = 0.13f; 
     
            // Input configuration 
            private const float MoveStickScale = 0.0f; 
            private const Buttons JumpButton = Buttons.B;         
    #else 
            // Constants for controling horizontal movement 
            private const float MoveAcceleration = 14000.0f; 
            private const float MaxMoveSpeed = 2000.0f; 
            private const float GroundDragFactor = 0.58f; 
            private const float AirDragFactor = 0.65f; 
     
            // Constants for controlling vertical movement 
            private const float MaxJumpTime = 0.35f; 
            private const float JumpLaunchVelocity = -4000.0f; 
            private const float GravityAcceleration = 3500.0f; 
            private const float MaxFallSpeed = 600.0f; 
            private const float JumpControlPower = 0.14f; 
     
            // Input configuration 
            private const float MoveStickScale = 1.0f; 
            private const Buttons JumpButton = Buttons.A; 
            private const Buttons ShootButton = Buttons.B; 
    #endif 
     
            /// <summary> 
            /// Gets whether or not the player's feet are on the ground. 
            /// </summary> 
            public bool IsOnGround 
            { 
                get { return isOnGround; } 
            } 
            bool isOnGround; 
     
            /// <summary> 
            /// Current user movement input. 
            /// </summary> 
            private float movement; 
     
            // Current direction the player is facing. 
            private int direction; 
     
            public bool IsShooting 
            { 
                get { return isShooting; } 
            } 
            private bool isShooting; 
     
            // Jumping state 
            private bool isJumping; 
            private bool wasJumping; 
            private float jumpTime; 
     
            private Rectangle localBounds; 
            /// <summary> 
            /// Gets a rectangle which bounds this player in world space. 
            /// </summary> 
            public Rectangle BoundingRectangle 
            { 
                get 
                { 
                    int left = (int)Math.Round(Position.X - sprite.Origin.X) + localBounds.X; 
                    int top = (int)Math.Round(Position.Y - sprite.Origin.Y) + localBounds.Y; 
     
                    return new Rectangle(left, top, localBounds.Width, localBounds.Height); 
                } 
            } 
     
            /// <summary> 
            /// Constructors a new player. 
            /// </summary> 
            public Player(Level level, Vector2 position) 
            { 
                this.level = level; 
     
                LoadContent(); 
     
                Reset(position); 
            } 
     
            /// <summary> 
            /// Loads the player sprite sheet and sounds. 
            /// </summary> 
            public void LoadContent() 
            { 
                // Load animated textures. 
                idleAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/Idle"), 0.2f, true); 
                runAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/Run"), 0.05f, true); 
                jumpAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/Jump"), 0.1f, false); 
                celebrateAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/Celebrate"), 0.1f, false); 
                dieAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/Die"), 0.1f, false); 
                shootAnimation = new Animation(Level.Content.Load<Texture2D>("Sprites/Player/Shoot"), 0.05f, true); 
     
                // Calculate bounds within texture size.             
                int width = (int)(idleAnimation.FrameWidth * 0.4); 
                int left = (idleAnimation.FrameWidth - width) / 2; 
                int height = (int)(idleAnimation.FrameWidth * 0.8); 
                int top = idleAnimation.FrameHeight - height; 
                localBounds = new Rectangle(left, top, width, height); 
     
                // Load sounds.             
                killedSound = Level.Content.Load<SoundEffect>("Sounds/PlayerKilled"); 
                jumpSound = Level.Content.Load<SoundEffect>("Sounds/PlayerJump"); 
                fallSound = Level.Content.Load<SoundEffect>("Sounds/PlayerFall"); 
                shootSound = Level.Content.Load<SoundEffect>("Sounds/Shoot_Beretta"); 
     
                //Load Bullet Textures 
                bulletTexture = Level.Content.Load<Texture2D>("Sprites/Bullet"); 
            } 
     
            /// <summary> 
            /// Resets the player to life. 
            /// </summary> 
            /// <param name="position">The position to come to life at.</param> 
            public void Reset(Vector2 position) 
            { 
                Position = position; 
                Velocity = Vector2.Zero; 
                isAlive = true
                if(!IsShooting) 
                    sprite.PlayAnimation(idleAnimation); 
            } 
     
            /// <summary> 
            /// Handles input, performs physics, and animates the player sprite. 
            /// </summary> 
            public void Update(GameTime gameTime) 
            { 
                GetInput(gameTime); 
     
                ApplyPhysics(gameTime); 
     
                if (IsAlive && IsOnGround) 
                { 
                    if (Math.Abs(Velocity.X) - 0.02f > 0) 
                    { 
                        sprite.PlayAnimation(runAnimation); 
                    } 
                    else 
                    { 
                        if (!IsShooting) 
                        { 
                            sprite.PlayAnimation(idleAnimation); 
                        } 
                        else 
                        { 
                            sprite.PlayAnimation(shootAnimation); 
                        } 
                         
                    } 
                } 
     
                for (int i = 0; i < playerBullets.Count; i++) 
                { 
                    playerBullets[i].Update(gameTime); 
                    if (playerBullets[i].Position.X < -bulletTexture.Width) 
                        playerBullets.RemoveAt(i); 
                } 
     
                // Clear input. 
                movement = 0.0f; 
                isJumping = false
                isShooting = false
            } 
     
            /// <summary> 
            /// Gets player horizontal movement and jump commands from input. 
            /// </summary> 
            private void GetInput(GameTime gameTime) 
            { 
                double elapsedMilliseconds = 
                    gameTime.TotalGameTime.TotalMilliseconds; 
                // Get input state. 
                GamePadState gamePadState = GamePad.GetState(PlayerIndex.One); 
                KeyboardState keyboardState = Keyboard.GetState(); 
     
                // Get analog horizontal movement. 
                movement = gamePadState.ThumbSticks.Left.X * MoveStickScale; 
     
                // Ignore small movements to prevent running in place. 
                if (Math.Abs(movement) < 0.5f) 
                    movement = 0.0f; 
     
                // If any digital horizontal movement input is found, override the analog movement. 
                if (gamePadState.IsButtonDown(Buttons.DPadLeft) || 
                    keyboardState.IsKeyDown(Keys.Left)) 
                { 
                    movement = -1.0f; 
                    direction = (int)PlayerDirection.Left; 
     
                } 
                else if (gamePadState.IsButtonDown(Buttons.DPadRight) || 
                         keyboardState.IsKeyDown(Keys.Right)) 
                { 
                    movement = 1.0f; 
                    direction = (int)PlayerDirection.Right; 
                } 
     
                else if (keyboardState.IsKeyDown(Keys.A) && 
                    gameTime.TotalGameTime.TotalMilliseconds - bulletDelay > 400) 
                { 
                     
                    bulletDelay = (int)gameTime.TotalGameTime.TotalMilliseconds; 
                    bullet = new Bullet(bulletTexture); 
     
                    bullet.Position = new Vector2( 
                        Position.X + shootAnimation.FrameWidth / 2 - bulletTexture.Width / 2, 
                        Position.Y - shootAnimation.FrameHeight / 2); 
     
                    playerBullets.Add(bullet); 
     
                    isShooting = true
                    sprite.PlayAnimation(shootAnimation); 
                } 
     
                else if (keyboardState.IsKeyUp(Keys.A)) 
                { 
                    isShooting = false
                    bulletDelay = 0; 
                } 
     
                // Check if the player wants to jump. 
                isJumping = 
                    gamePadState.IsButtonDown(JumpButton) || 
                    keyboardState.IsKeyDown(Keys.Space); 
            } 
     
            /// <summary> 
            /// Updates the player's velocity and position based on input, gravity, etc. 
            /// </summary> 
            public void ApplyPhysics(GameTime gameTime) 
            { 
                float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; 
     
                Vector2 previousPosition = Position; 
     
                // Base velocity is a combination of horizontal movement control and 
                // acceleration downward due to gravity. 
                velocity.X += movement * MoveAcceleration * elapsed; 
                velocity.Y = MathHelper.Clamp(velocity.Y + GravityAcceleration * elapsed, -MaxFallSpeed, MaxFallSpeed); 
     
                velocity.Y = DoJump(velocity.Y, gameTime); 
     
                // Apply pseudo-drag horizontally. 
                if (IsOnGround) 
                    velocity.X *= GroundDragFactor; 
                else 
                    velocity.X *= AirDragFactor; 
     
                // Prevent the player from running faster than his top speed.             
                velocity.X = MathHelper.Clamp(velocity.X, -MaxMoveSpeed, MaxMoveSpeed); 
     
                // Apply velocity. 
                Position += velocity * elapsed; 
                Position = new Vector2((float)Math.Round(Position.X), (float)Math.Round(Position.Y)); 
     
                // If the player is now colliding with the level, separate them. 
                HandleCollisions(); 
     
                // If the collision stopped us from moving, reset the velocity to zero. 
                if (Position.X == previousPosition.X) 
                    velocity.X = 0; 
     
                if (Position.Y == previousPosition.Y) 
                    velocity.Y = 0; 
            } 
     
     
            /// <summary> 
            /// Calculates the Y velocity accounting for jumping and 
            /// animates accordingly. 
            /// </summary> 
            /// <remarks> 
            /// During the accent of a jump, the Y velocity is completely 
            /// overridden by a power curve. During the decent, gravity takes 
            /// over. The jump velocity is controlled by the jumpTime field 
            /// which measures time into the accent of the current jump. 
            /// </remarks> 
            /// <param name="velocityY"> 
            /// The player's current velocity along the Y axis. 
            /// </param> 
            /// <returns> 
            /// A new Y velocity if beginning or continuing a jump. 
            /// Otherwise, the existing Y velocity. 
            /// </returns> 
            private float DoJump(float velocityY, GameTime gameTime) 
            { 
                // If the player wants to jump 
                if (isJumping) 
                { 
                    // Begin or continue a jump 
                    if ((!wasJumping && IsOnGround) || jumpTime > 0.0f) 
                    { 
                        if (jumpTime == 0.0f) 
                            jumpSound.Play(); 
     
                        jumpTime += (float)gameTime.ElapsedGameTime.TotalSeconds; 
                        sprite.PlayAnimation(jumpAnimation); 
                    } 
     
                    // If we are in the ascent of the jump 
                    if (0.0f < jumpTime && jumpTime <= MaxJumpTime) 
                    { 
                        // Fully override the vertical velocity with a power curve that gives players more control over the top of the jump 
                        velocityY = JumpLaunchVelocity * (1.0f - (float)Math.Pow(jumpTime / MaxJumpTime, JumpControlPower)); 
                    } 
                    else 
                    { 
                        // Reached the apex of the jump 
                        jumpTime = 0.0f; 
                    } 
                } 
                else 
                { 
                    // Continues not jumping or cancels a jump in progress 
                    jumpTime = 0.0f; 
                } 
                wasJumping = isJumping; 
     
                return velocityY; 
            } 
     
            /// <summary> 
            /// Detects and resolves all collisions between the player and his neighboring 
            /// tiles. When a collision is detected, the player is pushed away along one 
            /// axis to prevent overlapping. There is some special logic for the Y axis to 
            /// handle platforms which behave differently depending on direction of movement. 
            /// </summary> 
            private void HandleCollisions() 
            { 
                // Get the player's bounding rectangle and find neighboring tiles. 
                Rectangle bounds = BoundingRectangle; 
                int leftTile = (int)Math.Floor((float)bounds.Left / Tile.Width); 
                int rightTile = (int)Math.Ceiling(((float)bounds.Right / Tile.Width)) - 1; 
                int topTile = (int)Math.Floor((float)bounds.Top / Tile.Height); 
                int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / Tile.Height)) - 1; 
     
                // Reset flag to search for ground collision. 
                isOnGround = false
     
                // For each potentially colliding tile, 
                for (int y = topTile; y <= bottomTile; ++y) 
                { 
                    for (int x = leftTile; x <= rightTile; ++x) 
                    { 
                        // If this tile is collidable, 
                        TileCollision collision = Level.GetCollision(x, y); 
                        if (collision != TileCollision.Passable) 
                        { 
                            // Determine collision depth (with direction) and magnitude. 
                            Rectangle tileBounds = Level.GetBounds(x, y); 
                            Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds); 
                            if (depth != Vector2.Zero) 
                            { 
                                float absDepthX = Math.Abs(depth.X); 
                                float absDepthY = Math.Abs(depth.Y); 
     
                                // Resolve the collision along the shallow axis. 
                                if (absDepthY < absDepthX || collision == TileCollision.Platform) 
                                { 
                                    // If we crossed the top of a tile, we are on the ground. 
                                    if (previousBottom <= tileBounds.Top) 
                                        isOnGround = true
     
                                    // Ignore platforms, unless we are on the ground. 
                                    if (collision == TileCollision.Impassable || IsOnGround) 
                                    { 
                                        // Resolve the collision along the Y axis. 
                                        Position = new Vector2(Position.X, Position.Y + depth.Y); 
     
                                        // Perform further collisions with the new bounds. 
                                        bounds = BoundingRectangle; 
                                    } 
                                } 
                                else if (collision == TileCollision.Impassable) // Ignore platforms. 
                                { 
                                    // Resolve the collision along the X axis. 
                                    Position = new Vector2(Position.X + depth.X, Position.Y); 
     
                                    // Perform further collisions with the new bounds. 
                                    bounds = BoundingRectangle; 
                                } 
                            } 
                        } 
                    } 
                } 
     
                // Save the new bounds bottom. 
                previousBottom = bounds.Bottom; 
            } 
     
            /// <summary> 
            /// Called when the player has been killed. 
            /// </summary> 
            /// <param name="killedBy"> 
            /// The enemy who killed the player. This parameter is null if the player was 
            /// not killed by an enemy (fell into a hole). 
            /// </param> 
            public void OnKilled(Enemy killedBy) 
            { 
                isAlive = false
     
                if (killedBy != null
                    killedSound.Play(); 
                else 
                    fallSound.Play(); 
     
                sprite.PlayAnimation(dieAnimation); 
            } 
     
            /// <summary> 
            /// Called when this player reaches the level's exit. 
            /// </summary> 
            public void OnReachedExit() 
            { 
                sprite.PlayAnimation(celebrateAnimation); 
            } 
     
            /// <summary> 
            /// Draws the animated player. 
            /// </summary> 
            public void Draw(GameTime gameTime, SpriteBatch spriteBatch) 
            { 
                // Flip the sprite to face the way we are moving. 
                if (Velocity.X < 0) 
                    flip = SpriteEffects.FlipHorizontally; 
                else if (Velocity.X > 0) 
                    flip = SpriteEffects.None; 
     
                // Draw that sprite. 
                sprite.Draw(gameTime, spriteBatch, Position, flip); 
     
     
                foreach (Bullet playerBullet in playerBullets) 
                    playerBullet.Draw(spriteBatch); 
            } 
        } 
     
    I took the bullet class from the Object Oriented Programming Tutorial on Ziggyware. But I don't think its the bullet class that is the problem. It lies somewhere in the code.

    Sorry for posting the whole thing but I had to be thorough.
  • 7/19/2009 4:39 PM In reply to

    Re: Animation not playing all the way through

    You set isShooting to false at the bottom of each update call. Yet you try to use isShooting to figure out what animation to play.
    Typically, you will want two separate states: One for what the character is doing, gameplay-wise ("spawning a bullet"), and one for what is currently rendered ("playing shooting animation.")
    When spawning a bullet, you spawn a bullet and go back to doing nothing, but you also set the current animation to "shooting." The current animation should stay whatever it is until it has played out, and then switch back to idle (or movement, or whatever).
    Typically, it looks like:

    1) Update character controls
    2) Update character state machine based on controls
    3) Update character animation state machine
    4) Render character based on animation state machine
    Jon Watte, Direct3D MVP
    Tweets, occasionally
    kW X-port 3ds Max .X exporter
    kW Animation source code
  • 7/19/2009 11:23 PM In reply to

    Re: Animation not playing all the way through

    So in your opinion, what would be the best way to achieve this procedure?

    I read what you said, but putting it to use is a little fuzzy for me.
  • 7/21/2009 3:51 AM In reply to

    Re: Animation not playing all the way through

    I also noticed something odd. If I just put in the animation without adding in the bullet code, it plays fine. When I add in the bullet code it plays a fraction of it. Still bugging me.
Page 1 of 1 (6 items) Previous Next
var gDomain='m.webtrends.com'; var gDcsId='dcschd84w10000w4lw9hcqmsz_8n3x'; var gTrackEvents=1; var gFpc='WT_FPC'; /*<\/scr"+"ipt>");} /*]]>*/
DCSIMG