ios - SpriteKit 中的持续运动

标签 ios sprite-kit

我有一个游戏,我想根据用户触摸屏幕的左侧或右侧来向左或向右移动 SKNode。如何在用户触摸屏幕时对节点应用持续移动?

最佳答案

您实际上有三种选择来保持速度。

一种是在每次更新时简单地将速度重置回您想要的数量。在这种情况下,我选择了 200,200。这将使您的运动完全静止。

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

第二种选择是保持速度,但使用速率因子为运动失真留出空间。下面的示例会将速度保持为 200,200,但不会立即保持。相反,这将取决于利率。这将使您的 Action 更加逼真,并且不那么静态。例如,假设您有一个角色以恒定速度移动并且您改变了方向,您会看到一个微小的加速度,因为它变为新的恒定速度值,从而使运动的变化变得不那么静态而更加动态。我强烈推荐此选项。

-(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);

}

您拥有的第三个选项是仅设置速度或应用脉冲 ONCE(与我们上面所做的每一帧相反),但关闭其重力和空气阻力。这种方法的问题在于它不会始终保持您的速度。它只会保持恒定速度,直到受到外力(即摩擦、与另一个物体碰撞等)的作用。这种方法适用于您希望某些对象以恒定速度移动但仍保持完全动态的情况。如果您希望控制和/或保持对象速度,我根本不推荐此选项。我能想到的唯一场景可能是一个游戏,小行星以恒定速度在屏幕上漂浮,但仍然受到外力的影响(即 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。仅将它们用于动画。

我所说的实时运动是指对象的位置和速度在其模拟的每一步都对您很重要的运动。而在动画中,您实际上只关心一段时间内的起点和终点。例如,具有移动角色的游戏需要实时 Action 。您需要能够在模拟的每个步骤中监控角色的位置和速度,并可能在特定时间间隔进行调整。但是对于像移动 UI 元素这样更简单的事情,你不需要在每一步都跟踪它们的运动,所以使用动画

关于ios - SpriteKit 中的持续运动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19286610/

相关文章:

ios - SKAction.moveTo 根本不起作用

ios - 对于 SKSprite,customAction 实际上是 Update 调用吗?

cocoa-touch - 在 SKScene 中处理摇动手势

iphone - iPhone/iOS 上的通用 LISP

ios - Swift 2 - iOS - 分派(dispatch)回原始线程

ios - Collection View 在第一个索引上设置单选按钮图像并选择更改

ios - 正确使用 beginBackgroundTaskWithExpirationHandler

iphone - 禁用除一个 View 之外的所有 View 的用户交互

swift 3.0 : SKSpriteNode as Button does not work when given a non-SKView parent?

ios - SpriteKit 中的无限滚动背景