Не могу показать сцену второй раз в Cocos3D

У меня есть viewController со сценой кокосов, которую я вставляю в свой навигационный контроллер. В этом контроллере представления у меня есть следующие методы:

    -(void) viewDidLoad
{
    [super viewDidLoad];
    [_cc3FrameView addSubview: [self createGLView]];
    CC3Backgrounder.sharedBackgrounder.shouldRunTasksOnRequestingThread = YES;
}

- (void) viewWillAppear:(BOOL)animated
{
    if (!sceneInitialized) {
        sceneInitialized = YES;
        [CCDirector.sharedDirector runWithScene: [[self makePanoramaScene] asCCScene]];

    } else {
        [CCDirector.sharedDirector resume];
    }

    [CCDirector.sharedDirector startAnimation];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [[self runningPanoramaScene] sceneWillShow];
    });
}

-(AxPanoramaScene *)runningPanoramaScene
{
    CCScene *scene = [CCDirector.sharedDirector runningScene];
    AxPanoramaLayer *panoramaLayer = [scene.children lastObject];
    AxPanoramaScene *panoramaScene = (AxPanoramaScene *)panoramaLayer.cc3Scene;
    return panoramaScene;
}

-(void)viewWillDisappear:(BOOL)animated
{
    [CCDirector.sharedDirector pause];
}

Пока я нажимаю на этот контроллер - все работает, но когда я нажимаю на этот контроллер и снова нажимаю - у меня ярко-розовый экран и сплошные сообщения в логе:

    2014-12-12 19:30:06.447 UniversalMapExample[2262:258353] cocos2d: animation started with frame interval: 60.00
2014-12-12 19:30:06.452 UniversalMapExample[2262:258353] cocos2d: surface size: 768x973
OpenGL error GL_INVALID_OPERATION detected at -[CCES2Renderer resizeFromLayer:] 161
2014-12-12 19:30:06.452 UniversalMapExample[2262:258353] Failed to make complete framebuffer object 0x8219
2014-12-12 19:30:06.453 UniversalMapExample[2262:258353] cocos2d: surface size: 768x973
OpenGL error GL_INVALID_OPERATION detected at -[CCES2Renderer resizeFromLayer:] 161
2014-12-12 19:30:06.453 UniversalMapExample[2262:258353] Failed to make complete framebuffer object 0x8219
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
[***GL ERROR***] GL_INVALID_VALUE: Numeric argument is out of range from glUseProgram(15).
[***GL ERROR***] GL_INVALID_OPERATION: Operation not allowed in current state from glUniform3fv(7, 4, (0.329, 0.944, 0.000)) setting u_cc3LightSpotDirectionModel.
[***GL ERROR***] GL_INVALID_OPERATION: Operation not allowed in current state from glUniformMatrix4fv(12, 1, GL_FALSE, 
    [0.021050, -0.007339, -0.000000, 0.210503
     0.000000, -0.000000, 0.017596, -0.977556
     0.005937, 0.017031, 0.000000, -0.660065
     0.005926, 0.016997, 0.000000, 1.339256]) setting u_cc3MatrixModelViewProj.

Как правильно нажать контроллер с кокосовой сценой несколько раз? Я изменил пример с исходников кокоса на этот код. Что я здесь делаю неправильно? Обратите внимание - мой контроллер не CCDirector - он просто содержит вид со сценой Cocos - реализация похожа на CC3DemoMultiScene. Спасибо!


person ShurupuS    schedule 12.12.2014    source источник


Ответы (2)


Помните, что CCDirector — это UIViewController, но это также и синглтон, что придает ему некоторые уникальные нюансы.

Например, кажется, что вы вызываете метод createGLView каждый раз, когда хотите заменить контроллер. Если он соответствует дизайну CC3DemoMultiScene, он попытается воссоздать еще один CCGLView до того, как старый будет выпущен из синглтона CCDirector.

Как правило, лучше всего обращаться с CCDirector и CCGLView, которые вы создаете для него, как с автономными повторно используемыми единицами. При извлечении содержащего контроллера оставьте все как есть и каждый раз просто добавляйте и удаляйте CCGLView из иерархии представлений.

...Счет

person Bill Hollings    schedule 14.12.2014
comment
большое спасибо, Билл! Действительно, проблема была в воссоздании glview - работать с cocos3d не так просто, как я думал.. Но теперь проблема решена! спасибо еще раз! - person ShurupuS; 15.12.2014

Это копия/вставка из моего блога, где я освещал аналогичную проблему. Единственная разница в том, что я хотел полную интеграцию с UIKit. У меня была проблема, когда 2-й раз через. Возможно, это поможет вам.

http://www.notthepainter.com/full-cocos2d-uikit-integration/

Я работал над игрой, основанной на cocos2d, и мне не удалось запустить ее дважды. Было ясно, что я неправильно закрывал 1-ю игру или правильно строил 2-ю игру, или и то, и другое!

