【问题标题】:How do you load a scene while animating a sprite in cocos2d-x?在 cocos2d-x 中动画精灵时如何加载场景?
【发布时间】:2015-12-10 00:26:59
【问题描述】:

我有一个“舞台选择”场景和一个“游戏”场景。但是,当用户按下按钮开始游戏场景时,在按下按钮和显示场景之间会有延迟(在旧设备上大约需要 2 秒或更长时间)。所以我想我应该创建一个加载场景。

所以我现在正在做的是向我的“加载”场景传递一个 std::function,它在加载场景出现后 0.1 秒被调用。这个函数有这样的代码来启动“游戏”场景:

用于创建加载场景。

auto loading_scene = LoadingScene::createLoadingScene([stage_course]() {

    Director::getInstance()->replaceScene(Game::createScene(stage_course->course_id));

});

Director::getInstance()->replaceScene(loading_scene);

加载游戏场景。

void LoadingScene::onEnter()
{
    Node::onEnter();

    call_after(0.1, callback_start);  
}

这样的结果是加载场景显示一个简单的角色运行动画精灵。起初我尝试在回调前延迟 1.0 秒来检查精灵是否正常工作(确实如此,角色运行)。但是在执行回调(加载新场景的回调)时它会停止移动,并保持这种状态大约 1-2 秒,直到场景加载并呈现出来。..

有谁知道如何在场景加载时保持精灵动画,以便在显示“游戏”场景之前它永远不会停止运行?


编辑:

我正在使用 cocos2d-x-3.8。

我的加载场景在其 init 函数中包含以下代码,用于创建用于为尖顶设置动画的动画:

// Create the sprite animation
Animation *animation = Animation::create();
for (int i = 0; i < INT16_MAX; i++)
{
    string frame_sprite_name = StringUtils::format("Interface/loading/0_%d.png",i);

    auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(frame_sprite_name);

    if (frame) {
        animation->addSpriteFrame(frame);
    } else {
        break;
    }
}

animation->setDelayPerUnit(0.15f);


Animate *animate = Animate::create(animation);


// Create a temporal sprite to run the animation

auto temp_sprite = Sprite::create();

temp_sprite->setAnchorPoint(Vec2(0.5,0.5));
temp_sprite->setPosition(Vec2(DISPLAY_WIDTH/2.0f,DISPLAY_HEIGHT/2.0f));


this->addChild(temp_sprite);

temp_sprite->runAction(RepeatForever::create(animate));

编辑 2:

我的游戏场景加载时间过长的原因是因为我正在加载我的舞台所需的所有精灵图,如下所示:

// Shared

if (!SpriteFrameCache::getInstance()->isSpriteFramesWithFileLoaded(STUDENTS_SPRITE_MAP)) {
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile(STUDENTS_SPRITE_MAP);
}

if (!SpriteFrameCache::getInstance()->isSpriteFramesWithFileLoaded(OTHERS_SPRITE_MAP)) {
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile(OTHERS_SPRITE_MAP);
}

if (!SpriteFrameCache::getInstance()->isSpriteFramesWithFileLoaded(INTERFACE_SPRITE_MAP)) {
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile(INTERFACE_SPRITE_MAP);
}

if (!SpriteFrameCache::getInstance()->isSpriteFramesWithFileLoaded(ZOMBIES_SPRITE_MAP)) {
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile(ZOMBIES_SPRITE_MAP);
}

if (!SpriteFrameCache::getInstance()->isSpriteFramesWithFileLoaded(PORTRAITS_SPRITE_MAP)) {
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile(PORTRAITS_SPRITE_MAP);
}

if (!SpriteFrameCache::getInstance()->isSpriteFramesWithFileLoaded(CUTS_SPRITE_MAP)) {
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile(CUTS_SPRITE_MAP);
}

// Exclusive

if (!SpriteFrameCache::getInstance()->isSpriteFramesWithFileLoaded(TEACHERS_SPRITE_MAP)) {
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile(TEACHERS_SPRITE_MAP);
}

【问题讨论】:

    标签: c++ cocos2d-x cocos2d-x-3.0


    【解决方案1】:

    试试这个:

    void HelloWorld::loadTextures1(){
        Director::getInstance()->getTextureCache()->addImageAsync("sprites1.png", CC_CALLBACK_1(HelloWorld::loadTextures2, this));
    }
    
    void HelloWorld::loadTextures2(Texture2D* texture1){
        this->texture1 = texture1;
        CCLOG("Texture 1 loaded!");
        Director::getInstance()->getTextureCache()->addImageAsync("sprites2.png", CC_CALLBACK_1(HelloWorld::loadTextures3, this));
    }
    
    
    void HelloWorld::loadTextures3(Texture2D* texture2){
        this->texture2 = texture2;
        CCLOG("Texture 2 loaded!");
        Director::getInstance()->getTextureCache()->addImageAsync("sprites3.png", CC_CALLBACK_1(HelloWorld::allTexturesLoaded, this));
    }
    
    void HelloWorld::allTexturesLoaded(Texture2D* texture3){
        this->texture3 = texture3;
        CCLOG("Texture 3 loaded!");
    
        auto cache = SpriteFrameCache::getInstance();
    
        cache->addSpriteFramesWithFile("sprites1.plist", texture1);
        cache->addSpriteFramesWithFile("sprites2.plist", texture2);
        cache->addSpriteFramesWithFile("sprites3.plist", texture3);
    
        auto scene = GameScene::createScene();
        Director::getInstance()->replaceScene(TransitionShrinkGrow::create(.5, scene));
    }
    

    它异步加载这 3 个纹理,然后同步加载带有预加载纹理的 plist 文件。最后有一点冻结(同步部分),但我认为这还不错。您也可以深入挖掘 SpriteFrameCache 并尝试对其进行优化。

    【讨论】:

    • 我想这是最好的方法,就像其他答案所说的那样,但由于示例代码更容易理解。我想我可以将每个场景中需要哪些精灵表的信息设为静态每个场景类型,并基于它递归加载所有需要的信息。然后我可以在我的大部分场景中使用它。谢谢。 (我不知道我可以加载纹理,然后像这样将它与 spriteframe 缓存相关联。我认为“addSpriteFramesWithFile”会从头开始重新创建所有内容,所以我不认为我可以使用 addImageAsync 方法。
    【解决方案2】:

    我不知道 cocos2d-x 对此支持得特别好:

    CSLoader 在当前线程上加载场景,因此它会阻塞动画循环直到完成。

    为了在 CSLoader 工作时实现流畅的动画,需要对其进行重构 * 在工作线程中运行 - 这将很难,因为(我上次查看)如果不是在主 cocos 线程上创建的任何 Ref 派生对象都会出现恐慌。 * 频繁调用 Dispatcher / runloop 以允许帧动画。我还没有查看 cocostudio::CSLoader 代码来了解它对这个的适用程度……它似乎不支持开箱即用。

    另一种可能难以实现的方法是将场景简单地分解成块 - 每个块都可以快速加载,因此没有明显的加载延迟。

    【讨论】:

    • 把场景分成块是什么意思?
    • 希望整个场景不会一下子全部可见。稍后在需要时加载最初不可见的位。
    • 我有完全相同的问题:(我发现的唯一方法是手动加载精灵而不使用 cocos studio CSLoader,调用:auto TexureCache = Director::getInstance()->getTextureCache(); TexureCache- >addImageAsync("MainMenuScreen/Background.png", CC_CALLBACK_1(GS_Loading::LoadingCallback, this));
    • @finalpets 我很困惑,我不使用 cocos studio。
    • 啊。最初听起来像你。
    【解决方案3】:

    我同意 Chris 的说法,特别是卸载工作或将事情分成块。

    确实,Cocos2d-x 不是为多线程设计的,所以这就是为什么你需要实现一个只做少量工作的update 回调,然后等待下一个运行循环允许引擎渲染。

    我希望我可以帮助您解决加载问题,但您显示的代码仅用于加载动画,这并不是真正的问题。我们需要查看导致速度变慢的代码以提供一些实用的解决方案。

    【讨论】:

    • 我认为游戏场景的放缓是因为我正在加载 6 或 7 张精灵地图。但我不认为我可以选择不加载其中一些,因为我正在使用它们,而且我不想在用户玩游戏时减速。真的希望有人知道如何或有办法做到这一点。我想到的是在加载场景中异步加载精灵图,但我不知道这是否可能。我确实记得看到纹理可以异步加载,但不知道 spritemaps。
    • @Chiquis 我从来没有说过加载其中一些并开始场景。您应该加载部分数据,并等待下一个 runloop 继续加载。加载完所有内容后,然后您将转换到实际场景。同样,重要的是你要知道实际上什么需要时间,我们需要查看该代码以提出可能的解决方案。
    猜你喜欢
    • 2013-08-02
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-18
    • 1970-01-01
    • 2012-03-18
    相关资源
    最近更新 更多