如何旋转单个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):

- 侧方视角:

- 另一视角:

问题原因
- 生成平面与玩家朝向脱节:当前
get_rand_point_on_circle始终在世界坐标系的XY平面生成随机点,完全不关联玩家的旋转状态,导致玩家转向后,随机点仍固定在原平面。 - 旋转逻辑错误:使用
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
相关产品推荐
相关产品推荐

