【问题标题】:Spritekit physics: One ball hit another ballSpritekit 物理:一个球撞到另一个球
【发布时间】:2014-05-09 07:55:46
【问题描述】:

我是 SpriteKit 的新手。

我正在尝试解决这个问题: 我的场景中有两个球,当我拖动一个球并“击中”另一个球时,这个球应该使用正确的物理原理滚开。

在我的测试代码中,我只能“移动”第二个球,他没有使用击球的“力”...

这是我的场景代码:

#import "HittingScene.h"

@interface HittingScene()

@property (nonatomic, strong) SKShapeNode *targetBall;
@property (nonatomic, strong) SKShapeNode *mainBall;
@property (nonatomic, weak) SKShapeNode *draggedNode;

@end

@implementation HittingScene

- (id)initWithSize:(CGSize)size
{
    if (self = [super initWithSize:size]) {
        [self addChild:[self createMainBall]];
        [self addChild:[self createTargetBall]];

        [self setPhysicsBody:[SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame]];
    }
    return self;
}

- (SKShapeNode *)createTargetBall
{
    self.targetBall = [SKShapeNode node];

    CGPathRef path = CGPathCreateWithEllipseInRect((CGRect){{-20, -20}, {40, 40}}, NULL);
    [self.targetBall setPath:path];
    CGPathRelease(path);

    [self.targetBall setPosition:CGPointMake(200, 200)];
    [self.targetBall setName:@"targetBall"];

    [self.targetBall setPhysicsBody:[SKPhysicsBody bodyWithCircleOfRadius:20.0]];
    self.targetBall.physicsBody.dynamic = YES;
    self.targetBall.physicsBody.affectedByGravity = NO;
    self.targetBall.physicsBody.restitution = 0.7;

    return self.targetBall;
}

- (SKShapeNode *)createMainBall
{
    self.mainBall = [SKShapeNode node];

    CGPathRef path = CGPathCreateWithEllipseInRect((CGRect){{-20, -20}, {40, 40}}, NULL);
    [self.mainBall setPath:path];
    CGPathRelease(path);

    [self.mainBall setPosition:CGPointMake(100, 100)];
    [self.mainBall setName:@"mainBall"];

    [self.mainBall setPhysicsBody:[SKPhysicsBody bodyWithCircleOfRadius:20.0]];
    self.mainBall.physicsBody.dynamic = YES;
    self.mainBall.physicsBody.affectedByGravity = NO;
    self.mainBall.physicsBody.restitution = 0.7;

    return self.mainBall;
}

- (void)touchesBegan:(NSSet*) touches withEvent:(UIEvent*) event
{
    self.draggedNode = (SKShapeNode *)[self nodeAtPoint:[[touches anyObject]     locationInNode:self]];
}

- (void)touchesMoved:(NSSet*) touches withEvent:(UIEvent*) event
{
    self.draggedNode.position = [[touches anyObject] locationInNode:self];
}

- (void)touchesEnded:(NSSet*) touches withEvent:(UIEvent*) event
{
    self.draggedNode = nil;
}
@end

有人知道如何解决这个问题吗?

谢谢, 乌尔克曼

