在SpriteKit中不断移动

我有一个游戏,我想要向左或向右移动一个SKNode,取决于用户是否触摸屏幕的左侧或右侧。 如何在用户触摸屏幕的同时将节点的运动应用于节点?

你真的有三个select来保持速度。

一个是简单地保持每次更新后重新设定速度。 在这种情况下,我select了200,200。 这将使你的动作完全静止。

-(void)update:(NSTimeInterval)currentTime { node.physicsBody.velocity=CGVectorMake(200, 200); } 

第二个select是保持速度,但是使用速率因子为运动失真留下空间。 下面的例子将速度保持到200,200,但不是瞬间的。 相反,这取决于费率。 这会使你的动作更真实,不那么静止。 例如,假设你有一个angular色以恒定的速度移动,并且你改变方向,当它改变到新的恒定速度值时,你会看到一个微小的加速度,使得运动的改变不那么静止和更加dynamic。 我强烈推荐这个选项。

 -(void)update:(NSTimeInterval)currentTime { CGFloat rate = .05; CGVector relativeVelocity = CGVectorMake(200-node.physicsBody.velocity.dx, 200-node.physicsBody.velocity.dy); node.physicsBody.velocity=CGVectorMake(node.physicsBody.velocity.dx+relativeVelocity.dx*rate, node.physicsBody.velocity.dy+relativeVelocity.dy*rate); } 

你有第三个select是设置速度或应用脉冲一次 (而不是像我们上面所做的每一帧),但closures其重力和空气阻力。 这种方法的问题是,它并不总是保持你的速度。 它只会保持恒定的速度,直到外力作用(即摩擦,与另一个物体碰撞等)。 这种方法适用于您希望某些对象以恒定速度移动但仍保持完全dynamic的情况。 如果你想控制和/或保存你的对象的速度,我不推荐这个选项。 我能想到的唯一情况就是一个移动小行星的游戏,它以恒定的速度在屏幕上浮动,但仍然受到外力的影响(即2个小行星相撞,这将导致一个新的恒定的速度)。

 node.physicsBody.velocity=CGVectorMake(200, 200); node.physicsBody.linearDamping = 0; //You may want to remove the air-resistance external force. node.physicsBody.affectedByGravity = false; //You may want to remove the gravity external force 

