SpriteKit 中的持续移动 [英] Constant movement in SpriteKit

查看:14
本文介绍了SpriteKit 中的持续移动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a game where I would like to move an SKNode left or right depending on if the user touches the left or right side of the screen. How to I apply a constant movement to a node while the user is touching the screen?

推荐答案

你真的有三个选项来保持速度.

You really have three options for preserving the velocity.

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

One is to simply keep reseting the velocity back to your desired amount every update. In this case I chose 200,200. This will make your motion completely static.

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

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

The second option is to preserve the velocity but leave room for motion distortions using a rate factor. The example below would preserve the velocity to 200,200 but not instantaneously. Instead it would depend on the rate. This will make your motion much more realistic and a little less static. For example, lets say you have a character moving at constant speed and you change direction, you will see a tiny acceleration as it changes to the new constant speed value, making the change in motion less static and more dynamic. I highly recommend this option.

-(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 颗小行星相撞会产生新的匀速).

The third option you have is to just set the velocity or apply an impulse ONCE (as opposed to every frame like we did above), but turn off its gravity and air resistance. The problem with this approach is that it will not always preserve your velocity. It will only keep constant speed until acted on by an external force (i.e. friction, colliding with another body, etc). This approach works for cases where you want some object to move at constant speed but still remain completely dynamic. I don't recommend this option at all if you are looking to control and/or preserve your objects velocity. The only scenario I could think of for this is maybe a game with moving asteroids that float around the screen at constant speed but are still affected by external forces (i.e. 2 asteroids collide which will result in a new constant speed).

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 中编写的示例项目.我尝试与您的描述相匹配.它只是以恒定的速度向左或向右移动节点.请务必尝试使用速率因子.

Here is an example project I wrote in Swift using option 2. I tried to match your description. It simply moves a node left or right at constant speed. Be sure to experiment with the rate factor.

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 进行实时运动.仅将它们用于动画.

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

By real-time motion, I mean motion in which the position and velocity of your objects are important to you at each step in their simulation. Whereas in animation, you are really only concerned with the start and end points over some duration. For example, a game with moving characters requires real-time motion. You need to be able to monitor at each step in the simulation the positions and velocities of your characters, and potentially make adjustments at certain intervals. But for simpler things like moving UI elements, you don't need to track their motion at each step, so use animation

这篇关于SpriteKit 中的持续移动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