【问题标题】:sprite kit collision detection with child sprite子精灵的精灵套件碰撞检测
【发布时间】:2014-02-19 03:48:12
【问题描述】:

我正在尝试检测两个精灵之间的碰撞,但我无法对子精灵执行此操作。

self.player = [[Player alloc] initWithImageNamed:@"player"];
self.player.position = CGPointMake(150, 75);
[self addChild:self.player];

      _object = [SKSpriteNode spriteNodeWithImageNamed:@"object"];
      _object.position = CGPointMake(-40, 27);
       [self.player addChild:_object];

然后我有这样的碰撞检测

- (void)checkCollisions {
[self.map enumerateChildNodesWithName:@"enemy"
usingBlock:^(SKNode *node, BOOL *stop){SKSpriteNode *enemy = (SKSpriteNode *)node;
if (CGRectIntersectsRect(enemy.frame, _object.frame)) {
[enemy removeFromParent];
}
}]; }

*这不起作用!!!但如果我使用:

CGRectIntersectsRect(enemy.frame, self.player.frame)  

我可以检测到与主体的碰撞。如何为另一个精灵的孩子进行碰撞检测?

【问题讨论】:

    标签: ios iphone sprite-kit


    【解决方案1】:

    子节点的positionframe 属性相对于它的parent,您需要在代码中加以说明。

    SKNode 有两种方法可以帮助您将给定SKNodeposition 与另一个节点的坐标空间相互转换:

    convertPoint:fromNode:
    convertPoint:toNode:
    

    您可以使用它们将SKNodeposition 属性转换为另一个坐标空间。您要做的是将_object 的位置转换为敌人的坐标空间,反之亦然,然后使用带有新位置的临时CGRect 进行CGRectIntersectsRect 检查。

    这是一个例子:

    CGPoint globalPosition = [self.player convertPoint:_object.position toNode:self.player.parent];
    CGRect tempRect = CGRectMake(globalPosition.x, globalPosition.y, _object.frame.size.width, _object.frame.size.height);
    
    if (CGRectIntersectsRect(enemy.frame, _object.frame))
    {
       // collision occurred
    }
    

    这段代码假设你的敌人和你的玩家在同一个坐标空间中。 (有相同的父)

    【讨论】:

    • 我的回答是澄清为什么您的代码没有按预期工作。学习 SpriteKit 的内置碰撞如何工作是值得的。值得花时间通过 Sprite Kit 参考或教程了解它,这样您就可以清楚地了解它的工作原理。
    • 感谢我目前使用物理引擎的项目太过分了。这就是我改用 CGRectIntersectsRect 的原因。
    【解决方案2】:

    这是因为_objectself.player 的子节点,而enemy 节点是self.map 节点的子节点。如果要比较它们的帧,两个节点应该具有相同的父节点。

    我建议你使用 Sprite Kit 内置的碰撞处理机制:

    // Object:
    _object = [SKSpriteNode spriteNodeWithImageNamed:@"object"];
    _object.position = CGPointMake(-40, 27);
    _object.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_object.frame.size;
    _object.physicsBody.categoryBitMask = OBJECT_CATEGORY;
    _object.physicsBody.contactTestBitMask = ENEMY_CATEGORY;
    _object.physicsBody.collisionBitMask = 0;
    [self.player addChild:_object];
    
    // Enemy:
    // init enemy: SKSpriteNode *enemy = [SKSpriteNode spriteNodeWithImageNamed:@"enemy"];
    enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:enemy.frame.size;
    enemy.physicsBody.categoryBitMask = ENEMY_CATEGORY;
    enemy.physicsBody.contactTestBitMask = OBJECT_CATEGORY;
    enemy.physicsBody.collisionBitMask = 0;
    // add enemy to the scene: [self addChild:enemy];
    
    // Define that your SKScene conforms to SKPhysicsContactDelegate protocol:
    .....
    @interface MyScene : SKScene <SKPhysicsContactDelegate>
    ....
    
    
    // SKScene.m:
    static uint32_t const OBJECT_CATEGORY = 0x1 << 0;
    static uint32_t const ENEMY_CATEGORY = 0x1 << 1;
    
    @implementation MyScene
    
    - (id)initWithSize:(CGSize)size {
        if (self = [super initWithSize:size]) {
            .......
            self.physicsWorld.contactDelegate = self;
            ........
        }
        return self;
    }
    
    .......
    
    - (void)didBeginContact:(SKPhysicsContact *)contact{
        SKPhysicsBody *firstBody, *secondBody;
        if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
            firstBody = contact.bodyA;
            secondBody = contact.bodyB;
        }
        else {
            firstBody = contact.bodyB;
            secondBody = contact.bodyA;
        }
    
        if (((firstBody.categoryBitMask & OBJECT_CATEGORY) != 0) &&
                 (secondBody.categoryBitMask & ENEMY_CATEGORY) != 0) {
            NSLog(@"Collision detected!");
        }
    
    @end
    

    【讨论】: