发生碰撞时,除我的播放器以外的物理物体不会调用didBeginContact [英] Physics bodies other than my player won't call didBeginContact when colliding

查看:81
本文介绍了发生碰撞时,除我的播放器以外的物理物体不会调用didBeginContact的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的游戏中,我有4个位掩码,并且一切都已设置,但是didBeginContact仅在第一个位掩码(playerCategory)与某些对象碰撞时才被调用.如果3与4发生碰撞,即使我设置了contactTestBitMask使其碰撞也没有任何反应.

myscene.h

    self.physicsWorld.gravity = CGVectorMake(0.0, -2.45);
    self.physicsWorld.contactDelegate = self;

    self.player = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size: CGSizeMake(10.0, 20.0)];
    self.player.position = CGPointMake(20.0, self.frame.size.height);
    self.player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.player.size];
    self.player.physicsBody.affectedByGravity = YES;
    self.player.physicsBody.dynamic = YES;
    self.player.physicsBody.categoryBitMask = playerCategory;
    self.player.physicsBody.contactTestBitMask = enemyCategory;
    self.player.physicsBody.collisionBitMask = tileCategory;
    [self.gameNode addChild:self.player];

    [...]

- (void) swipeRightHandler:(UISwipeGestureRecognizer *) recognizer {
    NSLog(@"swipe right");
    SKSpriteNode *attackRect = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(40, 5)];
    attackRect.position = CGPointMake(self.player.position.x + 10, self.player.position.y);
    attackRect.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:attackRect.size];
    attackRect.physicsBody.categoryBitMask = attackCategory;
    attackRect.physicsBody.contactTestBitMask = 255;
    attackRect.physicsBody.collisionBitMask = enemyCategory;
    attackRect.physicsBody.affectedByGravity = NO;
    attackRect.physicsBody.dynamic = NO;
    [self.gameNode addChild:attackRect];
    [attackRect runAction:[SKAction moveBy:CGVectorMake(250, 0) duration:1.0] completion:^{
        [attackRect removeFromParent];
    }];
}

RandomLevelGenerator.m:

        SKSpriteNode *enemy = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(20, 20)];
        enemy.position = CGPointMake(visual_x, FLOOR_X + arc4random_uniform(MAX_Y - FLOOR_X));
        enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:enemy.size];
        enemy.physicsBody.categoryBitMask = enemyCategory;
        enemy.physicsBody.contactTestBitMask = playerCategory | attackCategory;
        enemy.physicsBody.collisionBitMask = attackCategory;
        enemy.physicsBody.affectedByGravity = NO;
        enemy.physicsBody.dynamic = NO;
        [self.scene.gameNode addChild:enemy];

LevelGenerator.h:

static const uint32_t playerCategory    =   0x1 << 0;
static const uint32_t tileCategory      =   0x1 << 1;
static const uint32_t enemyCategory     =   0x1 << 2;
static const uint32_t attackCategory    =   0x1 << 3;

再次

MyScene.m:

SKPhysicsBody *firstBody, *secondBody;

if(contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
    firstBody = contact.bodyA;
    secondBody = contact.bodyB;
} else {
    firstBody = contact.bodyB;
    secondBody = contact.bodyA;
}
NSLog(@"%d - %d", firstBody.categoryBitMask, secondBody.categoryBitMask);

最后一个NSLog仅打印1-x,从不打印3-x.我也尝试过允许其他碰撞,但是我无法让它们发生碰撞.

解决方案

如果两个实体的AND在一起的categoryBitMask为零,则它们不会生成联系事件.例如,这发生在playerCategory(1)和敌人Category(4)上:1 & 4 = 0< ==永远不会在玩家和敌人之间生成任何接触事件.在那种情况下,它甚至都不会检查contactBitMask标志.

如果要使两个主体生成接触事件,则它们都必须设置相同的类别位掩码标记.

categoryBitMask的默认值为0xFFFFFFFF,以便所有物体都可以相互接触.与collisionBitMask相同,因为通常情况下默认情况下您希望所有物体接触并碰撞.

在大多数情况下,您真正​​需要修改的唯一位掩码是contactBitMask ,其默认值为0,这意味着默认情况下不会生成任何联系事件(以提高性能).

仅更改仅更改contactBitMask不足的其他位掩码.

例如,当您想要接触事件但没有碰撞反馈(=碰撞物体接触时的速度/位置变化)时,请确保将这些物体的collisionBitMask AND在一起为0.这允许物体进行碰撞.产生联系事件,但彼此通过.创建触发器非常有用,例如,当玩家进入某个区域时,您可以让他通过,也可以触发游戏事件.

或者当您要对两个不同类别的实体使用相同的接触位掩码时,它们仅应与共享同一类别的其他实体发生碰撞/接触-即常规字符和鬼影"字符应与其他所有对象具有相同的接触行为在游戏中,除了他们不应该与有形(非幽灵)的同伴接触/碰撞.在这种情况下,两个主体都使用相同的contactBitMaskcollisionBitMask.然后为所有其他类别设置categoryBitMask中的所有标志,但不要为代表有形和虚幻实体的两个类别设置标志.即,如果有形类别为2而幻像类别为8,则categoryBitMask应为:0xFFFFFFFF - 2 - 8 = 0xFFFFFFF5(低8位为:11110101)

