首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >戈多发动机的转向运动

戈多发动机的转向运动
EN

Stack Overflow用户
提问于 2021-05-20 12:13:35
回答 1查看 665关注 0票数 2

我想了解戈多引擎的游戏开发。我试着制作一个类似于游戏导弹的移动游戏:

现在我有一个有效的操纵杆。我得到的值是一个规范化的Vector2

代码语言:javascript
复制
var joystick_value = joystick.get_value()

但是我不知道如何根据操纵杆值改变飞机的速度。加上设置一些限制的平面可以旋转多少(或最大角度)。

(飞机是KinematicBody2D)

有什么想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-20 13:51:58

速度

如果我们谈论的是KinematicBody2D和velocity,那么我们谈论的是这样的脚本--无论是给予还是接受:

代码语言:javascript
复制
extends KinematicBody2D

var velocity:Vector2 = Vector2.ZERO # pixels/second

func _physics_process(_delta:float) -> void:
    move_and_slide(velocity)

也许您最好使用speeddirection,而不是velocity。我们也可以这样做:

代码语言:javascript
复制
extends KinematicBody2D

var speed:float = 0                # pixels/second
var direction:Vector2 = Vector2.UP # pixels

func _physics_process(_delta:float) -> void:
    var velocity = direction.normalized() * speed
    move_and_slide(velocity)

如果我们想要一个angle而不是direction向量呢?当然:

代码语言:javascript
复制
extends KinematicBody2D

var speed:float = 0 # pixels/second
var angle:float = 0 # radians

func _physics_process(_delta:float) -> void:
    var velocity = Vector2.RIGHT.rotated(angle) * speed
    move_and_slide(velocity)

旋转

由于我们将进行转向,我们想要旋转的KinematicBody2D根据它的速度。

当然,我们可以从一个angle中得到一个旋转velocity

代码语言:javascript
复制
extends KinematicBody2D

var velocity:Vector2 = Vector2.ZERO # pixels/second

func _physics_process(_delta:float) -> void:
    rotation = velocity.angle()
    move_and_slide(velocity)

类似地,对于direction向量,或者如果您有angle,您可以直接使用它。

操舵

对于转向,我们将保持速度和变化的角度。所以我们想要我上面展示的speedangle版本。当然,在轮换时:

代码语言:javascript
复制
extends KinematicBody2D

var speed:float = 0 # pixels/second
var angle:float = 0 # radians

func _physics_process(_delta:float) -> void:
    rotation = angle
    var velocity = Vector2.RIGHT.rotated(angle) * speed
    move_and_slide(velocity)

现在我们将有一个来自用户输入的target_angle。就你而言,这意味着:

代码语言:javascript
复制
var target_angle = joystick.get_value().angle()

注意,我们不知道旋转的方向是什么。执行target_angle - angle不起作用,因为反过来旋转可能会更短。因此,我们将这样做:

代码语言:javascript
复制
var angle_difference = wrapf(target_angle - angle, -PI, PI)

wrapf是做什么的?它将值“包装”到一个范围。例如,wrapf(11, 0, 10)1,因为它通过1遍历了10,而1 + 01wrapf(4, 5, 10)9,因为它低于1510 - 19。希望这是合理的。

我们是在从-PIPI的范围内,所以它给出的角度差的方向,是较短的旋转。

我们还需要angular_speed。也就是说,每个时间单位的角度变化有多大(单位是角度/时间)。注意,这与角度的变化不一样(单位是角度)。要进行转换,我们乘以上次以来所用的时间:

代码语言:javascript
复制
var delta_angle = angular_speed * delta

啊,实际上,我们需要在angle_difference的方向上。因此,它的sign

代码语言:javascript
复制
var delta_angle = angular_speed * delta * sign(angle_difference)

我们不想过分。因此,如果delta_angle的绝对值大于angle_difference,则需要将delta_angle设置为angle_difference

代码语言:javascript
复制
var angle_difference = wrapf(target_angle - angle, -PI, PI)
var delta_angle= angular_speed * delta * sign(angle_difference)
if abs(delta_angle) > abs(angle_difference):
    delta_angle = angle_difference

我们可以在那里保存到abs的一个电话:

