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

Godot 4中如何让CharacterBody3D对齐圆柱网格实现F-Zero X式移动?

实现CharacterBody3D绕圆柱旋转移动(仿F-Zero X)

你的思路完全可行,通过多射线加权计算目标法线的方式,能稳定获取角色所在圆柱表面的贴合方向,接下来可以通过平滑旋转对齐法线+适配表面的移动逻辑完成需求,具体实现步骤如下:


一、完善目标法线计算(避免除以0错误)

首先要处理射线未碰撞或距离为0的情况,防止计算报错:

func _physics_process(delta):
    # 初始化权重和法线列表
    var weights: Array[float] = []
    var normals: Array[Vector3] = []

    # 遍历三个射线,收集有效碰撞数据
    for ray in [Raycast1, Raycast2, Raycast3]:
        if ray.is_colliding():
            var dist = ray.get_collision_point().distance_to(ray.global_position)
            if dist > 0.001: # 避免除以0
                weights.append(1.0 / dist)
                normals.append(ray.get_collision_normal())

    # 计算目标法线,无有效碰撞时 fallback 到默认向上
    var target_normal = Vector3.UP
    if weights.size() > 0:
        var weighted_sum = Vector3.ZERO
        for i in range(weights.size()):
            weighted_sum += weights[i] * normals[i]
        target_normal = weighted_sum.normalized()

二、平滑旋转角色对齐目标法线

通过球面插值(slerp)让角色的basis.y(当前向上方向)逐步对齐target_normal,同时保留角色的前进方向在圆柱表面的切平面上:

# 获取当前角色的向上和前进方向
    var current_up = basis.y
    var current_forward = basis.z

    # 将前进方向投影到目标法线的垂直平面(切平面),避免旋转时方向偏移
    var target_forward = (current_forward - target_normal * current_forward.dot(target_normal)).normalized()
    # 处理投影后方向接近零的极端情况
    if target_forward.length_squared() < 0.001:
        target_forward = Vector3.FORWARD

    # 创建目标坐标系:以target_normal为向上,target_forward为前进
    var target_basis = Basis.looking_at(target_forward, target_normal)

    # 平滑旋转到目标坐标系(rotation_speed控制旋转快慢,建议设为4~6)
    var rotation_speed = 5.0
    basis = basis.slerp_to(target_basis, rotation_speed * delta)

三、适配圆柱表面的移动逻辑

调整重力方向让角色贴紧圆柱,同时将玩家输入转换为表面切向的移动方向:

# 读取玩家输入(需提前在项目设置中绑定move_forward/move_backward/move_left/move_right动作)
    var input_dir = Vector2(
        Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
        Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
    ).normalized()

    # 将2D输入转换为角色局部坐标系的3D移动方向
    var move_dir = basis.x * input_dir.x + basis.z * input_dir.y
    # 确保移动方向严格在切平面内(垂直于目标法线)
    move_dir = (move_dir - target_normal * move_dir.dot(target_normal)).normalized()

    # 调整重力方向:让角色被"吸附"在圆柱表面
    var gravity = -target_normal * 12.0 # 数值可根据需求调整
    velocity += gravity * delta

    # 应用移动速度(move_speed控制角色移动快慢)
    var move_speed = 8.0
    velocity = move_dir * move_speed + gravity * delta

    # 执行移动(传入target_normal作为地面法线,让move_and_slide正确处理碰撞)
    move_and_slide(velocity, target_normal)

关键注意事项

  • 射线布局:建议将三个射线分布在角色的前、左、右三个方向(或上、左、右),避免集中在一侧导致法线计算偏差。
  • 参数调整:rotation_speed、gravity、move_speed需要根据你的场景大小和手感需求反复调试。
  • 边界处理:当角色离开圆柱表面时,代码会自动 fallback 到默认向上方向,可根据需求添加额外的脱离判定逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 21:55:09