长话短说:categoryBitMask标志应从0xFFFFFFFF中清除(而不是设置为特定位),以使特定类别中的各个主体不相互接触,但仍与所有其他主体接触. /p>

In my game I have 4 bitmasks and everything is setup, yet didBeginContact only gets called when the first bitmask (playerCategory) collides with something. if 3 collides with 4, nothing happens, even though I have the contactTestBitMask set for them to collide.

myscene.h

    self.physicsWorld.gravity = CGVectorMake(0.0, -2.45);
    self.physicsWorld.contactDelegate = self;

    self.player = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size: CGSizeMake(10.0, 20.0)];
    self.player.position = CGPointMake(20.0, self.frame.size.height);
    self.player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.player.size];
    self.player.physicsBody.affectedByGravity = YES;
    self.player.physicsBody.dynamic = YES;
    self.player.physicsBody.categoryBitMask = playerCategory;
    self.player.physicsBody.contactTestBitMask = enemyCategory;
    self.player.physicsBody.collisionBitMask = tileCategory;
    [self.gameNode addChild:self.player];

    [...]

- (void) swipeRightHandler:(UISwipeGestureRecognizer *) recognizer {
    NSLog(@"swipe right");
    SKSpriteNode *attackRect = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(40, 5)];
    attackRect.position = CGPointMake(self.player.position.x + 10, self.player.position.y);
    attackRect.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:attackRect.size];
    attackRect.physicsBody.categoryBitMask = attackCategory;
    attackRect.physicsBody.contactTestBitMask = 255;
    attackRect.physicsBody.collisionBitMask = enemyCategory;
    attackRect.physicsBody.affectedByGravity = NO;
    attackRect.physicsBody.dynamic = NO;
    [self.gameNode addChild:attackRect];
    [attackRect runAction:[SKAction moveBy:CGVectorMake(250, 0) duration:1.0] completion:^{
        [attackRect removeFromParent];
    }];
}

RandomLevelGenerator.m:

        SKSpriteNode *enemy = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(20, 20)];
        enemy.position = CGPointMake(visual_x, FLOOR_X + arc4random_uniform(MAX_Y - FLOOR_X));
        enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:enemy.size];
        enemy.physicsBody.categoryBitMask = enemyCategory;
        enemy.physicsBody.contactTestBitMask = playerCategory | attackCategory;
        enemy.physicsBody.collisionBitMask = attackCategory;
        enemy.physicsBody.affectedByGravity = NO;
        enemy.physicsBody.dynamic = NO;
        [self.scene.gameNode addChild:enemy];

LevelGenerator.h:

static const uint32_t playerCategory    =   0x1 << 0;
static const uint32_t tileCategory      =   0x1 << 1;
static const uint32_t enemyCategory     =   0x1 << 2;
static const uint32_t attackCategory    =   0x1 << 3;

MyScene.m again:

SKPhysicsBody *firstBody, *secondBody;

if(contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
    firstBody = contact.bodyA;
    secondBody = contact.bodyB;
} else {
    firstBody = contact.bodyB;
    secondBody = contact.bodyA;
}
NSLog(@"%d - %d", firstBody.categoryBitMask, secondBody.categoryBitMask);

That last NSLog, only ever prints 1 - x, never 3 - x. I've also tried allowing other collisions and I can't get any of them to collide.

解决方案

If the categoryBitMask for two bodies ANDed together is zero, they will not generate contact events. For instance this happens with playerCategory (1) and enemyCategory (4): 1 & 4 = 0 <== no contact events are generated, ever, between players and enemies. In that case it won't even get to check the contactBitMask flags.

If you want two bodies to generate contact events, they both have to have the same category bitmask flag set.

The default for categoryBitMask is 0xFFFFFFFF so that all bodies can contact with each other. Same for collisionBitMask because generally you want all bodies to contact and collide by default.

The only bit mask you really need to modify in most cases is the contactBitMask, whose default is 0, meaning no contact events are generated by default (to improve performance).

Only change the other bitmasks where changing contactBitMask alone does not suffice.

For example when you want contact events, but no collision feedback (= change in velocity/position of colliding bodies when they come in contact), then make sure that those body's collisionBitMask ANDed together is 0. This allows bodies to generate contact events, but pass through each other. Useful to create triggers, ie when the player enters an area you can let him pass but also trigger a game event.

Or when you want to use the same contact bitmasks for two different categories of bodies who should only collide/contact with other bodies sharing the same category - ie regular and "ghost" characters who should have the same contact behavior with everything else in the game, except they shouldn't contact/collide with their corporeal (non-ghost) counterparts. In that case, use the same contactBitMask and collisionBitMask for both bodies. Then set all flags in categoryBitMask for all other categories, but don't set the flags for the two categories representing the corporeal and ghost entities. Ie if corporeal category is 2 and ghost category is 8, the categoryBitMask should be: 0xFFFFFFFF - 2 - 8 = 0xFFFFFFF5 (lower 8 bits would be: 11110101)

Long story short: categoryBitMask flags should be cleared from 0xFFFFFFFF (rather than set to a specific bit) so that individual bodies in specific categories don't contact with each other but still contact with all other bodies.

这篇关于发生碰撞时,除我的播放器以外的物理物体不会调用didBeginContact的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