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

Godot 4基于RigidBody3D的3D赛车Context Steering AI修复需求

Godot 4 3D赛车AI修复(情境转向+Path3D跟随)

问题概述

使用Phind生成的脚本控制RigidBody3D赛车时,仅能移动但无法正确旋转,且Path3D跟随逻辑未正确实现。节点结构为:父节点RigidBody3D,子节点包含MeshInstance3D、CollisionShape3D。

修复后的完整脚本

extends RigidBody3D

@export var max_speed: float = 350.0
@export var steer_force: float = 0.1
@export var look_ahead_distance: float = 100.0
@export var num_rays: int = 8
@export var path: Path3D  # 关联场景中的Path3D节点
@export var ray_length: float = 50.0  # 危险检测射线长度

var ray_directions: Array[Vector3] = []
var interest: Array[float] = []
var danger: Array[float] = []
var chosen_dir: Vector3 = Vector3.ZERO

func _ready():
    # 初始化射线方向:围绕Y轴(竖直轴)生成均匀分布的射线
    ray_directions.resize(num_rays)
    interest.resize(num_rays)
    danger.resize(num_rays)
    
    for i in range(num_rays):
        var angle = i * 2 * PI / num_rays
        # 基于本地Z轴(前进方向)生成射线,覆盖360度
        ray_directions[i] = Vector3.FORWARD.rotated(Vector3.UP, angle)

func set_interest():
    if path:
        # 计算Path3D上的前进方向
        var path_position = path.curve.get_closest_point(global_position)
        var progress = path.curve.get_closest_offset(path_position)
        var look_ahead_point = path.curve.interpolate_baked(progress + look_ahead_distance)
        var path_direction = (look_ahead_point - global_position).normalized()
        path_direction.y = 0  # 保持水平方向,忽略Y轴高度变化
        
        # 计算每条射线与路径方向的匹配度(兴趣值)
        for i in range(num_rays):
            # 将射线方向转换为全局空间
            var global_ray_dir = global_transform.basis * ray_directions[i]
            global_ray_dir.y = 0
            # 点积越大,兴趣值越高(仅保留正向匹配)
            var dot_product = global_ray_dir.dot(path_direction)
            interest[i] = max(0.0, dot_product)
    else:
        # 默认兴趣:保持当前前进方向
        for i in range(num_rays):
            var global_ray_dir = global_transform.basis * ray_directions[i]
            global_ray_dir.y = 0
            var dot_product = global_ray_dir.dot(global_transform.basis.z)
            interest[i] = max(0.0, dot_product)

func set_danger():
    var space_state = get_world_3d().direct_space_state
    # 排除自身碰撞,避免射线检测到自己
    var exclude = [self]
    
    for i in range(num_rays):
        var global_ray_dir = global_transform.basis * ray_directions[i]
        global_ray_dir.y = 0  # 水平射线,只检测障碍物
        var ray_start = global_position + Vector3.UP * 0.5  # 从车身中部发射射线
        var ray_end = ray_start + global_ray_dir.normalized() * ray_length
        
        var query = PhysicsRayQueryParameters3D.create(ray_start, ray_end, exclude)
        var result = space_state.intersect_ray(query)
        
        # 根据障碍物距离计算危险值:越近危险值越高
        if result:
            var distance = (ray_start - result["position"]).length()
            danger[i] = 1.0 - (distance / ray_length)
        else:
            danger[i] = 0.0

func choose_direction():
    # 危险射线对应的兴趣值清零
    for i in range(num_rays):
        if danger[i] > 0.1:  # 阈值过滤轻微碰撞
            interest[i] = 0.0
    
    # 计算最终选择的方向
    chosen_dir = Vector3.ZERO
    for i in range(num_rays):
        chosen_dir += ray_directions[i] * interest[i]
    
    # 确保方向向量有效
    if chosen_dir.length_squared() > 0:
        chosen_dir = chosen_dir.normalized()
    else:
        # 无有效方向时保持当前前进方向
        chosen_dir = Vector3.FORWARD

func _physics_process(delta):
    set_interest()
    set_danger()
    choose_direction()
    
    # 将选择的方向转换为全局空间
    var global_chosen_dir = global_transform.basis * chosen_dir
    global_chosen_dir.y = 0  # 保持水平移动
    
    # 计算期望速度
    var desired_velocity = global_chosen_dir * max_speed
    # 平滑过渡到期望速度
    var target_velocity = linear_velocity.lerp(desired_velocity, steer_force * delta)
    target_velocity.y = linear_velocity.y  # 保留Y轴速度(比如重力影响)
    
    # 应用速度到刚体
    linear_velocity = target_velocity
    
    # 平滑旋转到前进方向
    if global_chosen_dir.length_squared() > 0:
        # 计算目标朝向
        var target_basis = Basis.looking_at(-global_chosen_dir, Vector3.UP)
        # 平滑插值旋转
        global_transform.basis = global_transform.basis.slerp(target_basis, steer_force * delta * 5.0)

关键修复说明

  • 旋转逻辑修正:放弃错误的look_at用法,改用slerp平滑插值刚体的Basis属性,确保旋转符合物理规则,同时保持水平方向避免倾斜。
  • 射线检测修复:修正射线起点/终点计算,排除自身碰撞,根据障碍物距离动态计算危险值,而非简单的0/1判断。
  • Path3D跟随实现:直接关联Path3D节点,通过路径上的前瞻点计算前进方向,确保赛车沿路径行驶。
  • 物理运动修正:将速度变量直接应用到RigidBody3D的linear_velocity属性,符合Godot物理引擎的控制逻辑,同时保留Y轴速度以响应重力。
  • 兴趣方向优化:基于全局空间计算射线与目标方向的点积,确保兴趣值计算准确,避免本地坐标系的方向混淆。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:21:03