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

Unity 2D中随机路径移动时如何避免碰撞物体?

解决2D迷宫敌人穿墙问题的几种方案

嘿,完全懂这种卡了一周的憋屈!咱们一步步把敌人穿墙的毛病给修好。从你描述的情况和代码片段来看,核心问题大概率出在碰撞检测没生效或者移动方式绕过了物理引擎,给你几个针对性的解决思路:

1. 先把敌人的碰撞组件配置对

这是最基础也最容易忽略的点:

  • 给敌人GameObject添加Rigidbody2D组件:
    • 如果是用路径点移动,建议把Body Type设为Kinematic(不会受重力影响,但依然能触发碰撞),同时确保Freeze Rotation Z是勾选的(避免敌人旋转)。
  • 给敌人添加合适的Collider2D(比如BoxCollider2D或CircleCollider2D):
    • 一定要取消勾选Is Trigger!勾了这个会让碰撞体变成触发器,完全不参与物理碰撞,敌人自然就穿墙了。
    • 调整Collider的大小,确保它和敌人的Sprite轮廓匹配,不要太大也不要太小。

2. 用物理引擎驱动移动,别直接改Transform

很多入门教程会用transform.Translate或者直接赋值transform.position来移动敌人,这种方式会直接绕过Unity的物理碰撞系统,敌人当然能穿墙。改成用Rigidbody2D的方法来移动:

public class Enemy_AI : MonoBehaviour 
{
    public float speed;
    public float waitTime;
    public float startWaitTime;
    // 假设你有存储路径点的列表
    public List<Transform> waypoints;
    private int currentWaypointIndex;
    private Rigidbody2D rb;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        startWaitTime = waitTime;
        currentWaypointIndex = Random.Range(0, waypoints.Count);
    }

    void Update()
    {
        // 计算到目标点的方向
        Vector2 targetPos = waypoints[currentWaypointIndex].position;
        Vector2 moveDirection = (targetPos - (Vector2)transform.position).normalized;

        // 用Rigidbody2D.MovePosition来移动,会遵守碰撞规则
        rb.MovePosition(rb.position + moveDirection * speed * Time.deltaTime);

        // 到达目标点后切换下一个随机点
        if(Vector2.Distance(transform.position, targetPos) < 0.1f)
        {
            if(waitTime <= 0)
            {
                currentWaypointIndex = Random.Range(0, waypoints.Count);
                waitTime = startWaitTime;
            }
            else
            {
                waitTime -= Time.deltaTime;
            }
        }
    }
}

3. 确保随机选的路径点是“可达”的

如果你的路径点本身就放在墙里,或者当前位置到目标点的直线穿墙,敌人还是会硬穿过去。可以加个射线检测来验证路径是否合法:

// 在Inspector里把墙所在的图层拖进来
public LayerMask wallLayer;

// 检查两点之间是否有墙阻挡
bool IsPathClear(Vector2 start, Vector2 end)
{
    RaycastHit2D hit = Physics2D.Linecast(start, end, wallLayer);
    // 如果没有撞到任何墙,路径就是通的
    return hit.collider == null;
}

// 切换路径点的时候用这个方法验证
void SwitchToRandomWaypoint()
{
    int newIndex;
    Vector2 targetPos;
    do
    {
        newIndex = Random.Range(0, waypoints.Count);
        targetPos = waypoints[newIndex].position;
    } while(!IsPathClear((Vector2)transform.position, targetPos));
    
    currentWaypointIndex = newIndex;
}

4. 升级成2D NavMesh寻路(更省心的方案)

如果上面的方法还是有问题,直接用Unity的2D导航网格系统,它会自动处理绕路,彻底解决穿墙问题:

  • 给所有墙添加NavMeshObstacle2D组件,调整Size和Offset让它覆盖墙的区域。
  • 打开Window > AI > NavMesh > 2D NavMesh Settings,设置好Agent Radius(和敌人的碰撞体大小匹配),然后点击Bake烘焙导航网格。
  • 给敌人添加NavMeshAgent2D组件,设置Speed为你的speed值,然后用代码设置随机目标点:
private NavMeshAgent2D navAgent;

void Start()
{
    navAgent = GetComponent<NavMeshAgent2D>();
    navAgent.speed = speed;
    // 初始设置随机目标
    SetRandomDestination();
}

void SetRandomDestination()
{
    // 从路径点列表里选一个点
    Transform randomWaypoint = waypoints[Random.Range(0, waypoints.Count)];
    navAgent.SetDestination(randomWaypoint.position);
}

// 可以在Update里检查是否到达目标,然后切换下一个点
void Update()
{
    if(!navAgent.pathPending && navAgent.remainingDistance < 0.1f)
    {
        if(waitTime <= 0)
        {
            SetRandomDestination();
            waitTime = startWaitTime;
        }
        else
        {
            waitTime -= Time.deltaTime;
        }
    }
}

先从第1、2步开始排查,这两个是最常见的问题。如果还是不行,把完整的Enemy_AI代码贴出来,咱们再细化找问题!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:33:37