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

查看:102
本文介绍了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*).

我正在尝试这样做以优化 CCSpriteBatchNode 的数量.这是我的主类的代码片段(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];
}

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

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天全站免登陆