2013-02-27 57 views
0

我知道爲什麼每次我調用Update_Animation(Point sheetSize,TimeSpan frameInterval,GameTime gameTime)函數時,精靈動畫的速度變得更快。這是由gameTime造成的嗎?如何解決它?謝謝。如何避免混合不同的精靈動畫速度?

class Character 
{ 
    #region Field 
    // Character file 
    System.Xml.Linq.XDocument doc; 

    // The texture with animation frames 
    Texture2D animationTexture_Stand; 
    Texture2D animationTexture_Run; 
    Texture2D animationTexture_Hit; 

    // The size of single frame inside the animationTexture 
    public Point frameSize_Stand; 
    public Point frameSize_Run; 
    public Point frameSize_Hit; 

    // The size and structure of whole frames sheet in animationTexture. The animationTexture could 
    // hold animaton sequence organized in multiple rows and multiple columns. 
    Point sheetSize_Stand; 
    Point sheetSize_Run; 
    Point sheetSize_Hit; 

    // Amount of time between frames 
    TimeSpan frameInterval_Stand; 
    TimeSpan frameInterval_Run; 
    TimeSpan frameInterval_Hit; 
    #endregion 

    #region Initialization 
    /// <summary> 
    /// Constructor of a character class 
    /// </summary> 
    /// <param name="characterName">the name of the xml file of the character without .xml</param> 
    /// <param name="content">ContentManager instance</param> 
    public Character(String characterName, ContentManager content) 
    { 
     doc = System.Xml.Linq.XDocument.Load("Content/" + "Player/" + characterName + ".xml"); 

     // Get the first sprite info from the XML definition 
     var stand = doc.Root.Element("stand"); 
     var run = doc.Root.Element("run"); 
     var hit = doc.Root.Element("hit"); 

     animationTexture_Stand = content.Load<Texture2D>(stand.Attribute("SheetName").Value); 
     animationTexture_Run = content.Load<Texture2D>(run.Attribute("SheetName").Value); 
     animationTexture_Hit = content.Load<Texture2D>(hit.Attribute("SheetName").Value); 

     frameSize_Stand = new Point(); 
     frameSize_Stand.X = int.Parse(stand.Attribute("FrameWidth").Value, NumberStyles.Integer); 
     frameSize_Stand.Y = int.Parse(stand.Attribute("FrameHeight").Value, NumberStyles.Integer); 
     frameSize_Run = new Point(); 
     frameSize_Run.X = int.Parse(run.Attribute("FrameWidth").Value, NumberStyles.Integer); 
     frameSize_Run.Y = int.Parse(run.Attribute("FrameHeight").Value, NumberStyles.Integer); 
     frameSize_Hit = new Point(); 
     frameSize_Hit.X = int.Parse(hit.Attribute("FrameWidth").Value, NumberStyles.Integer); 
     frameSize_Hit.Y = int.Parse(hit.Attribute("FrameHeight").Value, NumberStyles.Integer); 

     sheetSize_Stand = new Point(); 
     sheetSize_Stand.X = int.Parse(stand.Attribute("SheetColumns").Value, NumberStyles.Integer); 
     sheetSize_Stand.Y = int.Parse(stand.Attribute("SheetRows").Value, NumberStyles.Integer); 
     sheetSize_Run = new Point(); 
     sheetSize_Run.X = int.Parse(run.Attribute("SheetColumns").Value, NumberStyles.Integer); 
     sheetSize_Run.Y = int.Parse(run.Attribute("SheetRows").Value, NumberStyles.Integer); 
     sheetSize_Hit = new Point(); 
     sheetSize_Hit.X = int.Parse(hit.Attribute("SheetColumns").Value, NumberStyles.Integer); 
     sheetSize_Hit.Y = int.Parse(hit.Attribute("SheetRows").Value, NumberStyles.Integer); 

     frameInterval_Stand = TimeSpan.FromSeconds(1.0f/int.Parse(stand.Attribute("Speed").Value, NumberStyles.Integer)); 
     frameInterval_Run = TimeSpan.FromSeconds(1.0f/int.Parse(run.Attribute("Speed").Value, NumberStyles.Integer)); 
     frameInterval_Hit = TimeSpan.FromSeconds(1.0f/int.Parse(hit.Attribute("Speed").Value, NumberStyles.Integer)); 

    } 
    #endregion 

