代码之家  ›  专栏  ›  技术社区  ›  cyber_dave

XNA格斗类游戏动画循环问题

  •  1
  • cyber_dave  · 技术社区  · 15 年前

    我已经在这方面工作了相当长的一段时间,在不同的地方寻找解决方案。我使用了Nick Gravelyn将动画存储到文本文件中的风格,只是增加一个索引来更改帧。我遇到的麻烦是循环动画一次,而且只有一次,但由于某种原因,我知道应该工作的方式不是工作的方式,我认为它会。我一辈子都搞不懂为什么,除非它非常具体地说明XNA是如何工作的。

    这是我的密码:

    private void UpdateAttack(KeyboardState current, KeyboardState last, GameTime gameTime)
            {
               if (current.IsKeyDown(Keys.S) && last.IsKeyUp(Keys.S))
               {
                   neutralStandingKick(gameTime);
               }
            }   
    
            private void neutralStandingKick(GameTime gameTime)
            {
                //timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds; //Framerate control
                //if (timeSinceLastFrame > millisecondsPerFrame) //Framerate control
                //{
                    //timeSinceLastFrame -= millisecondsPerFrame; //Framerate control
                    if (mCurrentState != State.Kicking)
                    {
                        mCurrentState = State.Kicking;
    
                        Position.Y = 200;
    
                        loopOnce(25, 30); //Starts at frame 25, ends at 30
                    }
                //}
            }
    
            private void loopOnce(int min, int max)
            {
                if (currentImageIndex > max || currentImageIndex < min) //Checks to see if index out of range of current animation
                    currentImageIndex = min; //Starts at the beginning of the animation
                for (int i = min; i < max; i++) //Uses the range to determine when to stop
                { currentImageIndex++; } //Increments index each iteration that passes
            }
    

    Edit:这里是这个特殊类的Draw方法

    public void Draw(SpriteBatch spriteBatch)
    {
        //Get the name of the current sprite to draw
        string spriteName = possibleImages[currentImageIndex];
    
        //Use that to get the source rectangle
        Rectangle source = spriteSourceRectangles[spriteName];
    
        //Send rectangle to a function to set the framesize for bounds checking
        getFrameSize(source);
    
        spriteBatch.Draw(theSpriteSheet, Position, source, Color.White);
    }
    
    private void getFrameSize(Rectangle frame)
    {
        frameSize = frame; //For bounds checking
    }
    

    为什么这样不行?

    新代码(加文的建议):

    private void UpdateAttack(KeyboardState current, KeyboardState last, GameTime gameTime)
    {
        const int min = 22;
        const int max = 30;
    
        timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds; //Framerate control
    
               if (current.IsKeyDown(Keys.S) && mCurrentState != State.Kicking)
               {
                   mCurrentState = State.Kicking;
                   currentImageIndex = min;
               }
               if (mCurrentState == State.Kicking)
               {
                   if (timeSinceLastFrame > millisecondsPerFrame) //Framerate control
                   {
                       timeSinceLastFrame -= millisecondsPerFrame; //Framerate control
                       currentImageIndex++;
                   }
               }
               if (currentImageIndex == max)
                   mCurrentState = State.Idle;
    }
    

    调用UpdateAttack的方法:

    public void Update(GameTime theGameTime, Game game)
    {
        KeyboardState aCurrentKeyboardState = Keyboard.GetState();
    
        UpdateMovement(aCurrentKeyboardState);
        UpdateJump(aCurrentKeyboardState);
        UpdateAttack(aCurrentKeyboardState, mPreviousKeyboardState, theGameTime);
        UpdateStageBounds(game);
    
        mPreviousKeyboardState = aCurrentKeyboardState;
    }
    

    它将在按住键盘键“s”时循环播放动画。但它不会像预期的那样在一次按键中循环所有7帧。

    1 回复  |  直到 11 年前
        1
  •  0
  •   Gavin    15 年前

    从我所看到的代码,你张贴将只画你踢动画的最后一帧作为for循环在LoopOnce方法循环所有帧,只画最后一个。这是因为每次更新都会调用draw方法一次。

    XNA首先调用update方法,然后调用draw。因此,在更新方法中,将动画的当前帧设置为“最大帧”(max frame),然后进入“绘制方法”(draw method),然后绘制当前帧,此时是最后一帧。

    要使其工作,您只需为每次要更新的调用将要绘制的帧增加一个。

    private void UpdateAttack(KeyboardState current, KeyboardState last, GameTime gameTime)
            {
               if (current.IsKeyDown(Keys.S) && last.IsKeyUp(Keys.S))
               {
                 mCurrentState =State.Kicking;
                 currentImageIndex=25;
               }
               if(mCurrentState ==State.Kicking)
                   neutralStandingKick(gameTime);              
            }
    
       private void neutralStandingKick(GameTime gameTime)
        {
               currentImageIndex++;
                if(currentImageIndex==30) mCurrentStart = State.SomeOtherState;
        } 
    

    删除“一次绘制”方法。您需要将State.SomeOtherState替换为对象未启动时所处的状态。您可能还想用常量交换硬编码的帧编号。不需要更改绘制方法,此动画才能工作。希望这有帮助。