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
相关产品推荐
相关产品推荐

