我从本教程中下载了Ray Wenderlich的简单联系人监听器:http://www.raywenderlich.com/606/how-to-use-box2d-for-just-collision-detection-with-cocos2d-iphone
目前我正在使用下面的代码,它几乎是我在CCLayer中实现Ray的自定义b2ContactListener。但问题是,一次碰撞有多个回调。
有人可以告诉我如何制作它,以便碰撞只会触发一次,直到2个物体都不再触摸然后再润饰?
这是我目前使用的代码:
std::vector<b2Body *>toDestroy;
std::vector<MyContact>::iterator pos;
for(pos = _contactListener->_contacts.begin(); pos != _contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
// Get the box2d bodies for each object
b2Body *bodyA = contact.fixtureA->GetBody();
b2Body *bodyB = contact.fixtureB->GetBody();
if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) {
CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
CCSprite *spriteB = (CCSprite *) bodyB->GetUserData();
if ((spriteA.tag == 1 && spriteB.tag == 2) || (spriteA.tag == 2 && spriteB.tag == 1)) {
NSLog(@"tag 1 hit tag 2");
}
谢谢!
EDIT1:
if ((hasDetectedCollision == NO) && ( (spriteA.tag == 1 && spriteB.tag == 2) || (spriteA.tag == 2 && spriteB.tag == 1) ) ) {
hasDetectedCollision = YES;
NSLog(@"tag 1 hit tag 2");
[self doSomethingWhenCollisionHappens];
}
- (void)doSomethingWhenCollisionHappens {
//here you might want to remove an object because of a collision
//or maybe change the color of the objects that collided
//I can't provide more details of what you might want
//to do without seeing more of your code
//but when you are ready to start receiving collision updates again
//set hasDetectedCollision to NO again
[yesLabel setString:[NSString stringWithFormat:@"Yes: %d", yesNumber++]];
hasDetectedCollision = NO;
}
然后在我的init方法中:
hasDetectedCollision = NO;
新编辑:
if (!hasDetectedCollision && ((spriteA.tag == 1 && spriteB.tag == 4) || (spriteA.tag == 4 && spriteB.tag == 1))) {
hasDetectedCollision = YES;
[yesLabel setString:[NSString stringWithFormat:@"Yes:%d", yesInt++]];
NSLog(@"tag 1 hit tag 4");
}
答案 0 :(得分:1)
我对Box2d并不熟悉,但是根据你在问题中描述的内容,这应该可以帮到你:
在你的.h:
@interface foo : FooBar {
BOOL hasDetectedCollision;
}
并在你的.m:
- (void)viewDidLoad {
hasDetectedCollision = NO;
}
然后简单地替换
if ((spriteA.tag == 1 && spriteB.tag == 2) || (spriteA.tag == 2 && spriteB.tag == 1)) {
NSLog(@"tag 1 hit tag 2");
}
与
if ((hasDetectedCollision == NO) && ( (spriteA.tag == 1 && spriteB.tag == 2) || (spriteA.tag == 2 && spriteB.tag == 1) ) ) {
hasDetectedCollision = YES;
NSLog(@"tag 1 hit tag 2");
[self doSomethingWhenCollisionHappens];
}
然后:
- (void)doSomethingWhenCollisionHappens {
//here you might want to remove an object because of a collision
//or maybe change the color of the objects that collided
//I can't provide more details of what you might want
//to do without seeing more of your code
//but when you are ready to start receiving collision updates again
//set hasDetectedCollision to NO again
hasDetectedCollision = NO;
}
然后,当您在检测到碰撞时完成您想做的任何事情时,将hasDetectedCollision设置为no,然后重新开始。
编辑:
std::vector<b2Body *>toDestroy;
std::vector<MyContact>::iterator pos;
for(pos = _contactListener->_contacts.begin(); pos != _contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
// Get the box2d bodies for each object
b2Body *bodyA = contact.fixtureA->GetBody();
b2Body *bodyB = contact.fixtureB->GetBody();
if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) {
CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
CCSprite *spriteB = (CCSprite *) bodyB->GetUserData();
if(hasDetectedCollision == NO)
NSLog(@"hasDetectedCollision == NO");
if ((spriteA.tag == 1 && spriteB.tag == 2) || (spriteA.tag == 2 && spriteB.tag == 1)) {
NSLog(@"tag 1 hit tag 2");
}
如果检查hasDetectedCollision状态的if语句被执行,那么问题不在于布尔值,而在于你的碰撞检测。
答案 1 :(得分:0)
我不完全确定关于多个答案的SO规则是什么,但这是检查冲突的替代方法,我一直在使用它:
在viewDidLoad方法中:
NSTimer *g = [[NSTimer alloc] initWithFireDate:[NSDate date]
interval:.1
target:self
selector:@selector(checkForCollisions)
userInfo:nil repeats:YES];
NSRunLoop *r = [NSRunLoop currentRunLoop];
[r addTimer:g forMode: NSDefaultRunLoopMode];
[g release];
在checkForCollisions方法中:
//without knowing what you are checking collisions for and
//why you are checking for collisions, I can't be too specific here
//but this code will do what you want
for(someObject* objectOfInterest in yourArrayOfObjectsToBeCompared)) {
CALayer* layerOne = objectOfInterest.layer.presentationLayer;
CGRect rectOne = layerOne.frame;
for(someObject* compareObject in yourArrayOfObjectsToBeCompared) {
CALayer* layerTwo = compareObject.layer.presentationLayer;
CGRect rectTwo = layerTwo.frame;
if(CGRectIntersectsRect(rectOne, rectTwo) && ![compareObject isEqual:objectOfInterest]) {
//collision detected
}
}
此代码只循环遍历您的对象数组以进行比较,然后为每个对象的表示层制作CALayer副本。这一步是至关重要的,因为取对象的常规帧不会给出它当前的位置;这将给出其目的地位置。然后代码再次执行相同的操作,将其与数组中的每个其他对象进行比较。