【问题讨论】:

  • 那是因为你经常改变节点(身体)的位置,因此身体没有从运动中积累的力(即速度保持为0)。为此,您必须通过 applyForce/Impulse 移动对象,或者根据球的先前位置自行计算冲击冲量,并由此得出运动速度并将其应用于任何接触的身体。
  • 听起来很清楚 :) 但是我如何使用 applyForce 或 applyImpact 移动主球?我已经在网上搜索过,但没有找到任何东西:(
  • 如果您找到了解决方案,请将其发布为答案。

标签: ios sprite-kit game-physics


【解决方案1】:

我认为问题在于你只是在改变触球时的位置。这样做只是将节点放在一个新点上,实际上并不涉及任何力量。您需要设置一个碰撞系统,当主球与目标球发生碰撞时,该系统会对目标球施加一定的力。

SKPhysicsBody 中的

applyForce:atPoint: 看起来是个不错的起点。

https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKPhysicsBody_Ref/Reference/Reference.html

【讨论】:

    【解决方案2】:

    这是一个可能的解决方案:

    #import "HittingScene.h"
    
    @interface HittingScene() <SKPhysicsContactDelegate>
    
    @property (nonatomic, strong) SKShapeNode *targetBall;
    @property (nonatomic, strong) SKShapeNode *mainBall;
    @property (nonatomic) CGPoint lastTouch;
    @property (nonatomic) bool isDragging;
    
    @end
    
    @implementation HittingScene
    
    static const uint32_t mainBallCategory = 0x1 << 0;
    static const uint32_t targetBallCategory = 0x1 << 1;
    
    - (id)initWithSize:(CGSize)size
    {
        if (self = [super initWithSize:size]) {
    
            self.physicsWorld.gravity = CGVectorMake(0, 0);
    
            [self addChild:[self createMainBall]];
            [self addChild:[self createTargetBall]];
    
            [self setPhysicsBody:[SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame]];
            self.physicsWorld.contactDelegate = self;
            [self.targetBall.physicsBody applyForce:CGVectorMake(30, 30)];
        }
        return self;
    }
    
    - (SKShapeNode *)createTargetBall
    {
        self.targetBall = [SKShapeNode node];
    
        CGPathRef path = CGPathCreateWithEllipseInRect((CGRect){{-20, -20}, {40, 40}}, NULL);
        [self.targetBall setPath:path];
        CGPathRelease(path);
    
        [self.targetBall setPosition:CGPointMake(200, 200)];
        [self.targetBall setName:@"targetBall"];
    
        [self.targetBall setPhysicsBody:[SKPhysicsBody bodyWithCircleOfRadius:20.0]];
        self.targetBall.physicsBody.dynamic = YES;
        self.targetBall.physicsBody.affectedByGravity = YES;
        self.targetBall.physicsBody.restitution = 0.7;
        self.targetBall.physicsBody.categoryBitMask = targetBallCategory;
        self.targetBall.physicsBody.contactTestBitMask = mainBallCategory;
    
        return self.targetBall;
    }
    
    - (SKShapeNode *)createMainBall
    {
        self.mainBall = [SKShapeNode node];
    
        CGPathRef path = CGPathCreateWithEllipseInRect((CGRect){{-20, -20}, {40, 40}}, NULL);
        [self.mainBall setPath:path];
        CGPathRelease(path);
    
        [self.mainBall setPosition:CGPointMake(100, 100)];
        [self.mainBall setName:@"mainBall"];
    
        [self.mainBall setPhysicsBody:[SKPhysicsBody bodyWithCircleOfRadius:20.0]];
        self.mainBall.physicsBody.dynamic = NO;
        self.mainBall.physicsBody.affectedByGravity = NO;
        self.mainBall.physicsBody.restitution = 0.7;
        self.mainBall.physicsBody.categoryBitMask = mainBallCategory;
    
        return self.mainBall;
    }    
    
    - (void)touchesBegan:(NSSet*) touches withEvent:(UIEvent*) event
    {
        if ((SKShapeNode *)[self nodeAtPoint:[[touches anyObject] locationInNode:self]] == self.mainBall) {
            self.isDragging = YES;
        }
    }
    
    - (void) didBeginContact:(SKPhysicsContact *)contact
    {
        if (self.isDragging) {
            float angle = atan2f (self.lastTouch.y - self.mainBall.position.y, self.lastTouch.x - self.mainBall.position.x) ;
            float distance = hypotf(self.lastTouch.x - self.mainBall.position.x, self.lastTouch.y - self.mainBall.position.y);
    
            // calculate vector
            CGFloat thrust = distance;
            CGVector thrustVector = CGVectorMake(thrust*cosf(angle), thrust*sinf(angle));
    
            // apply force or impluse to target node
    
            // force is not working
            // [self.targetBall.physicsBody applyForce:thrustVector];
    
            // impulse is working
            [self.targetBall.physicsBody applyImpulse:thrustVector];
        }
    }
    
    - (void)touchesMoved:(NSSet*) touches withEvent:(UIEvent*) event
    {
        self.lastTouch = [[touches anyObject] locationInNode:self];
        if (self.isDragging) {
            [self.mainBall runAction:[SKAction moveTo:[[touches anyObject] locationInNode:self] duration:0.01]];
        }
    }
    
    - (void)touchesEnded:(NSSet*) touches withEvent:(UIEvent*) event
    {
        self.isDragging = NO;
    }
    
    @end
    

    【讨论】:

    • 我认为您的问题之一是您将dynamic 属性设置为NO。它必须是动态的才能受到物理引擎的影响。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-29
    • 1970-01-01
    • 2020-01-10
    • 2016-05-14
    • 2018-01-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多