代码语言:javascript
复制
var angle_difference = wrapf(target_angle - angle, -PI, PI)
var delta_angle_abs = angular_speed * delta
var delta_angle = delta_angle_abs * sign(angle_difference)
if delta_angle_abs > abs(angle_difference):
    delta_angle = angle_difference

把它们放在一起:

代码语言:javascript
复制
extends KinematicBody2D

var speed:float = 0         # pixels/second
var angle:float = 0         # radians
var angular_speed:float = 0 # radians/second

func _physics_process(delta:float) -> void:
    var target_angle = joystick.get_value().angle()
    var angle_difference = wrapf(target_angle - angle, -PI, PI)
    var delta_angle_abs = angular_speed * delta
    var delta_angle = delta_angle_abs * sign(angle_difference)
    if delta_angle_abs > abs(angle_difference):
        delta_angle = angle_difference

    angle += delta_angle
    rotation = angle
    var velocity = Vector2.RIGHT.rotated(angle) * speed
    move_and_slide(velocity)

最后,一些重构,包括但不限于将代码块提取到另一个函数:

代码语言:javascript
复制
extends KinematicBody2D

var speed:float = 0         # pixels/second
var angle:float = 0         # radians
var angular_speed:float = 0 # radians/second

func _physics_process(delta:float) -> void:
    var target_angle = joystick.get_value().angle()
    angle = apply_rotation_speed(angle, target_angle, angular_speed, delta)
    rotation = angle
    var velocity = Vector2.RIGHT.rotated(angle) * speed
    move_and_slide(velocity)

static func apply_rotation_speed(from:float, to:float, angle_speed:float, delta:float) -> float:
    var diff = wrapf(to - from, -PI, PI)
    var angle_delta = angle_speed * delta
    if angle_delta > abs(diff):
        return to

    return from + angle_delta * sign(diff)

下面是一个具有角加速度的版本:

代码语言:javascript
复制
extends KinematicBody2D

var speed:float = 0                # pixels/second
var angle:float = 0                # radians
var angular_speed:float = 0        # radians/second
var angular_acceleration:float = 0 # radians/second^2

func _physics_process(delta:float) -> void:
    var target_angle = joystick.get_value().angle()
    if angle == target_angle:
        angular_speed = 0
    else:
        angular_speed += angular_acceleration * delta
        angle = apply_rotation_speed(angle, target_angle, angular_speed, delta)

    rotation = angle
    var velocity = Vector2.RIGHT.rotated(angle) * speed
    move_and_slide(velocity)

static func apply_rotation_speed(from:float, to:float, angle_speed:float, delta:float) -> float:
    var diff = wrapf(to - from, -PI, PI)
    var angle_delta = angle_speed * delta
    if angle_delta > abs(diff):
        return to

    return from + angle_delta * sign(diff)

还有有角度放松的闪亮版本:

代码语言:javascript
复制
extends KinematicBody2D

var speed = 10
var angle:float = 0
var angular_speed:float = 0
export(float, EASE) var angular_easing:float = 1

func _physics_process(delta:float) -> void:
    var target_angle = (get_viewport().get_mouse_position() - position).angle()
    angle = apply_rotation_easing(angle, target_angle, angular_easing, delta)

    rotation = angle
    var velocity = Vector2.RIGHT.rotated(angle) * speed
    move_and_slide(velocity)

static func apply_rotation_easing(from:float, to:float, easing:float, delta:float) -> float:
    var diff = wrapf(to - from, -PI, PI)
    var diff_norm = abs(diff)
    var angle_speed = ease(diff_norm / PI, easing)
    var angle_delta = angle_speed * delta
    if angle_delta > diff_norm:
        return to

    return from + angle_delta * sign(diff)

angular_easing设置为0到1之间的某个值,使其在接近目标角度时开始旋转和减速时加速。值为0时,它不会旋转。其值为1,它以恒定的速度旋转。见https://docs.godotengine.org/en/3.1/classes/class_@gdscript.html#class-gdscript-method-ease

我测试了这个答案中的代码(使用一些非零值),这是用于鼠标控制的:

代码语言:javascript
复制
var target_angle = (get_viewport().get_mouse_position() - position).angle()

它起作用了。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67620139

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档