    #region Update Animation 
    TimeSpan nextFrame; 
    Point currentFrame; 

    public void Update_Animation(Point sheetSize, TimeSpan frameInterval, GameTime gameTime) 
    { 
     if (nextFrame >= frameInterval) 
     { 
      currentFrame.X++; 

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

      if (currentFrame.Y >= sheetSize.Y) 
       currentFrame.Y = 0; 

      nextFrame = TimeSpan.Zero; 
     } 
     else 
     { 
      nextFrame += gameTime.ElapsedGameTime; 
     } 
    } 
    #endregion 

    #region Update Control 
    KeyboardState mPreviousKeyboardState; 

    String action; 
    SpriteEffects effect = SpriteEffects.FlipHorizontally; 

    Vector2 feetPosition = new Vector2(0, 450); 
    Vector2 mSpeed = Vector2.Zero; 
    Vector2 mDirection = Vector2.Zero; 
    Vector2 mStartingPosition = Vector2.Zero; 

    int CHARACTER_SPEED = 50; 
    int MOVE_LEFT = -5; 
    int MOVE_RIGHT = 5; 
    int MOVE_UP = -5; 
    int MOVE_DOWN = 5; 


    enum State 
    { 
     Walking, 
     Jumping, 
     Hitting, 
    } 

    State mCurrentState = State.Walking; 

    public void UpdateControl(GameTime gameTime) 
    { 
     KeyboardState aCurrentKeyboardState = Keyboard.GetState(); 

     feetPosition += mDirection * mSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds; 
     UpdateMovement(aCurrentKeyboardState, gameTime); 
     UpdateJump(aCurrentKeyboardState, gameTime); 

     mPreviousKeyboardState = aCurrentKeyboardState; 
    } 

