龙骨在多次播放的时候很大概率丢帧

近期在做些和龙骨帧事件先关的业务逻辑,发现丢帧很严重,设定播放次数为10,有3次以上出现了丢帧。查看源码看到发现获取当前帧索引的方式是这样的

神奇吧,这样的获取方式,可以说是必然会出现丢帧现象,游戏设置的帧率越高,这个丢帧就会越明显。简单的修改就是去保存当前帧索引preFrameIndex,下一次计算当前帧curFrameIndex的时候,比对,如果出现curFrameIndex-preFrameIndex > 1就说明丢帧,把丢的帧在这里补回就可以了。但只是简单的临时措施,望大佬有全面修复这个问题的大招。

以下代码替换整个update即可
void AnimationTimelineState::update(float time)
{
const auto prevTime = this->_currentTime;
const auto prevPlayTimes = this->_currentPlayTimes;

if (!this->_isCompleted && this->_setCurrentTime(time))
{
    const auto eventDispatcher = this->_armature->_display;

    if (!_isStarted)
    {
        _isStarted = true;

        if (eventDispatcher->hasEvent(EventObject::START)) 
        {
            const auto eventObject = BaseObject::borrowObject<EventObject>();
            eventObject->animationState = this->_animationState;
            this->_armature->_bufferEvent(eventObject, EventObject::START);
        }
    }

    if (this->_keyFrameCount)
    {
        const auto currentFrameIndex = this->_keyFrameCount > 1 ? (unsigned)(this->_currentTime * this->_frameRate) : 0;
  auto curPlayTimes = prevPlayTimes;
  auto executeCount = 0;
  
  if (curPlayTimes == this->_currentPlayTimes)
  {
    executeCount = currentFrameIndex - this->_currentFrameIndex;
  }
  else {
    executeCount += this->_keyFrameCount - this->_currentFrameIndex - 1;
    /*** 当前播放次数是从0开始的,所以当前播放次数达到动作播放次数时就不会在改变当前帧下标的数据了。
    ***  也就不在需要在补算当前播放次数的帧数了。
    ***///
    if (this->_animationState->playTimes == 0 || this->_currentPlayTimes < this->_animationState->playTimes) {
      executeCount += currentFrameIndex + 1;
    }

    if (this->_currentPlayTimes - curPlayTimes > 1) {
      executeCount += (this->_currentPlayTimes - curPlayTimes - 1) * this->_keyFrameCount;
    }
  }

  // 容错处理
  if (executeCount < 0) {
    executeCount = currentFrameIndex;
    this->_currentFrameIndex = -1;
  }

  for (size_t i = 0; i < executeCount; i++)
  {
    ++this->_currentFrameIndex;
    const auto currentFrame = this->_timeline->frames[this->_currentFrameIndex];
    if (this->_currentFrame != currentFrame)
    {
      if (this->_keyFrameCount > 1)
      {
        auto crossedFrame = this->_currentFrame;
        this->_currentFrame = currentFrame;

        if (!crossedFrame)
        {
          const auto prevFrameIndex = (unsigned)(prevTime * this->_frameRate);
          crossedFrame = this->_timeline->frames[prevFrameIndex];

          if (this->_isReverse)
          {
          }
          else
          {
            if (
              prevTime < crossedFrame->position ||
              prevPlayTimes != this->_currentPlayTimes
              )
            {
              crossedFrame = crossedFrame->prev;
            }
          }
        }

        if (this->_isReverse)
        {
          while (crossedFrame != currentFrame)
          {
            this->_onCrossFrame(crossedFrame);
            crossedFrame = crossedFrame->prev;
          }
        }
        else
        {
          while (crossedFrame != currentFrame)
          {
            crossedFrame = crossedFrame->next;
            this->_onCrossFrame(crossedFrame);
          }
        }
      }
      else
      {
        this->_currentFrame = currentFrame;
        this->_onCrossFrame(this->_currentFrame);
      }
    }

    if (this->_currentFrameIndex == this->_keyFrameCount -1)
    {
      if (eventDispatcher->hasEvent(EventObject::LOOP_COMPLETE))
      {
        const auto eventObject = BaseObject::borrowObject<EventObject>();
        eventObject->animationState = this->_animationState;
        this->_armature->_bufferEvent(eventObject, EventObject::LOOP_COMPLETE);
      }
      this->_currentFrameIndex = -1;
      this->_currentFrame = nullptr;
    }
  }
    }

    if (prevPlayTimes != this->_currentPlayTimes)
    {
        if (this->_isCompleted && eventDispatcher->hasEvent(EventObject::COMPLETE))
        {
            const auto eventObject = BaseObject::borrowObject<EventObject>();
            eventObject->animationState = this->_animationState;
            this->_armature->_bufferEvent(eventObject, EventObject::COMPLETE);
        }

        this->_currentFrame = nullptr;
    }
}

}

1赞