这里是我使用选项2在Swift中编写的一个示例项目。我试图匹配您的描述。 它只是以恒定的速度向左或向右移动一个节点。 请务必尝试率因素。

 import SpriteKit class GameScene: SKScene { var sprite: SKSpriteNode! var xVelocity: CGFloat = 0 override func didMoveToView(view: SKView) { sprite = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 50, height: 50)) sprite.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.size) sprite.physicsBody.affectedByGravity = false sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0) self.addChild(sprite) } override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { let touch = touches.anyObject() as UITouch let location = touch.locationInNode(self) if (location.x<self.size.width/2.0) {xVelocity = -200} else {xVelocity = 200} } override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) { xVelocity = 0 } override func update(currentTime: CFTimeInterval) { let rate: CGFloat = 0.5; //Controls rate of motion. 1.0 instantaneous, 0.0 none. let relativeVelocity: CGVector = CGVector(dx:xVelocity-sprite.physicsBody.velocity.dx, dy:0); sprite.physicsBody.velocity=CGVector(dx:sprite.physicsBody.velocity.dx+relativeVelocity.dx*rate, dy:0); } } 

注意:尽量远离SKActions进行实时动作。 只能将它们用于animation。

通过实时运动,我的意思是运动中的物体的位置和速度在模拟的每一步对你都很重要。 而在animation中,你真的只关心一段时间的起点和终点。 例如,具有移动angular色的游戏需要实时动作。 您需要能够在模拟的每个步骤中监控angular色的位置和速度,并且可能会在一定的时间间隔进行调整。 但对于简单的事情,如移动UI元素,你不需要跟踪他们在每一步的动作,所以使用animation

添加一个ivar:

 CGPoint velocity; 

设置动作,例如向右移动:

 velocity.x = 5; 

整合速度每一步:

 -(void) update:(NSTimeInterval)currentTime { CGPoint pos = self.position; pos.x += velocity.x; pos.y += velocity.y; self.position = pos; } 

PS:对于连续操作,特别是移动,行动是非常糟糕的,因为它们是以时间为基础的,即应该在一段时间后结束。 但是,如果行动的时间在到达目的地之前耗尽了呢?

我直接设置velocity.dx,但是我不推荐这种方法,因为它完全忽略了以前的速度。

 public func setSpeed(speed: CGFloat) { physicsBody.velocity.dx = speed } 

我想提供一个解决scheme,与现有的spritekit物理引擎更好的工作,但我没有,我会提供一个赏金,因为我也需要一个解决scheme。

对于Swift中的触摸,你可以这样做:

 override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { player.setSpeed(100) // You can use touches.anyObject().position to see the touch position and implement left/right movement } 

这正是你如何做math…

所以在这个例子中,手指想要移动物品。

这正好确定了你希望在帧时间内移动多less。

在这里输入图像说明

(在许多(当然不是全部)的情况下,你将有一个质量作为正常化的“一公斤”(如果你的物理学是在“抽象”的身体上工作的话 – 你正在推动“图标”,“斑点”或类似的如果你的物理学是坦克,足球或其他什么的,那么你必须使用现实世界的价值。)用“一公斤”的质量,就是这样做的。

请享用!

取决于你是否想使用物理力量或行动。

像这样的东西

 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch *touch in touches) { UITouch* touch = [touches anyObject]; CGPoint loc = [touch locationInNode:self]; if (loc.x > self.frame.size.width * 0.5) { NSLog(@"move right"); // move the sprite using an action // or set physics body and apply a force } else { NSLog(@"move left"); } } } 

如果您决定使用操作,请在touchesEnded中移除您正在移动的精灵的所有操作。

如果你正在应用一个小部队触发开始精灵应该停下来。

使用physicsBody的velocity属性。 可变的权利是触摸点减去对象(在这种情况下是自我),并提供相关的速度

 -(void)segmentedTouchBegan:(NSValue *)p{ CGPoint point = [p CGPointValue]; int right = (point.x - self.screenWidth/2.0f)/ABS((point.x - self.screenWidth/2.0f)); //1 if right -1 if left self.physicsBody.velocity = CGVectorMake(SHIFT*right, 0); } -(void)segmentedTouchMoved:(NSValue *)p{ CGPoint point = [p CGPointValue]; int right = (point.x - self.screenWidth/2.0f)/ABS((point.x - self.screenWidth/2.0f)); //1 if right -1 if left self.physicsBody.velocity = CGVectorMake(SHIFT*right, 0); } -(void)segmentedTouchEnded:(NSValue *)p{ self.physicsBody.velocity = CGVectorMake(0, 0); } 

如果你的SKNodephysicsBodyphysicsBody施加强制:

 @interface GameScene() @property (nonatomic) CGVector force; @end @implementation GameScene - (void)update:(CFTimeInterval)currentTime { [self.player.physicsBody applyForce:self.force]; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { self.sideForce = CGVectorMake(3000, 0); } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { self.sideForce = CGVectorMake(0, 0); } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { self.sideForce = CGVectorMake(0, 0); } @end 

如果没有,请使用LearnCocos2D的答案。

如果你必须从左到右的固定位置停止你的动作。

这对于Swift和Objective-C。

你必须在物理学中使用:

node.position = CGPoint(X:…..,Y:…..)node.physicsBody = nil

 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { /* Called when a touch begins */ UITouch *touch = [touches anyObject]; CGPoint touchLocation = [touch locationInNode:self]; if (touchLocation.x > 50) { // Do whatever.. _timer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(movePlayer:) userInfo:nil repeats:YES]; NSLog(@"Right"); } else if (touchLocation.x < 50){ ////// use another NSTimer to call other function//// NSLog(@"left"); } } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ if (_timer != nil) { [_timer invalidate]; _timer = nil; } } -(void)movePlayer:(id)sender { hero.physicsBody.velocity = CGVectorMake(400, 0); }