Как загрузить сцену во время анимации спрайта в cocos2d-x?
У меня есть сцена "сценический выбор" и сцена "игра". Однако, когда пользователь нажимает кнопку для запуска игровой сцены, происходит задержка между нажатием и сценой (около 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 секунд, пока сцена не загрузится, а затем его будет представлена.
Кто-нибудь знает, как сохранить анимацию спрайта во время загрузки сцены, чтобы она не переставала работать до тех пор, пока не будет показана сцена "игра"?
Edit:
Я использую 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);
}
Ответы
Ответ 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 и пытаться его оптимизировать.
Ответ 2
Я не знаю, что cocos2d-x поддерживает это особенно хорошо:
CSLoader загружает сцену в текущий поток, поэтому блокирует цикл анимации до ее завершения.
Чтобы добиться гладкой анимации, работая с CSLoader, ее нужно будет реорганизовать либо
* для запуска в рабочем потоке - что будет сложно (в прошлый раз, когда я смотрел), любой объект, полученный из Ref, будет паниковать, если он не создан в основном потоке кокосов.
* для частого вызова в Dispatcher/runloop, чтобы позволить анимации кадра. Я не смотрел код cocostudio:: CSLoader, чтобы узнать, насколько это возможно для этого... он, похоже, не поддерживает это в коробке.
Альтернативой, которую может быть трудно достичь, является просто разорвать сцену на куски - каждый из которых можно быстро загрузить, чтобы не было заметной задержки нагрузки.
Ответ 3
Я согласен с тем, что говорит Крис, в частности, за выгрузкой или срывом вещей на куски.
Правда, Cocos2d-x не предназначен для многопоточности, поэтому вам нужно реализовать обратный вызов update
, который выполняет только небольшую работу, а затем ждет, пока следующая runloop не позволит движку визуализировать.
Я хотел бы помочь вам решить проблемы с загрузкой, но код, который вы показываете, предназначен только для загрузки анимаций, что на самом деле не проблема. Нам нужно увидеть код, который заставляет замедлить предоставление некоторых практических решений.