math - 围绕枢轴移动和旋转对象并从停止的位置恢复
问题描述
我想围绕另一个对象移动一个对象 - 就好像一个对象是另一个对象的孩子一样。这是GDscript - Godot Engine 3.2,但逻辑应该与其他游戏引擎非常相似。
每当我按住空格键时,绿色立方体都会跟随蓝色立方体旋转。
第一个 GIF 演示了从 Vector3(0, 4, 0) 位置开始的绿色立方体,没有应用任何旋转。这工作得很好。
在第二个 GIF 中,我反复按住和释放空格键。我希望绿色立方体从它离开的地方继续,但是它“跳”到一个新的位置并从那里继续。
下面的代码不包括蓝色立方体(枢轴点)的实际旋转,而只包括移动/旋转绿色立方体所需的计算。蓝色立方体的旋转不是问题。此外,旋转只是为了演示 - 在实际场景中,蓝色立方体也会移动。
旋转是使用四元数计算的,但这不是必需的。
extends Node
var _parent
var _child
var _subject
var _positionOffset: Vector3
var _rotationOffset: Quat
func _ready():
_parent = get_parent()
_child = $"/root/Main/Child"
func _input(event):
if event is InputEventKey:
if event.scancode == KEY_SPACE:
if event.is_action_pressed("ui_accept") and _child != null:
_subject = _child
_set_subject_offset(_parent.transform, _child.transform)
elif event.is_action_released("ui_accept"):
_subject = null
func _set_subject_offset(pivot: Transform, subject: Transform):
_positionOffset = (pivot.origin - subject.origin)
_rotationOffset = pivot.basis.get_rotation_quat().inverse() * subject.basis.get_rotation_quat()
func _rotate_around_pivot(subject_position: Vector3, pivot: Vector3, subject_rotation: Quat):
return pivot + (subject_rotation * (subject_position - pivot))
func _physics_process(_delta):
if _subject == null: return
var target_position = _parent.transform.origin - _positionOffset
var target_rotation = _parent.transform.basis.get_rotation_quat() * _rotationOffset
_subject.transform.origin = _rotate_around_pivot(target_position, _parent.transform.origin, target_rotation)
_subject.set_rotation(target_rotation.get_euler())
我觉得我错过了一些明显的东西。
解决方案
您可以通过临时将主体设置为轴心点来轻松实现此目的,同时保留全局变换:
extends Spatial
onready var obj1: Spatial = $Object1
onready var obj2: Spatial = $Object2
func reparent(obj: Spatial, new_parent: Spatial):
# Preserve the global transform while reparenting
var old_trans := obj.global_transform
obj.get_parent().remove_child(obj)
new_parent.add_child(obj)
obj.global_transform = old_trans
func _physics_process(delta: float):
obj1.rotate_z(delta)
func _input(event: InputEvent):
if event.is_action_pressed("ui_accept"):
reparent(obj2, obj1)
elif event.is_action_released("ui_accept"):
reparent(obj2, self)
如果重新设置不可行,您可以改为将RemoteTransform设置为枢轴,然后将其转换推送到要旋转的对象:
extends Spatial
onready var remote_trans: RemoteTransform = $RemoteTransform
func _process(delta):
rotate_z(delta)
func attach(n: Node):
# move the remote so the target maintains its transform
remote_trans.global_transform = n.global_transform
remote_trans.remote_path = n.get_path()
func detach():
remote_trans.remote_path = ""
推荐阅读
- sql - 通过给定的 SLA 时间范围和营业时间计算到期日期时间的 SQL 函数
- reactjs - 使用 http API 的 react-phone-number-input 代码示例
- python - 将字典中的数据附加到列表
- angular - 如何在声纳云中获得准确的代码覆盖率
- c++ - 访问在 .cpp 文件中声明的结构的内容
- java - 从 HBASE 表中查询大量数据时 Result 对象的大小
- php - 4 字节大端到 int
- next.js - Next JS Paging - 使用相同的页面文件
- python - Pycharm Django 控制台在 WSL 上没有名为“django_manage_shell”的模块
- python - 在 Django 中计算外键总数