如何将定向速度应用于spritenode?

时间:2015-04-03 13:03:57

标签: ios objective-c sprite-kit

所以我做了一个 SKSpriteNode

SKSpriteNode *ball = [SKSpriteNode spriteNodeWithImageNamed:@"ball.png"];
ball.size = CGSizeMake(40, 40);
ball.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
ball.name = @"ball";
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:20];
[self addChild:ball];

我可以像这样移动它:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInNode:self];
    SKNode *node = [self nodeAtPoint:location];
    if ([node.name isEqualToString:@"ball"]) {
        draggedBall = [self nodeAtPoint:[[touches anyObject]locationInNode:self]];
        draggedBallStartPosition = draggedBall.position;
     }

}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    if ([[touches anyObject]locationInNode:self].x -draggedBall.position.x < 50
    && [[touches anyObject]locationInNode:self].x -draggedBall.position.x > -50) {
        draggedBall.position = [[touches anyObject]locationInNode:self];
        draggedBall.physicsBody.affectedByGravity = NO;

    }
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    float dx = draggedBall.position.x - draggedBallStartPosition.x;
    float dy = draggedBall.position.y - draggedBallStartPosition.y;
    NSLog(@"DX: %f DY: %f",dx,dy);
    [draggedBall.physicsBody applyImpulse:CGVectorMake(dx, dy)];
    draggedBall.physicsBody.affectedByGravity = YES;
    draggedBall = nil;
}

draggedBall 是一个SKNode ivar。所以我想要做的是刷球,当它释放时,它继续向那个方向发展。你刷的速度越快,冲动越大。现在我尝试(并且失败)这样做,但这显然不起作用。不知何故,需要检测球的最后方向,然后是开始朝那个方向前进和释放球之间的时间量。并且取决于该时间长度,影响球的速度。由于这是一种经常使用的游戏机制,我认为有一种标准化的方法可以做到这一点。无论如何,谢谢你的帮助。

1 个答案:

答案 0 :(得分:0)

我不熟悉这样做的标准方法,但是我使用以下方法从屏幕上的任意位置创建一个矢量,然后将其应用到节点物理主体。也许您可以采用触摸逻辑来满足您的要求。

以下是SKScene.m子类中的所有内容,但它可以在任何SKNode子类中实现。

从标量开始,可以在测试期间稍后进行调整。

#define FLICK_SCALAR 0.5

要使用的等式需要时间和点我将其包含在结构中以及指示开始时间的标志。因此,在.m的顶部,在@implementation和任何类扩展之前放置以下内容。

typedef struct TouchData {
CGPoint point;
NSTimeInterval time;
BOOL hasStarted;// flick has started
} TouchData;

然后在上面的类扩展中添加以下属性。

@property TouchData touchOriginData;

重写的触摸方法具有以下实现。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// store the start data
for (UITouch *touch in touches) {
    // testing flick gesture
    _touchOriginData.point = [touch locationInNode:self];
    _touchOriginData.time = [touch timestamp];
    _touchOriginData.hasStarted = NO;
    }
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
//NSLog(@"touches moved");
if (!_touchOriginData.hasStarted) {
    // must be moving for the first time so start timing now
    for (UITouch *touch in touches) {
        _touchOriginData.time = [touch timestamp];
        _touchOriginData.hasStarted = YES;
        }
    }
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// store the end data
TouchData touchEndData;
touchEndData.time = 0;
touchEndData.point.x = 0.0;
touchEndData.point.y = 0.0;
touchEndData.hasStarted = NO;
for (UITouch *touch in touches) {
    touchEndData.point = [touch locationInNode:self];
    touchEndData.time = touch.timestamp;
}
if (_touchOriginData.hasStarted) {
    // calculate the impulse vector from TouchData structs
    NSTimeInterval timeTaken = touchEndData.time - _touchOriginData.time;
    CGFloat vector_x = (touchEndData.point.x - _touchOriginData.point.x) / timeTaken * FLICK_SCALAR;
    CGFloat vector_y = (touchEndData.point.y - _touchOriginData.point.y) / timeTaken * FLICK_SCALAR;
    CGVector impulseVector = CGVectorMake(vector_x, vector_y);
    // here is where you can now apply an impulse to a 
    // physics body of, in your case, a ball node.
    // get the ball node (ball)
    SKNode *ball = [self childNodeWithName:@"ball"];
    // apply the impulse
    [ball.physicsBody applyImpulse: impulseVector];

    }
}

注意 - 我还为场景设置 multiTouchEnabled NO ,在其生命周期的某个时间点。