2014-10-26 93 views
1

我目前正在使用Objective-C和SpriteKit与朋友一起工作。我和我的朋友都是SpriteKit的新手,所以我们正在研究的这个项目更多的只是一种学习体验。但是,当然,我们遇到了一些麻烦。同一类型的多个对象上的SpriteKit碰撞检测

游戏相当简单:有一个球飞过屏幕并从“墙壁”或iPhone屏幕边缘弹开。用户控制屏幕底部的桨,使球返回,防止球触及屏幕底部。每次击球时,屏幕顶部的得分计数器都会增加1。

这是我们正在努力完成的。当比赛的比分等于5时,我们为场景添加一个新球。新球开始自行移动,但每当我们尝试检测新球是否碰到屏幕边缘时,碰撞就不会被检测到。

这里是我们的方法,该方法返回一个球对象:

+(id)ball 
{ 
    // the ball is a random image from google 
    Ball *ball = [Ball spriteNodeWithImageNamed:@"ball"]; 

    // set the position of the ball 
    ball.position = CGPointMake(0, 80); 

    // set ball name property 
    ball.name = @"ball"; 

    // give the ball a physics body 
    ball.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:ball.size]; 

    ball.physicsBody.affectedByGravity = NO; 

    return ball; 
} 

这种方法被称为移动球的场景:

-(void)move:(int)deltaX withDeltaY:(int)deltaY 
{ 
    SKAction *testMoveRight = [SKAction moveByX:deltaX y:deltaY duration:0.03]; 

    // this will repeat the action over and over 
    SKAction *move = [SKAction repeatActionForever:testMoveRight]; 
    [self runAction:move]; 
} 

这些是我们的碰撞检测类:

// this category is for the original ball in the game 
static const uint32_t ballCategory = 0x1 << 0; 
// this category is for the second ball that gets added to the game 
static const uint32_t ball2Category = 0x1 << 1; 
static const uint32_t paddleCategory = 0x1 << 2; 
static const uint32_t topBarrierCategory = 0x1 << 3; 
static const uint32_t leftBarrierCategory = 0x1 << 4; 
static const uint32_t rightBarrierCategory = 0x1 << 5; 
static const uint32_t gameOverBarrierCategory = 0x1 << 6; 

这里是我们的didBeginContact方法:

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


    // first ball contact 
    if ((firstBody.categoryBitMask & ballCategory) != 0 && (secondBody.categoryBitMask & rightBarrierCategory) != 0) { 
     [ball move:-15 withDeltaY:0]; 
    } 

    else if ((firstBody.categoryBitMask & ballCategory) != 0 && (secondBody.categoryBitMask & topBarrierCategory) != 0) { 
     [ball move:0 withDeltaY:-20]; 
    } 

    else if ((firstBody.categoryBitMask & ballCategory) != 0 && (secondBody.categoryBitMask & leftBarrierCategory) != 0) { 
     [ball move:15 withDeltaY:0]; 
    } 

    else if ((firstBody.categoryBitMask & ballCategory) != 0 && (secondBody.categoryBitMask & paddleCategory) != 0) { 
     [ball move:0 withDeltaY:20]; 

     // increment score 
     self.score++; 
     // update the score label 
     self.deathLabel.text = [NSString stringWithFormat:@"%i", self.score]; 

     // add a new ball to the scene if the score is 5 
     if (score == 5) { 
      [scene addChild:ball2]; 
      [ball2 move:5 withDeltaY:10]; 
     } 
    } 

    // second ball contact detection 
    if ((firstBody.categoryBitMask & ball2Category) != 0 && (secondBody.categoryBitMask & rightBarrierCategory) != 0) { 
     [ball2 move:-15 withDeltaY:0]; 
    } 
} 

为什么我们添加到场景中的第二个球没有检测到它与正确的屏障(屏幕右边缘)相撞?当它到达屏幕的右边缘时,它不会反弹并像我们想要的那样向左移动。有什么建议么?

回答

1

仅仅添加一个physicsBody到球上是不够的,你还必须设置类别,接触和碰撞位掩码。首先,我的球physicsBody改变

ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.frame.size.width/2];

通知物理学的身体是第一更高效,并为您的情况下第二好。除此之外,每个障碍你都不需要单独的类别。结合他们都为一个:

self.size = self.view.bounds.size; 

CGMutablePathRef path = CGPathCreateMutable(); 
CGPathMoveToPoint(path, NULL, 0, 0); 
CGPathAddLineToPoint(path, NULL, 0, self.frame.size.height); 
CGPathAddLineToPoint(path, NULL, self.frame.size.width, self.frame.size.height); 
CGPathAddLineToPoint(path , NULL, self.frame.size.width, 0); 
CGPathAddLineToPoint(path, NULL, 0, 0); 
SKShapeNode *bounds = [SKShapeNode shapeNodeWithPath:path]; 
bounds.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromPath:path]; 
CGPathRelease(path); 
bounds.physicsBody.categoryBitMask = boundsCategory; 

正如你所看到的,每个SpriteNode有categoryBitmask,它有两种碰撞位掩码(这意味着它反弹/与这些类别碰撞)和接触位掩码(我没有在这里设置一个,但是当这个联系发生时,调用didBeginContact方法)。在你的代码中,didBeginContact方法不会被调用,但你也不需要它来弹跳。为了澄清,这种反弹会自行发生,这意味着你不需要任何接触方法或掩码,只需对球施加一定的力量/冲动,并接触它会反弹的边界。

至于球,你不需要每个球的另一个类别 - 这是冗余。对于创建的每一个球,刚刚成立的categoryBitmask同一件事:

ball.physicsBody.categoryBitMask = ballCategory; 
ball.physicsBody.collisionBitMask = boundsCategory; 

加上几行,你告诉编译器,每个球“ballCategory”的,它应该与任何对象是“碰撞boundsCategory”。希望这有帮助,祝你好运!

+0

感谢您的澄清。你有没有想过我是否可以让球的物理体在从障碍物弹回时不会失去“速度”,并让它向相反的方向移动?正如你上面所建议的那样,我已经设定了球的类别边界掩蔽和碰撞边界掩蔽,但是最终在两个障碍反弹之后球失去了速度。有什么建议么?我仍然对我应该如何使用didBeginContact方法感到困惑。 – Surfero 2014-10-27 01:41:15

+0

didBeginContact用于当两个对象彼此接触时(对象不会互相反弹,didBeginContact将被调用,但对象将继续移动/执行它们的操作)时要调用的方法。对于球不断弹跳,将其恢复到1.0f: 'ball.physicsBody.restitution = 1.0f' 恢复原状是'弹性'的值,其中1.0f表示弹跳时不会失速,0.0f表示只要碰撞它停止(0反弹)。如果这回答你的问题,我将不胜感激,如果你标记我的答案是正确的。谢谢! – Andriko13 2014-10-27 02:03:28

+0

至于朝相反的方向移动,您可能需要明确指出您的意思。 – Andriko13 2014-10-27 02:04:08