子精灵的精灵套件碰撞检测

Posted

技术标签:

【中文标题】子精灵的精灵套件碰撞检测【英文标题】: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)  

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

【问题讨论】:

【参考方案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

【讨论】:

以上是关于子精灵的精灵套件碰撞检测的主要内容,如果未能解决你的问题,请参考以下文章

检测精灵套件中的碰撞

pygame之精灵碰撞检测

Python进阶篇十一Pygame的精灵和碰撞检测

动画精灵与碰撞检测

使用固定的 SKPhysicsJoint 将作为孩子的平台检测命中框附加到玩家精灵会更改玩家的碰撞和检测位掩码

如何检测pygame中的碰撞?