如何在cocos2d-x中为精灵动画时加载场景?

问题描述:

我有一个“舞台选择”场景和一个“游戏”场景。但是,当用户按下按钮启动游戏场景时,按下按钮和显示的场景之间会有一段延迟(旧设备上大约需要2秒钟或更长时间)。所以我认为我应该创建一个加载场景。如何在cocos2d-x中为精灵动画时加载场景?

所以我在做什么,现在被传递给我的“加载”现场的std ::功能出现的场景加载后调用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。

我加载场景在其初始化函数下面的代码来创建它是用来动画一个尖顶的动画:

// 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); 
} 

试试这个:

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并尝试优化它。

+0

我想这是最好的方法,其他种类的答案说,但更容易理解多亏了示例代码。我想我可以根据每个场景类型制作每个场景静态所需的精灵表单,并根据它递归地加载所有需要的信息。然后我可以在大部分场景中使用它。谢谢。 (我不知道我可以加载纹理,然后像这样将它与spriteframe缓存关联起来,我认为'addSpriteFramesWithFile'会从头开始重新创建所有东西,所以我没想到我可以使用addImageAsync方法。 – Pochi

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

CSLoader在当前线程上加载场景,以阻止动画循环,直到完成为止。

为了实现流畅的动画,wile CSLoader正在工作,它需要重构或者 *以在工作线程中运行 - 这将会很困难(上次我查看的时候)任何Ref派生对象都会惊恐如果它没有在主要的科科斯线程上创建。 *经常调出分派器/ runloop以允许帧进行动画处理。我没有看过cocostudio :: CSLoader代码,看看它是如何可靠的......它似乎并不支持这个框。

可能难以实现的替代方法是简单地将您的场景分解为块 - 每个块都可以快速加载,因此不会出现明显的加载延迟。

+0

通过将场景划分为块是什么意思? – Pochi

+0

希望整个场景一次不可见。稍后在需要时加载最初不可见的位。 –

+1

我有完全相同的问题:(我发现的唯一方法是使用cocos studio CSLoader手动加载图片,并呼吁: \t auto TexureCache = Director :: getInstance() - > getTextureCache(); TexureCache-> addImageAsync(“ MainMenuScreen/Background.png“,CC_CALLBACK_1(GS_Loading :: LoadingCallback,this)); – finalpets

我同意克里斯说的话,特别是卸载工作或将事情分解成块。

确实,Cocos2d-x并不是专为多线程而设计的,所以您需要实现一个只做少量工作的回调函数,然后等待下一个回滚函数以允许引擎进行渲染。

我希望我可以帮你解决加载问题,但是你所展示的代码只是用于加载动画,这不是真正的问题。我们需要看到导致速度减慢的代码,以提供一些实用的解决方案。

+0

我认为游戏的放缓场景来自我加载6或7个雪碧地图的事实,但我不认为我可以选择不加载其中的一些,因为即时通讯使用它们,而且我不想在用户播放时放慢速度。真的希望有人知道怎么做或者有什么方法来做到这一点。想到的是在加载场景中异步加载spritemaps但我不知道如果这是可能的。我记得看到纹理可以异步加载,但不知道spritemaps。 – Pochi

+0

@Chiquis我从来没有说过加载他们中的一些并开始现场。您应该加载部分数据,并等待下一个runloop继续加载。一旦你加载了所有内容,**然后**你转换到实际的场景。再次重要的是,您知道什么事情需要时间,我们需要查看该代码来提出可能的解决方案。 – Mazyod