Cocos2d:可以有一个指向父母的类指针的指针吗? [英] Cocos2d: Is it ok to have a pointer to a parent's class pointer?

查看:110
本文介绍了Cocos2d:可以有一个指向父母的类指针的指针吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

傻问题. Cocos2d是围绕父子层次结构构建的.我想知道是否可以有一个父类(例如GameScene)并用指向该父类成员(例如CCSpriteBatchNode *)的指针初始化一个子类(例如SpriteHandler).

Silly question. Cocos2d is build around the parent-child hierarchy. I was wondering if it is ok to have a parent class (e.g. GameScene) and initialize a child class (e.g. SpriteHandler) with a pointer to a member of the parent class (e.g. CCSpriteBatchNode*).

我正在尝试这样做以优化CCSpriteBatchNodes的数量.这是我的主要课程(GameScene风格)的代码片段.

I am trying to do this to optimize the number of CCSpriteBatchNodes. Here is a code snippet of my main class (GameScene style).

#import <Foundation/Foundation.h>
#import "cocos2d.h"

enum ShooterSceneLayerTags {
    HudLayerTag = 0,
    };

@interface ShooterScene : CCLayer {
    CCSpriteBatchNode* sharedSpriteBatchNode;
}


-(id) initWithSharedBatchNodeReference:( CCSpriteBatchNode*) sharedSpriteBatchNode;
+ (id) sceneWithId:(int)sceneId;
 @end


#import "ShooterScene.h"
#import "MainMenuScene.h"

//Layers
#import "LevelSpritesLayer.h"
#import "HudLayer.h"



@interface ShooterScene (PrivateMethods)
-(void) addLayers:(int)sceneId;
-(void) loadGameArtFile;
-(BOOL) verifyAndHandlePause;
@end

@implementation ShooterScene

+ (id) sceneWithId:(int)sceneId
{
    CCScene *scene = [CCScene node];

    ShooterScene * shooterLayer = [[self alloc] initWithId:sceneId];
    [scene addChild:shooterLayer];

    return scene;    
}

-(id) initWithId:(int)sceneId 
{
    if ((self = [super init]))
    {
        //Load game art before adding layers - This will initialize the batch node
        [self loadGameArtFile:sceneId]; 

        //Will add sprites to shared batch node for performance
        [self addLayers:sceneId];
        [self addChild:sharedSpriteBatchNode];

        //Do other stuff..
        [self scheduleUpdate];

    }
    return self;

}

-(void) addLayers:(int)sceneId
{
    LevelSpritesLayer * levelData = [LevelSpritesLayer node];
    [levelData initWithSharedBatchNodeReference:sharedSpriteBatchNode];

    [self addChild:levelData];

    switch (sceneId) {
        case 1:
            [levelData loadLevelOneSprites];
            break;
        case 2:
            [levelData loadLevelTwoSprites];
            break;            
        default:
            break;
    }

    HudLayer * hud = [HudLayer node];
    [hud setUpPauseMenu];
    [self addChild:hud z:1 tag:HudLayerTag];
}

-(BOOL) verifyAndHandlePause
{
    HudLayer * hud = [self getChildByTag:HudLayerTag];
    if(hud.pauseRequested){
         [[CCDirector sharedDirector] replaceScene:[MainMenuScene scene]];

        return true;
    }
    else {
        return false;
    }

}
-(void) update:(ccTime)delta
{
    if([self verifyAndHandlePause]==false)
    {
        //Continue with animation etc.. 


    }
}

/**
 This is tricky. Could have loaded this in LevelData but as I am expecting to use the same SpriteSheet for HudLayer as well then 
 I prefer to have the control here of this. Also, the same sheet could be used for more level, hence specific function is not bad 
 **/
-(void) loadGameArtFile:(int) sceneId
{
    CCSpriteFrameCache* frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
    [frameCache addSpriteFramesWithFile:@"game-art-hd.plist"];

    sharedSpriteBatchNode = [CCSpriteBatchNode batchNodeWithFile:@"game-art-hd.png"];
}

//As dealloc is deprecated, I prefer to remove unused sprites and texture on cleanup
-(void) cleanup
{
    [[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];     
}

这是loadLevelData方法之一,它使用了sharedSpriteBAtchNodeReference

-(void) loadLevelOneSprites
{
    //Just a proof of concept example
    testSprite = [CCSprite spriteWithSpriteFrameName:@"File0.png"];
    testSprite.anchorPoint = CGPointMake(0.5f, 0.5f);
    testSprite.position = CGPointMake(160.0f, 240.0f);
    [sharedSpriteBatchNodeReference addChild:testSprite];
}

推荐答案

[Ben]所说的.它不应作为保留或强引用,后者是ARC中实例变量的默认设置.

What [Ben] said. It should not be a retaining or strong reference, the latter being the default in ARC for instance variables.

有一种方法可以确保即使在使用强引用的情况下,ARC也可以确保循环安全.覆盖清除方法,并在此处取消引用(在MRC下,如果您保留了引用,也应在此处调用release):

There is one way to ensure under ARC that you're retain-cycle-safe even if you use a strong reference. Override the cleanup method and nil the reference there (under MRC you should also call release here, if you retained the reference):

-(void) cleanup
{
    sharedSpriteBatchNode = nil;
    [super cleanup];
}

在dealloc中执行此操作将无效.只要子节点对父节点有很强的引用,就不会释放它.因此,您需要在清理中执行此操作,并确保可以在其中设置清理标志的所有方法调用都将该参数设置为YES.

Doing this in dealloc won't work. As long as a child node has a strong reference to a parent, it will not be deallocated. So you need to do this in cleanup, and ensure that all method calls where you can set the cleanup flag has that parameter set to YES.

但是还有其他(我认为更好)的解决方案,而不是在初始化程序中传递父节点.例如,您可以从父级通过公共标签获取共享的批处理节点,然后在每次需要时执行此操作(将其包装到一个小函数中),或将其存储在一个弱(非保留)实例var中:

But there are other, and I think better, solutions than passing a parent node in the initializer. For example you could get the shared batch node via a common tag from the parent, and either do that every time you need it (wrap it into a small function) or store it in a weak (non-retaining) instance var:

// onEnter is typically called right after init (during addChild)
// parent is already set here
-(void) onEnter
{
    [super onEnter];

    CCSpriteBatchNode* sharedBatchNode = [parent getChildByTag:kSharedBatchNodeTag];
}

或者假设parentBatchNode是父类的一个属性,或者获取父对象并对其进行转换:

Or get the parent and cast it, assuming the sharedBatchNode to be a property of the parent class:

-(void) whereEver
{
    ShooterScene* scene = (ShooterScene*)parent;
    CCSpriteBatchNode* sharedBatchNode = scene.sharedSpriteBatchNode;
    …

    // you can also reduce the above to a single line:
    CCSpriteBatchNode* batch = ((ShooterScene*)parent).sharedSpriteBatchNode;
}

尤其是建议使用后一种解决方案.即使您经常需要这样做,它也很快.投射是免费的,对资源的访问只不过是发送消息而已.只需确保父级实际上是您要对其投射的类的对象即可.

Especially this latter solution is recommended. Even if you need to do that often it's fast. Casting is free, property access no more than a message send. Just be sure that the parent is in fact an object of the class you're casting it to.

这篇关于Cocos2d:可以有一个指向父母的类指针的指针吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