简单的介绍
这绝对可以做到,而且不需要复杂的计算。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