Cocos2d中精灵的暂停/简历动作/动画

Pause/Resume Action/Animation on Sprite in Cocos2d

本文关键字:动画 Cocos2d 精灵 暂停      更新时间:2023-10-16

使用cocos2d-x和c ,我正在尝试播放和暂停精灵的动画。

我正在使用Cocos2dx的3.15.1版。

我有一个名为PlayerSprite的类,它是从cocos2d::Sprite类中脱离的。在PlayerSprite初始化中,我已经使用以下代码设置了动画:

SpriteBatchNode* playerSpriteBatch = SpriteBatchNode::create("player.png");
SpriteFrameCache* spriteFrameCache = SpriteFrameCache::getInstance();
spriteFrameCache->addSpriteFramesWithFile("player.plist");
Vector<SpriteFrame*> animFrames(2);
char str[18] = { 0 };
for (int i = 1; i < 3; i++) {
    sprintf(str, "player_idle_%d.png", i);
    SpriteFrame* frame = spriteFrameCache->getSpriteFrameByName(str);
    animFrames.pushBack(frame);
}
Animation* idleAnim = Animation::createWithSpriteFrames(animFrames, 0.8f);
self->idleAction = self->runAction(RepeatForever::create(Animate::create(idleAnim)));
self->idleAction->setTag(0);

当我运行代码时,它可以正常工作,并且动画循环正确。

在我的void update()方法中,我试图暂停/播放基于玩家正在移动或闲置的天气动作/动画。

我使用以下代码执行此操作:

const bool isIdleActionRunning = this->getNumberOfRunningActionsByTag(0) > 0 ? true : false;
const bool isMoving = !vel.isZero();
if (!isMoving && !isIdleActionRunning) {
    // Player is idle AND animation is not running
    // Run animation
    this->runAction(idleAction);
} else if (isMoving && isIdleActionRunning) {
    // Player is moving but animation is running
    // Pause animation
    this->stopActionByTag(0);
}

当我现在运行此代码时,我的角色就会掉下来,一旦他击中了gound,我就会在this->runAction(idleAction);上遇到一个错误:

访问违规阅读位置0xddddde5

我相信这是由于this->stopActionByTag(0)删除动作指针而引起的。我试图克隆行动以避免这种情况,但没有成功。

我知道这有点晚了,您可能已经解决了这个问题,但是...

您的问题是您不能多次使用一个操作实例(iDleaction)。因此,一旦您运行并将其删除,它将被释放并且无法使用。因此,您现在有2个选项,

  • 在运行动作之前,每次都会创建一个新的iDleaction操作。
  • 或,保留了一个闲置,永远不要运行它。相反,创建此闲置的克隆,并每次运行一个新的克隆。即。

    idleAction->retain();
    const bool isIdleActionRunning = this->getNumberOfRunningActionsByTag(0) > 0 ? true : false;
    const bool isMoving = !vel.isZero();
    if (!isMoving && !isIdleActionRunning) {
        // Player is idle AND animation is not running
        // Run animation
        Action idleActionClone = idleAction->clone();
        this->runAction(idleActionClone);
    } else if (isMoving && isIdleActionRunning) {
        // Player is moving but animation is running
        // Pause animation
        this->stopActionByTag(0);
    }
    

解决方案:调用retain()以保持您的动作。

这是COCOS2D-X的内存管理问题。

RepeatForever类的create()函数中(从Ref派生),参考计数设置为1,并且在返回对象之前有一系列代码ret->autorelease(),这意味着该对象将在此帧的末端自动释放。

您称为runAction()函数与创建的帧相同,操作由ActionManager保留,其参考计数设置为2,然后在框架末端1(Autorelease)。

停止它后,它由ActionManager发布,参考计数设置为0,并且已删除。此后,您使用了操作,这将是一种违规方法。

*编辑:当删除PlayerSprite或泄漏时,不要忘记手动释放动作。

停止操作时,它将从内存中回收。为了再次发挥作用,您必须重新创建它。因此,您可以制作创建者功能,从而返回动画。不利的一面是您每次都会重新创建动画,并且它也会从一开始播放(从技术上讲,您可以倒带)。

,但我已经开发了一种更简单的技术来暂停/简历动画:

假设您有一个动作:

action = MoveBy::create(5.0f, Vec2(50, 100));

现在,您可以将此动作嵌入这样的速度动作:

action = Speed::create(MoveBy::create(5.0f, Vec2(50, 100)), 1.0f);

1.0f-是速度,因此是正常的动作率。现在暂停致电:

action->setSpeed(0.0f);

和恢复:

action->setSpeed(1.0f);

,如果您出于某种原因或其他原因需要使用不同的速度;)