2009-12-02 139 views
2

让我看看我是否可以清楚说明我正在尝试做什么...我会提炼出它的核心问题。c和客观c变量

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

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

问题出在这里: 但是score是“GAME”对象的一个​​实例变量,我没有该实例变量的可见性。我想我可以通过名为& addscore或其他参数传递给c函数的另一个参数,但想知道是否有一个更明显的方法来做到这一点,因为可能有一堆超过'score'的其他变量必须更新碰撞。

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

在此先感谢。

+0

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

回答

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); 
} 

如果现有游戏对象具有合适的性质或信息,则可以甚至可以执行类似以下的操作,只需传递整个Objective-C对象:

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

第三种方法是更改​​C函数的返回值以指示是否检测到冲突,然后将其保留在GAME类中的Objective-C代码中以更新分数和可能需要的任何其他操作发生。

+0

非常感谢克里斯托弗。我最终做了选项#2。这是一个很酷的模式,能够通过简单的指针访问整个obj-c对象并在C中访问它们。这么多用途。我还假设你可以传递泛型void指针并在函数内强制转换,以使用例更一般化。干杯。 – Ferris 2009-12-03 02:00:35

0

不,你做不是需要你的对象中的变量可以被函数看到。这打破封装,这是一个坏主意。当你想要一个对象做某件事情时(比如改变一些内部价值,如分数),你应该提供一种方法来实现这种效果。

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

+0

是的,实际上这就是我所做的......一旦检索到对象指针,我就使用标准的obj-c构建了访问器方法来执行我的内部变量更新。感谢您的跟进。 – Ferris 2009-12-03 07:51:12

0

如果游戏对象是单身人士,你可以从任何范围(包括你的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. 
} 
1

为了提高对最后的答案多一点,你可以做到以下几点:

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源内部完成的,并且它更加干净。