В Интернете есть множество учебных пособий, в которых рассказывается, как добавлять кнопки UIKit в ваше приложение Cocos2D или как запускать Cocos2D из вашего приложения на основе UIKit. Но мне нужно было сделать и то, и другое. Мне нужен UIViewController под моей игрой и виджеты UIKit поверх моей игры. Я потратил много времени на чтение, и вот что я придумал.

Во-первых, создание проекта Xcode было кошмаром. В конце концов я использовал шаблон cocos2d/box2d, а затем вырвал ненужные файлы и добавил все исходные файлы обратно. Файл AppDelegate.m выглядит точно так же, как должно выглядеть приложение, отличное от cocos2d. Это противоречит сути многих руководств, в которых рекомендуется создавать среду cocos2d в AppDelegate. Я боролся с этим, большую часть пятницы мне не везло, а затем в понедельник я вставил Cocos2DSingleton, и он практически запустился с первого раза.

Вот метод viewDidLoad моего GameViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:NO];

    TTCocos2DSingleton *shared = [TTCocos2DSingleton sharedCocos2D];
    CCGLView *glView = [shared currentGLView];

    [self.view insertSubview:glView atIndex:1];
}

Есть мнение, на что следует обратить внимание. GameViewController имеет игровые UIButtons, оценочные UILabels и другие игровые виджеты пользовательского интерфейса. Это позволяет мне выполнять многие элементы управления игрой в Interface Builder, а не раскладывать их вручную. Обратите внимание, что я скрываю строку состояния, так как игра полноэкранная.

Я получаю свой экземпляр cocos2d через синглтон, получаю его glView и вставляю его в представление GameViewController с индексом 1. Это ставит его ниже всех элементов управления игрой. Я покажу вам метод sharedCocos2D позже, давайте посмотрим на viewWillAppear.

- (void) viewWillAppear:(BOOL)animated
{
    if(![[CCDirector sharedDirector]  runningScene]){
        CCScene *scene = [MyGameLayer scene];

        myGame = [MyGameLayer node];
        myGame.delegate = self;

        [scene addChild: myGame];

        [[CCDirector sharedDirector] runWithScene:scene];
    } else {
        // we have a scene already, replace the original to get a new game
        [[CCDirector sharedDirector] startAnimation];

        CCScene *scene = [MyGameLayer scene];

        myGame = [MyGameLayer node];
        myGame.delegate = self;

        [scene addChild: myGame];

        [[CCDirector sharedDirector] replaceScene:scene];
    }
}

Обратите внимание, как мы относимся к первому запуску иначе, чем ко второму. Для второго и последующих запусков мы заменяем сцену новой. Это позволяет избежать всех проблем с «перезапуском». Также обратите внимание, что я установил делегат. Я использую протокол делегата для связи между моим игровым уровнем и моим UIViewController.

Мой одноэлементный шаблон взят из блога Duck Rowing, который, я должен признать, довольно крутое название для блога. Я не собираюсь показывать здесь весь код синглтона, этот блог посвящен cocos2d, но вот как я создаю свою среду cocos2d.

+ (TTCocos2DSingleton *) sharedCocos2D;
{
    static dispatch_once_t onceQueue;

    dispatch_once(&onceQueue, ^{
        if (sharedInstance) {
            return;
        }
        sharedInstance = [[TTCocos2DSingleton alloc]init];
        // Create an CCGLView with a RGB565 color buffer, and a depth buffer of 0-bits
        sharedInstance->glView = [CCGLView viewWithFrame:[[UIScreen mainScreen] bounds]
                             pixelFormat:kEAGLColorFormatRGB565 //kEAGLColorFormatRGBA8
                             depthFormat:0  //GL_DEPTH_COMPONENT24_OES
                      preserveBackbuffer:NO
                              sharegroup:nil
                           multiSampling:NO
                         numberOfSamples:0];
        [sharedInstance->glView setMultipleTouchEnabled:YES];
        [sharedInstance setupDirector];
    });
    return sharedInstance;

}

Синглтон настраивает CCGLView, включает мультитач, а затем настраивает директор. (Я поместил это в другой метод, так как ошибочно думал, что мне нужно будет вызывать его в другом месте. Оказывается, мне это не нужно.)

- (void)setupDirector
{
    CCDirectorIOS *director = (CCDirectorIOS*) [CCDirector sharedDirector];

    [director setView:glView];
    [director enableRetinaDisplay:YES];
    director.wantsFullScreenLayout = YES;
    [director setDisplayStats:NO];
    [director setAnimationInterval:1.0/60];
}

И в setupDirector мы устанавливаем обычные подозреваемые, необходимые для приложения cocos2d. Теперь в игру можно играть несколько раз, у меня есть полный UIViewController/UINavController под ним, и у меня есть виджеты UIKit поверх моей игры. Нирвана.

person Paul Cezanne    schedule 12.12.2014
comment
Спасибо, @Paul, я взял код из вашего сообщения в блоге! - person ShurupuS; 15.12.2014