1

一个被滥用的话题,但我找不到答案。我正在关注“Learn iPhone and iPad cocos2d Game Development”一书,无法真正理解 ShootEmUp 示例中的方法(可在1处获得)是否是最好的方法。作者使用了一个 GameScene,它添加了各种对象(例如 Ship、InputLayer 等)作为子对象。有争议的方面是,在这些对象中,通过使用静态方法调用 GameScene,该方法返回 GameScene 类的静态实例,该实例在 GameScene 的 init 方法中实例化。这对我来说似乎是一个循环引用,并且根据许多人(例如,参见这篇文章)是要避免的。我不确定在游戏编程中是否也是如此,因为这种方法在1这可能是有原因的。

有人能澄清一下吗?我不确定是完全重构我的代码还是保留静态变量方法。

非常感谢你 :)!

源代码

4

2 回答 2

2

我猜你指的是这部分:

static GameScene* instanceOfGameScene;
+(GameScene*) sharedGameScene
{
  NSAssert(instanceOfGameScene != nil, @"GameScene instance not yet initialized!");
  return instanceOfGameScene;
}

这不会创建循环引用。有些人可能会争辩说,以这种方式构建代码不是一个好习惯,但这是一个不同的讨论。

如果此函数(GameScene对象)的返回值在某些 GameScene 子项中没有被引用为强属性,那没关系。

如果您在其中一个孩子中有此情况,您将遇到循环引用的情况:

@property(nonatomic, strong) GameScene *mainScene;
// OR for non-ARC
@property(nonatomic, retain) GameScene *mainScene;

这些将使GameScene对象的引用计数不会变为 0 并解除分配。

希望这可以帮助。

于 2012-05-04T12:34:44.150 回答
2

你在这里看到的是一个半单例模式,它在整个 Cocos 中被广泛使用,实际上 Cocos 框架本身是完全建立在单例对象上的(就像很多 Apple 的 UIKit 一样)。游戏经常使用单例,因为您通常在游戏中拥有大量中心数据,例如分数、健康、武器等,您的许多对象都需要了解这些数据。您通常还有一些对象,例如玩家、敌人等,它们需要通知您的应用程序的中央调度他们正在做什么,以便游戏中的其他对象可以做出相应的反应或调整。

这就是为什么许多 Cocos 游戏使用您在此处展示的技术的原因。如果您了解单例编程的风险,这不是一个坏习惯。基本上,请记住这一点:

  • 无论您使用单例技术还是使用另一种方法调用父级,您基本上都在做同样的事情。直接引用中央游戏引擎可能比依赖方法为您派生它更好。我不建议使用[self parent],因为当您首先必须确定“谁是父级”时,以后会很难阅读和调试,而是单例访问可以让您立即知道您正在访问谁。
  • 孩子永远不应该保留其父母。您可以引用父级,但不要保留。
  • 这里的单例方法的替代方法是在子节点中创建一个指向父节点的 iVar。但这本质上是相同的想法,因此为了最大限度地降低保留周期的风险,访问单例通常更安全。如果您的 iVar 设置不正确,您可能会有一个循环引用。您在此处显示的方法不是循环引用。

请注意,此特定代码会阻止您初始化 GameScene+(GameScene*) sharedGameScene之前使用方法。这就是使它成为半单例的原因。通常,如果单例中的这个方法还没有初始化,那么它会很聪明地初始化它自己,这样使用这个类方法要么返回,要么首先创建然后返回对象。

在 Cocos 中可能不是问题,因为您可能会在执行其他任何操作之前初始化游戏场景,因此它已经存在。

于 2012-05-05T04:30:44.313 回答