【问题标题】:c and objective-c variablesc和objective-c变量
【发布时间】:2009-12-02 17:26:56
【问题描述】:

让我看看我是否能清楚地表达我想要做什么......我将把它提炼到核心问题。

我有一个objective-c 程序和一个c 回调函数。上下文是我在 iphone sdk 中使用 cocos2d 和花栗鼠物理。我想做的是在子弹和怪物发生碰撞时更新“分数”。一切正常,除了更新分数。

游戏逻辑在 obj-c 中,但实际的碰撞逻辑在 c 函数中完成,当发生碰撞时会调用该函数。例如,我在那里渲染了碰撞的火焰/爆炸。我也想更新分数。

问题来了: 但是 score 是“GAME”对象的一个​​实例变量,我看不到那个实例变量。我想我可以通过引用将另一个参数传递给 c 函数,称为 &addscore 或其他东西,但想知道是否有更明显的方法可以做到这一点,因为除了 'score' 之外可能还有一堆其他变量必须在碰撞。

网络是我需要对象中的变量才能被 c 函数看到,反之亦然:那些在函数中设置的变量才能在对象中看到。

提前致谢。

【问题讨论】:

  • 请注意,当您使用 Xcode 编译代码时,它实际上会编译为 Objective-C 或 Objective-C++。所以我们喜欢称之为“C 回调函数”,将能够在其中使用Objective-C 语法。所以你可以只传递你的对象,或者使用单例。

标签: iphone c objective-c cocos2d-iphone chipmunk


【解决方案1】:

您关于通过引用传递来访问 C 代码中的 Obj-C 实例变量的知识和想法似乎是正确的。

如果您需要传递许多变量,我假设它们共同构成某种“游戏状态”描述。也许这些可以组合成一个单独的对象或结构,并通过单个参数传递给 C 函数?

例如,下面的类:

typedef struct GameState {
  int score;
  int numberOfBulletsLeft;
} GameState;

@interface GAME : NSObject {
  GameState state;
}

...

@end

可以很好地使用如下的 C 函数

void myCFunctionThatDoesCollisiondetectionEtc(GameState * state) {
  NSLog(@"You have %d bullets left", state->numberOfBulletsLeft);
}

如果您现有的 GAME 对象具有合适的属性或消息,您甚至可以执行以下操作,只需传递整个 Objective-C 对象:

void myCFunctionThatDoesCollisionDetectionEtc(GAME * myGame) {
  if (...)
    [myGame increaseScore:50];
  else
    [myGame decreaseScore:50];
}

第三种选择是更改 C 函数的返回值以指示是否检测到碰撞,然后将其留给 GAME 类中的 Objective-C 代码来更新分数和任何其他可能的操作需要发生。

【讨论】:

  • 非常感谢克里斯托弗。我最终做了选项#2。这是一个很酷的模式,能够通过简单的指针访问整个 obj-c 对象并在 C 中访问它们。如此多的用途。我还假设您可以传递通用 void 指针并将它们强制转换为函数以使用例更通用。干杯。
【解决方案2】:

要进一步改进最后一个答案,您可以执行以下操作:

cpSpaceAddCollisionPairFunc( space, 1, 2, (cpCollFunc)functionName, game);

void functionName( cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, GameClass *game) {
    [game doSomethingToScoreSomething];
}

不需要在函数内部强制转换指针,您可以改为强制转换函数指针。这就是我在内部使用 Chipmunk 源代码所做的,而且它更干净。

【讨论】:

    【解决方案3】:

    不,您确实需要对象中的变量对函数可见。这破坏了封装,这是一个坏主意。当你想让一个对象做某事(比如改变一些内部值,比如分数)时,你应该提供一个方法来实现这个效果。

    如果你允许你的类之外的代码改变你的实例变量,那么你就放弃了面向对象编程的一个关键优势。

    【讨论】:

    • 是的,实际上这就是我所做的......一旦检索到对象指针,我就构建了访问器方法来使用标准 obj-c 执行我的内部变量更新。感谢您的跟进。
    【解决方案4】:

    如果游戏对象是单例,您可以从任何范围(包括您的 C 回调)访问它。如果您只希望某个对象的一个​​实例存在,您将创建一个单例。通过向类发送消息以检索单例实例,始终可以从任何地方访问单例:

    [Game sharedGameInstance];
    

    或者,花栗鼠允许您将void * data 传递给回调。这是为了适应程序员向回调发送他需要的信息。

    您可以在void * 中向回调发送指向您的游戏对象实例的指针,如下所示:

    cpSpaceAddCollisionPairFunc( space, 1, 2, &functionName, (void *)game );
    
    void functionName( cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, void *data ) {
        GameClass * game = (GameClass *)data;
        // do whatever you need here. You can call messages on game as per usual.
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-31
      • 2011-04-27
      相关资源
      最近更新 更多