简单的介绍
这绝对可以做到,并且不需要复杂的计算。 SpriteKit 完全有能力处理这种碰撞。我认为你误解了这里的物理原理。在物理学中,有一个你正在打破的简单规则需要牢记。这里用现实生活中的话来说:
没有两个物体可以占据空间中的同一点。这也适用于物体的一部分。任何两个物体的任何部分都不能占据空间中的同一点。考虑到这一点,我们可以说,无论两个物体有多近,它们之间总是存在一些空间。
换句话说,两个相邻物体之间的空间量必须大于零。无论这个空间多么无限小,它仍然必须存在。
问题
您的根本问题是蓝色圆圈之间的间距为零。假设圆的半径为 30,顶部圆的 y 位置为 400。
您对定位中间圆的数学计算可能是topCircle.position.y - (topCircle.height + middleCircle.height) / 2
。由于您的圆的半径都相同(在我们的示例中为 30),因此您可能将其简化为topCircle.y - CIRCLE_DIAMETER
。如果您绝对定位圆圈,这可能就是您在头脑中执行的计算。
无论使用哪个等式,当您代入数字时,第二个球的 y 位置都是 340。
第一个方程:400 - (60 + 60) / 2 = 340
第二个方程:400 - 60 = 340
(注意:第一个方程更灵活,允许您使用任何大小的圆圈而不是统一大小的圆圈)
问题就在这里。现在应该很清楚,顶部圆的底部与中间圆的顶部在空间中占据相同的点。
顶部圆圈:400 - 30 = 370
中圈:340 + 30 = 370
之间的空间:|370 - 370| = 0
这两个物理体试图占据空间中的同一点,因此已合并为一个体,从而呈现出您所看到的行为。
解决方案
话虽如此,如果您只需在圆圈之间添加一点(或更少)的空间,您就会得到您想要的行为。
(注意:还要确保将每个圆圈的物理体的恢复设置为 1)
这适用于任意数量的圆圈。下面是一个简单的示例场景,其中 1 个圆圈与其他 4 个圆圈联系,展示了这种行为。我在 iPhone 6 上运行了这个:
#import "GameScene.h"
@interface GameScene()
@property (strong, nonatomic) NSArray *nodes;
@end
@implementation GameScene
#pragma mark - View Lifecycle
-(void)didMoveToView:(SKView *)view
{
self.backgroundColor = [SKColor blackColor];
[self createNodes];
[self positionNodes];
[self addNodes];
}
#pragma mark - Setup
- (void)createNodes
{
// You could use SKShapeNode as well
self.nodes = @[[SKSpriteNode spriteNodeWithImageNamed:@"circle"],
[SKSpriteNode spriteNodeWithImageNamed:@"circle"],
[SKSpriteNode spriteNodeWithImageNamed:@"circle"],
[SKSpriteNode spriteNodeWithImageNamed:@"circle"],
[SKSpriteNode spriteNodeWithImageNamed:@"circle"]];
// Use this if you don't have a 30-radius circle image at hand
// self.nodes = @[[SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(60, 60)],
// [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(60, 60)],
// [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(60, 60)],
// [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(60, 60)],
// [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(60, 60)]];
for(SKSpriteNode *node in self.nodes)
{
node.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:30];
node.physicsBody.affectedByGravity = NO;
node.physicsBody.restitution = 1;
}
}
- (void)positionNodes
{
SKSpriteNode *node = self.nodes.firstObject;
node.position = CGPointMake(300, 400);
for(NSInteger i = 1; i < self.nodes.count - 1; i++)
{
SKSpriteNode *prevNode = node;
node = self.nodes[i];
node.position = CGPointMake(300, prevNode.position.y - (prevNode.frame.size.height + node.frame.size.height) / 2 - 1);
}
node = self.nodes.lastObject;
node.position = CGPointMake(300, 100);
// Above created nodes at these positions:
// (300, 400);
// (300, 339);
// (300, 278);
// (300, 217);
// (300, 100);
}
- (void)addNodes
{
for(SKSpriteNode *node in self.nodes)
{
[self addChild:node];
}
}
#pragma mark - Touch Events
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
SKSpriteNode *node = self.nodes.lastObject;
[node.physicsBody applyImpulse:CGVectorMake(0, 20)];
}
@end