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

Godot 4.0中如何用move_and_collide仅检测水平轴碰撞?解决敌人转向异常

解决Godot 3D敌人移动碰撞转向问题

区分墙壁与地板碰撞的两种方案

1. 通过碰撞法线判断

地板碰撞的法线接近竖直方向(y轴正方向),墙壁的法线则为水平方向(x/z轴方向)。你可以通过碰撞对象的法线分量区分:

  • 获取碰撞法线:collided.get_normal()
  • 判断法线的y分量绝对值,若接近1则为地板,不触发转向;若接近0则为墙壁,反转移动方向。

2. 使用碰撞层/掩码区分

给地板和墙壁设置不同的碰撞层,在敌人节点的碰撞掩码中只勾选墙壁所在的层。这样move_and_collide只会检测与墙壁的碰撞,完全忽略地板,从根源避免误触发。

Godot 4.0中仅检测水平轴碰撞的实现

可以通过以下两种方式实现:

  • 单独拆分水平与竖直方向的运动:先处理竖直方向的重力(依赖is_on_floor()),再单独构造水平方向的速度向量传入move_and_collide,这样检测的只有水平方向的碰撞。
  • 结合move_and_slide(更推荐):CharacterBody3D的move_and_slide自带地板滑动处理,你可以遍历滑动碰撞,只对水平方向的碰撞(墙壁)触发转向逻辑。

优化后的代码示例

基于move_and_collide的版本

var speed = 4.0  # 建议调整为合理速度,0.1过慢
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")

func _physics_process(delta):
    # 处理重力(Godot 4中y轴向上,重力方向为负)
    if not is_on_floor():
        velocity.y -= gravity * delta

    # 设置水平速度
    velocity.x = speed
    # 执行移动并获取碰撞结果(记得乘delta保证帧率无关)
    var collision = move_and_collide(velocity * delta)

    if collision:
        var normal = collision.get_normal()
        # 法线y分量小于0.5,判定为墙壁碰撞
        if abs(normal.y) < 0.5:
            speed *= -1

更稳定的move_and_slide版本

var speed = 4.0
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")

func _physics_process(delta):
    # 重力处理
    if not is_on_floor():
        velocity.y -= gravity * delta

    # 水平移动
    velocity.x = speed
    # 执行滑动移动
    move_and_slide()

    # 遍历所有滑动碰撞,检测墙壁
    for i in range(get_slide_collision_count()):
        var col = get_slide_collision(i)
        var normal = col.get_normal()
        if abs(normal.y) < 0.5:
            speed *= -1
            break  # 避免单次帧内多次反转方向

注意:碰撞法线的判断阈值(0.5)可根据场景调整,比如存在斜坡时,可适当降低阈值来区分斜坡与墙壁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 20:13:12