【问题标题】:initWithSpriteFrameName not initializing class after upgrade to cocos2d v2.0升级到 cocos2d v2.0 后 initWithSpriteFrameName 没有初始化类
【发布时间】:2013-01-18 19:17:04
【问题描述】:

我一直在构建《学习 Cocos2D》一书中描述的 SpaceViking 项目。当我开始遇到问题时,我已经读到了 Box2D 的第 10 章。然后我尝试将 cocos2D 从版本 1 升级到版本 2.0。在进行必要的更改以修复弃用后,代码不再有效。具体来说,我发现当创建游戏对象或敌人对象时,它们的 init 方法不再被调用。例如,当执行以下行时:

RadarDish *radarDish = [[RadarDish alloc] initWithSpriteFrameName:@"radar_1.png"];

未调用 RadarDish 初始化方法。然后,我查看了版本 1 和版本 2 中 initWithSpriteFrameName 的执行情况,发现 CCSprite.m 发生了变化,因此不再调用 init 方法。在版本 2 的源代码中,initWithSpriteFrameName 方法调用 initWithSpriteFrame 调用 initWithTexture 调用:

-(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect rotated:(BOOL)rotated
{
    if( (self = [super init]) ) {

因此,不会调用 RadarDish init 方法。相反,调用 CCNode init 方法。但是在版本 1 中,initWithSpriteFrameName 调用 initWithSpriteFrame 调用具有以下代码的 initWithTexture:

// IMPORTANT: [self init] and not [super init];
if( (self = [self init]) ){
    [self setTexture:texture];
    [self setTextureRect:rect];
}

这允许调用 RadarDish init 方法。

我能做些什么来解决这个问题?这本书似乎不太可能需要更改以支持升级到 cocos2d v2.0,所以我怀疑我一定遗漏了其他东西。但是如果我错了,那么更改此代码以导致调用 RadarDish init 方法的方法是什么?

【问题讨论】:

  • InitWithSpriteFrameName 应该可以工作。你的 init 方法是什么样的?
  • cocos2d 2.x 在许多细节上与 v1.x 不同,所以不能指望 v1.x 代码只能在 2.x 下工作

标签: cocos2d-iphone xcode4.5


【解决方案1】:

好吧,我错了。 “cocos2d 2.x 在许多细节上与 v1.x 不同,所以不能指望 v1.x 代码只能在 2.x 下工作”。如果你打算跟着《学习 Cocos2D》这本书,我建议加载 cocos2d-iphone 1.0.1 版本。否则,您将面临许多不兼容问题以及需要修复的大量弃用。

但是如果你真的想使用最新的cocos2d,那么你应该做一些事情。 1) 按照this link 中的说明进行操作。 2) 您将有很多弃用和更改需要修复,因此请使用this link 了解如何修复这些弃用和更改。 3) 您还需要更新 Joystick 类,因此请转到 this link 以获取这些更改,4) 您必须在谷歌上搜索其余部分以找到解决方案。

现在至于我在这里提到的问题的解决方案,可能有多种解决方案,但我会在下面提供一个(感谢 Sylvan 上面的回答):

在每个 GameObjects、EnemyObjects 和 PowerUps 中,我添加了一个方法来覆盖 initWithFrameName。这将规避对象 init 方法的使用。例如,对于 RadarDish,我添加了以下内容:

-(id) initWithSpriteFrameName:(NSString*)frameName {
    if( (self=[super init]) ) {
        if ((self = [super initWithSpriteFrameName:frameName])) {

            CCLOG(@"### RadarDish initialized");
            [self initAnimations];                                   // 1
            characterHealth = 100.0f;                                // 2
            gameObjectType = kEnemyTypeRadarDish;                    // 3
            [self changeState:kStateSpawning];                       // 4

        }
    }
    return self;
}

这允许 GameObject 和 GameCharacter init 方法在 CCSprite 的 initWithSpriteFrameName 方法运行之前运行。

Viking GameObject 必须有一个稍微不同的解决方案,因为它是使用 initWithSpriteFrame 而不是 initWithSpriteFrameName 初始化的。但是覆盖的实现和上面RadarDish的例子基本一样。

(除了克服弃用所必需的所有更改)上述更改允许“学习 Cocos2D”示例中的其他所有内容保持不变。

祝你好运。

【讨论】:

    【解决方案2】:

    我认为您遇到了麻烦,因为您将 init 方法保持原样而不修改它。您在 RadarDish 类上调用方法 initWithSpriteFrameName: 但该类没有该方法名称,因此它查找其超类。我认为你可以简单地将你的 init 方法重命名为 initWithSpriteFrameName: 并且你会没事的。像这样:

    // RadarDish.m
    
    -(id) initWithSpriteFrameName:(NSString*)frameName {
       if ((self = [super initWithSpriteFrameName:frameName])) {
          // init anything here
       }
       return self;
    }
    

    只是没有一个名为 init 的方法并期望它被调用。

    【讨论】:

    • 在“学习Cocos2d”的例子中,RadarDish.m没有initWithSpriteFrameName方法。它只有一个 init 方法。 RadarDish 是一个 GameCharacter,它是一个游戏对象,它是一个 CCSprite。甚至没有从 CCSprite 调用 init 方法(就像在 cocos2d-iphone 的 1.0.1 版本中一样)。但是,是的,这可能是通过重载 initWithSpriteFrameName 的另一种方法(尽管我没有尝试过)。谢谢。
    • 我试过这个,但我仍然遇到问题。虽然这对 RadarDish 和其他几个 GameCharacters 有效,但更多的崩溃仍在继续,我厌倦了追踪东西。我怀疑你的方法更合理,但现在我会继续使用我的方法,以便继续前进。
    • 我发现我需要稍微扩展您的解决方案才能使其正常工作。我发现在执行 [super initWithSpriteFrameName:frameName] 之前必须先执行 [super init],因为 GameObject 和 GameCharacter init 方法也需要运行,并且必须在 [super initWithSpriteFrameName:frameName] 之前运行。我不确定我是否应该编辑您的答案,所以我在下面记录了解决方案。感谢您的帮助。
    • 好的,很高兴你明白了。有时每个人的情况都是独一无二的,有利于您解决问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多