【问题标题】:rotation of character by finger用手指旋转字符
【发布时间】:2021-08-25 18:10:24
【问题描述】:

任务是围绕垂直轴旋转字符。作为输入,我们希望在屏幕的任何位置使用手指进行圆形运动。我们尝试使用两种方法首先使用射线,但随后您需要在角色周围拖动手指(有效但不像我们需要的那样)

func _process(_delta):
    look_at_cursor()

func look_at_cursor():
    var player_position = global_transform.origin
    var drop_plane = Plane(Vector3(0, 1, 0), player_position.y)
    var mouse_position = get_viewport().get_mouse_position()
    var ray_length  = 1000
    var ray_start = $Position3D/Camera.project_ray_origin(mouse_position)
    var end_ray = ray_start + $Position3D/Camera.project_ray_normal(mouse_position) * ray_length
    var cursor_pos = drop_plane.intersects_ray(ray_start, end_ray)
    look_at(cursor_pos, Vector3.UP)
    shoot_point = end_ray

第二个是 InputEventScreenDrag,它的工作但只在一个方向。请在这里帮忙。

func _input(event):
    if event is InputEventScreenDrag:
            var rotx = event.relative.x * rot_speed 
            var roty = event.relative.y * rot_speed
            #if rotx < 0:
            #    rotx = - rotx
            #if roty < 0:
            #    roty = - roty
            #rotate_y(rotx+roty)

【问题讨论】:

  • 你要确保你的变量是正数(if rotx &lt; 0: rotx = - rotxif roty &lt; 0: roty = - roty)所以rotx+roty 总是正数,因此rotate_y(rotx+roty) 总是正数轮换。我不知道你希望它如何表现,但如果问题是 its working but only in one direction,那么,不要那样做。
  • 那个划痕应该被移除,如果我们这样做了,那么 char 会从 -90 旋转到 +90,这个任务会旋转 360 度。
  • 如果您沿直线拖动,它将旋转一整圈(我想测试以确保)。但是你想拖一圈对吧?
  • 是的,你是对的。收到您的答复,非常感谢,将对其进行测试并在此处写下进展如何。
  • 非常感谢,工作很好,只添加一件事。如果相对 != last_relative:

标签: godot gdscript


【解决方案1】:

在测试和解决一些抖动问题之间我花了一些时间来弄清楚……我会解释的。

首先,我决定从我在Holding screen touch in godot 中描述的技术开始。所以我的_input 的开头是这样的:

func _input(event:InputEvent):
    if not event is InputEventMouse\
      and not event is InputEventScreenDrag\
      and not event is InputEventScreenTouch:
        return

    var is_left_click:bool = event is InputEventMouse\
      and ((event as InputEventMouse).button_mask & BUTTON_LEFT) != 0
    var is_drag := event is InputEventScreenDrag\
      or (event is InputEventMouseMotion and is_left_click)

对于轮换,我决定使用curl 的概念。我的意思是,我将使用叉积来确定旋转的方向。这样我们就不需要定义旋转中心(所以你可以在屏幕的任何部分做圆圈,它仍然可以工作)。

让我们声明curl

var curl:float = 0.0

由于我们要做叉积,我们需要保留最后一个亲戚,这样我们就可以和当前的做叉积。所以声明last_relative

var last_relative:Vector3 = Vector3.ZERO

让我们做叉积:

    var relative := Vector3(event.relative.x, event.relative.y, 0).normalized()
    curl = relative.cross(last_relative).z
    last_relative = relative

但是,我们需要确保为下一次拖动重置它。我们将在is_drag 为 false 时设置它(即在新闻发布时):

    if is_drag:
        var relative := Vector3(event.relative.x, event.relative.y, 0).normalized()
        curl = relative.cross(last_relative).z
        last_relative = relative
    else:
        last_relative = Vector3.ZERO
        curl = 0.0

桌子上的下一个问题是旋转速度。我最终使用了_physics_process。这也让我们可以使用delta,这样转速就稳定了。

说到转速,声明rot_speed

var rot_speed:float = TAU

TAU 表示每秒旋转一圈。

现在我们可以写_physics_process

func _physics_process(delta: float) -> void:
    rotate_y(sign(curl) * rot_speed * delta)

接下来是抖动。其中一部分是输入仿真。所以我禁用了它。但这还不够。为了彻底解决jitter,_input不会写curl,而是target_curl

先声明target_curl:

var target_curl:float = 0.0

然后设置在_input:

    if is_drag:
        var relative := Vector3(event.relative.x, event.relative.y, 0).normalized()
        target_curl = relative.cross(last_relative).z
        last_relative = relative
    else:
        last_relative = Vector3.ZERO
        target_curl = 0.0

现在,我们将在physics_process 中将curl 简化为target_curl

func _physics_process(delta: float) -> void:
    if target_curl > curl:
        curl += delta
        if curl > target_curl:
            curl = target_curl
    elif target_curl < curl:
        curl -= delta
        if curl < target_curl:
            curl = target_curl

    rotate_y(sign(curl) * rot_speed * delta)

最后,当用户保持位置(不是拖动)时,我们没有得到任何_input。这意味着用户可以做一点弧线,并保持位置,物理体将继续旋转。我们通过擦除每个物理帧 target_curl 来解决这个问题。

完整的代码清单:

extends KinematicBody

var rot_speed:float = TAU
var last_relative:Vector3 = Vector3.ZERO
var curl:float = 0.0
var target_curl:float = 0.0

func _input(event:InputEvent):
    if not event is InputEventMouse\
      and not event is InputEventScreenDrag\
      and not event is InputEventScreenTouch:
        return

    var is_left_click:bool = event is InputEventMouse\
      and ((event as InputEventMouse).button_mask & BUTTON_LEFT) != 0
    var is_drag := event is InputEventScreenDrag\
      or (event is InputEventMouseMotion and is_left_click)

    if is_drag:
        var relative := Vector3(event.relative.x, event.relative.y, 0).normalized()
        target_curl = relative.cross(last_relative).z
        last_relative = relative
    else:
        last_relative = Vector3.ZERO
        target_curl = 0.0

func _physics_process(delta: float) -> void:
    if target_curl > curl:
        curl += delta
        if curl > target_curl:
            curl = target_curl
    elif target_curl < curl:
        curl -= delta
        if curl < target_curl:
            curl = target_curl

    rotate_y(sign(curl) * rot_speed * delta)
    target_curl = 0.0

在 Windows 上用鼠标测试,在 Android 上用触摸测试。

【讨论】:

    猜你喜欢
    • 2011-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-06
    • 2010-11-21
    • 2023-04-07
    相关资源
    最近更新 更多