You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多轴旋转异常:复现Hadamard门时仅X轴旋转生效

问题

我正在尝试复现Hadamard门的工作机制,系统由球体加附着的圆柱体组成,希望先绕X轴旋转90度,再绕Z轴旋转180度。但点击圆柱体时仅执行了X轴旋转,请问主Node3D的脚本需修改哪些地方?

初始配置:
初始配置

当前脚本:

extends Node3D

@onready var click_area: Area3D = $State/ClickArea
@onready var state_node: Node3D = $State

var tween: Tween

const ROTATION_AROUND_X := 90.0
#const ROTATION_AROUND_Y := 0.0
const ROTATION_AROUND_Z := 180.0

func _ready():
    click_area.input_event.connect(_on_click_area_input_event)

func _on_click_area_input_event(_camera: Camera3D, event: InputEvent, _pos: Vector3, _normal: Vector3, _shape_idx: int) -> void:
    if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
        _play_hadamard_animation()

func _play_hadamard_animation():
    # Kill any existing tween to ensure the animation starts fresh
    if tween and tween.is_valid():
        tween.kill()

    # Create the new tween
    tween = get_tree().create_tween()
    tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
    
    var start_rotation := state_node.rotation_degrees
    
    tween.tween_property(state_node, "rotation_degrees",
        start_rotation + Vector3(ROTATION_AROUND_X, 0.0, ROTATION_AROUND_Z), 1.2)
解决方案

问题出在当前代码是同时对X和Z轴应用旋转,而非按顺序执行两个旋转步骤。要实现先绕X转90度、再绕Z转180度的效果,需做以下修改:

  • 拆分动画阶段:将两个旋转拆分为Tween的连续步骤,而非一次性设置最终旋转向量。GDScript的Tween会按调用顺序依次执行tween_property,无需额外链式调用。
  • 分步计算目标值:第一步目标为当前旋转加X轴90度,第二步目标为第一步完成后的旋转加Z轴180度。

修改后的完整脚本:

extends Node3D

@onready var click_area: Area3D = $State/ClickArea
@onready var state_node: Node3D = $State

var tween: Tween

const ROTATION_AROUND_X := 90.0
const ROTATION_AROUND_Z := 180.0

func _ready():
    click_area.input_event.connect(_on_click_area_input_event)

func _on_click_area_input_event(_camera: Camera3D, event: InputEvent, _pos: Vector3, _normal: Vector3, _shape_idx: int) -> void:
    if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
        _play_hadamard_animation()

func _play_hadamard_animation():
    # 终止现有动画,确保新动画从头开始
    if tween and tween.is_valid():
        tween.kill()

    tween = get_tree().create_tween()
    tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
    
    # 第一步:绕X轴旋转90度
    var x_rotate_target = state_node.rotation_degrees + Vector3(ROTATION_AROUND_X, 0.0, 0.0)
    tween.tween_property(state_node, "rotation_degrees", x_rotate_target, 0.6)
    
    # 第二步:绕Z轴旋转180度(自动衔接上一步完成后执行)
    var z_rotate_target = x_rotate_target + Vector3(0.0, 0.0, ROTATION_AROUND_Z)
    tween.tween_property(state_node, "rotation_degrees", z_rotate_target, 0.6)

额外优化方案:
如果需要确保旋转基于节点本地坐标系(避免欧拉角可能的万向锁问题),可以改用tween_method调用节点的旋转方法:

# 替代tween_property的写法,直接基于本地轴旋转
tween.tween_method(func(amount): state_node.rotate_x(deg_to_rad(amount)), 0, ROTATION_AROUND_X, 0.6)
tween.tween_method(func(amount): state_node.rotate_z(deg_to_rad(amount)), 0, ROTATION_AROUND_Z, 0.6)

内容的提问来源于stack exchange,提问作者albusdemens

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 10:16:18