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

如何旋转单个Vector3点使其朝向玩家?Godot开发求助

问题:随机圆上点无法跟随玩家旋转

我正在设计一个从圆上获取随机点的系统,已成功生成随机点并通过网格立方体可视化,但当偏离-Z前方向轴旋转时,随机点无法跟随旋转。我尝试用rand_point = rand_point.rotated(Vector3.RIGHT,player.rotation.y)实现旋转,但没效果,不太懂旋转逻辑。

完整代码

extends Node

@export_subgroup("Misc")
@export var player : CharacterBody3D
@export var raycast : RayCast3D
@onready var bullet_impact : PackedScene = preload("res://Source/bullet impact/bullet_impact.tscn")
@export_subgroup("Temp paremeters")
@export var fire_rate : float = 0.1
var fire_time : float = 0.0

@export_subgroup("Recoil parameters")
var radius : int = 1
var impact_array : Array

func _process(delta):
    
    if Input.is_action_just_pressed("Clear"):
        clear_impact()
    
    if fire_time > 0.0:
        fire_time -= delta
    
    if Input.is_action_pressed("Fire") and fire_time <= 0.0:
        fire_time = fire_rate
        handle_raycast()
    
func handle_raycast() -> void:
    var rand_point : Vector3 = Vector3.ZERO
    
    if raycast.is_colliding():
        var obj = raycast.get_collider()
        var point = raycast.get_collision_point()
        var normal = raycast.get_collision_normal()
        
        rand_point = get_rand_point_on_circle(point)
        rand_point = rand_point.rotated(Vector3.RIGHT,player.rotation.y)
        handle_impact(rand_point)

func clear_impact() -> void:
    if impact_array.size() == 0: return
    
    for impact in impact_array:
        if is_instance_valid(impact):
            impact.queue_free()

func handle_impact(impact_pos : Vector3) -> void:
    if impact_pos == Vector3.ZERO: return
    var impact = bullet_impact.instantiate()
    get_tree().current_scene.add_child(impact)
    impact.global_position = impact_pos
    impact_array.append(impact)


func get_rand_point_on_circle(center : Vector3) -> Vector3:
    var theta = randf_range(0, 2 * PI)
    
    # 生成距离圆心的随机距离(在圆半径范围内)
    var distance = randf_range(0, radius)
    
    # 计算圆平面内的随机点位置
    var x = center.x + distance * cos(theta)
    var y = center.y + distance * sin(theta)
    
    # Z坐标保持与圆心一致,确保点在平面内
    var z = center.z
    
    return Vector3(x, y, z)

问题场景截图

  • 前方向(normal):normal
  • 侧方视角:侧方视角
  • 另一视角:另一视角

问题原因

  1. 生成平面与玩家朝向脱节:当前get_rand_point_on_circle始终在世界坐标系的XY平面生成随机点,完全不关联玩家的旋转状态,导致玩家转向后,随机点仍固定在原平面。
  2. 旋转逻辑错误:使用rand_point.rotated(Vector3.RIGHT, player.rotation.y)时,是绕世界固定X轴旋转整个点,且旋转中心是世界原点而非碰撞点,这会导致碰撞点本身被错误偏移,而非仅让偏移量跟随玩家旋转。

修正方案

替换handle_raycast函数,改为基于玩家全局变换生成跟随旋转的随机偏移:

func handle_raycast() -> void:
    var rand_point : Vector3 = Vector3.ZERO
    
    if raycast.is_colliding():
        var point = raycast.get_collision_point()
        
        # 1. 在玩家局部坐标系的XY平面生成随机偏移(对应玩家的左右/上下方向)
        var theta = randf_range(0, 2 * PI)
        var distance = randf_range(0, radius)
        var local_offset = Vector3(distance * cos(theta), distance * sin(theta), 0)
        
        # 2. 将局部偏移转换为世界坐标系下的向量,匹配玩家当前朝向
        var world_offset = player.global_transform.basis * local_offset
        
        # 3. 最终随机点 = 碰撞点 + 世界空间偏移
        rand_point = point + world_offset
        handle_impact(rand_point)

逻辑说明

  • 玩家局部坐标系的X轴对应左右方向,Y轴对应上下方向,生成的偏移会自然跟随玩家旋转。
  • 通过player.global_transform.basis将局部偏移转换为世界空间向量,确保偏移方向与玩家当前朝向一致。
  • 直接将偏移加到碰撞点上,避免了以世界原点为中心的错误旋转问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 05:13:15