6

我遇到了一些碰撞问题。我有两个大小和质量相同的物体。当一个人与另一个静止的人发生碰撞时,我会得到正确的行为(图像中的灰色区域)。当我有两个彼此相邻的对象时,行为不太正确。Spritekit 结果在左侧。右边的预期/需要的结果。

我想我知道发生了什么,但不知道该怎么办。如果对象是一个具有两倍质量的对象,那么 spritekit 的行为将是正确的,但它们是独立的对象,最上面的对象应该采用传入粒子的速度。似乎将它们视为一个对象。

在两者接触后,我尝试作弊并缩小半径以缩小差距,但随后一切都变得一团糟。有人知道我可以在这里做什么吗?谢谢。

在此处输入图像描述

4

2 回答 2

3

简单的介绍

这绝对可以做到,而且不需要复杂的计算。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
于 2015-05-18T21:29:43.370 回答
0

你可以做什么,这只是理论上的,因为我自己还没有尝试过,是在碰撞回调中检查其中一个碰撞器是否与第三个对象相交/碰撞并手动计算它的速度。

我怀疑你不会得到 2 个堆叠球的碰撞检测(因为它们从那个位置开始)所以手动检查这个并将适当的速度应用于相邻的物体可能会起到作用。

可能必须跟踪哪些“身体对”已经计算了它们的新速度以避免计算周期(可能是无限的)。

于 2014-12-16T09:18:01.217 回答