    private void UpdateMovement(KeyboardState aCurrentKeyboardState, GameTime gameTime) 
    { 
     if (mCurrentState == State.Walking) 
     { 
      action = "stand"; 
      Update_Animation(sheetSize_Stand, frameInterval_Stand, gameTime); 

      mSpeed = Vector2.Zero; 
      mDirection = Vector2.Zero; 

      if (aCurrentKeyboardState.IsKeyDown(Keys.Left) && !aCurrentKeyboardState.IsKeyDown(Keys.Right)) 
      { 
       action = "run"; 
       effect = SpriteEffects.None; 

       mSpeed.X = CHARACTER_SPEED; 
       mDirection.X = MOVE_LEFT; 

       Update_Animation(sheetSize_Run, frameInterval_Run, gameTime); 
      } 
      else if (aCurrentKeyboardState.IsKeyDown(Keys.Right) && !aCurrentKeyboardState.IsKeyDown(Keys.Left)) 
      { 
       action = "run"; 
       effect = SpriteEffects.FlipHorizontally; 

       mSpeed.X = CHARACTER_SPEED; 
       mDirection.X = MOVE_RIGHT; 

       Update_Animation(sheetSize_Run, frameInterval_Run, gameTime); 
      } 

      if (aCurrentKeyboardState.IsKeyDown(Keys.Z) && mPreviousKeyboardState.IsKeyUp(Keys.Z)) 
      { 
       mCurrentState = State.Hitting; 
      } 
     } 

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

      Update_Animation(sheetSize_Hit, frameInterval_Hit, gameTime); 
      mCurrentState = State.Walking; 
     } 
    } 

    private void UpdateJump(KeyboardState aCurrentKeyboardState, GameTime gameTime) 
    { 
     if (mCurrentState == State.Walking) 
     { 
      if (aCurrentKeyboardState.IsKeyDown(Keys.Up) && mPreviousKeyboardState.IsKeyUp(Keys.Up)) 
       Jump(); 
     } 

     if (mCurrentState == State.Jumping) 
     { 
      if (mStartingPosition.Y - feetPosition.Y > 150) 
       mDirection.Y = MOVE_DOWN; 

      if (feetPosition.Y > mStartingPosition.Y) 
      { 
       feetPosition.Y = mStartingPosition.Y; 
       mCurrentState = State.Walking; 
       mDirection = Vector2.Zero; 
      } 
     } 
    } 

    private void Jump() 
    { 
     if (mCurrentState != State.Jumping) 
     { 
      mCurrentState = State.Jumping; 
      mStartingPosition = feetPosition; 
      mDirection.Y = MOVE_UP; 
      mSpeed = new Vector2(CHARACTER_SPEED, CHARACTER_SPEED); 
     } 
    } 

    #endregion 

    #region Draw Animation 
    Texture2D animationTexture; 
    Point frameSize; 

    /// <summary> 
    /// Rendering of the animation 
    /// </summary> 
    /// <param name="spriteBatch">SpriteBatch in which current frame will be rendered</param> 
    /// <param name="position">The position of the current frame</param> 
    /// <param name="scale">Scale factor to apply on the current frame</param> 
    /// <param name="spriteEffect">SpriteEffect to apply on the current frame</param> 
    public void Draw_Animation(SpriteBatch spriteBatch) 
    { 
     if (action == "stand") 
     { 
      Assign_Sprite(animationTexture_Stand, frameSize_Stand); 
      Draw_Action(spriteBatch, feetPosition, 1.0f, effect); 
     } 
     else if (action == "run") 
     { 
      Assign_Sprite(animationTexture_Run, frameSize_Run); 
      Draw_Action(spriteBatch, feetPosition, 1.0f, effect); 
     } 
     else if (action == "hit") 
     { 
      Assign_Sprite(animationTexture_Hit, frameSize_Hit); 
      Draw_Action(spriteBatch, feetPosition, 1.0f, effect); 
     } 

    } 

    private void Assign_Sprite(Texture2D assignAnimationTexture, Point assignFrameSize) 
    { 
     animationTexture = assignAnimationTexture; 
     //currentFrame = AssignCurrentFrame; 
     frameSize = assignFrameSize; 
    } 

    private void Draw_Action(SpriteBatch spriteBatch, Vector2 position, float scale, SpriteEffects spriteEffect) 
    { 
     spriteBatch.Draw(animationTexture, position - new Vector2(0, frameSize.Y), new Rectangle(
      frameSize.X * currentFrame.X, 
      frameSize.Y * currentFrame.Y, 
      frameSize.X, 
      frameSize.Y), 
      Color.White, 0f, Vector2.Zero, scale, spriteEffect, 0); 
    } 
    #endregion 
} 
+0

這是一種不必要的複雜動畫邏輯。試試微軟官方教程中更簡單的版本:http://xbox.create.msdn.com/en-US/education/tutorial/2dgame/getting_started – user1306322 2013-02-27 11:55:06

回答

1

我不知道如果是這樣的問題,但是這個代碼是關於我:

if (nextFrame >= frameInterval) 
{ 
    //Blah blah 

    nextFrame = TimeSpan.Zero; 
} 

如果gameTime.ElapsedGameTime不規整(如果你的遊戲是有性能問題),這種方法不會正確計時。相反,你應該嘗試:

while (nextFrame >= frameInterval) 
{ 
    //Blah blah 

    nextFrame -= frameInterval; 
} 

因此會有一定的時間「遺留」在nextFrame,所以下一個動畫會在合適的時間。

但是,由於您的問題不是很清楚,我不確定這是否能真正解決您的問題。