You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Unity 3D中敌人跟随玩家时如何根据移动方向播放动画?

问题描述

我正在开发一款2.5D足球游戏,采用3D空间+精灵资源的方案。当前需要实现敌人跟随玩家移动时,根据自身移动方向播放对应动画,方向包括:向后、向左、向右、后左、后右、前左、前右,且尽量不使用Blend Tree(混合树)。

之前尝试用transform.position.x/z判断方向,但效果很差——因为位置坐标无法反映实时的移动输入/速度方向。现有代码如下:

using UnityEngine;

public class EnnemyAnimation : MonoBehaviour
{
    void Update()
    {
       if (transform.position.x > 0)
       {
           Debug.Log("right");   // play animation right
       }
       else if (transform.position.x < 0)
       {
           Debug.Log("left");    // play animation left
       }
       else if (transform.position.z < 0) 
       {
           Debug.Log("back");    // play animation back
       }
       else if (transform.position.z > 0)
       {
           Debug.Log("front");    // play animation front
       }
       else if (transform.position.x < 0 && transform.position.z < 0)
       {
           Debug.Log("back-left");    // play animation back left
       }
       else if (transform.position.x > 0 && transform.position.z < 0)
       {
           Debug.Log("back-right");   // play animation back right
       }
       else if (transform.position.x < 0 && transform.position.z > 0)
       {
           Debug.Log("front-left");    // play animation front left
       }
       else if (transform.position.x > 0 && transform.position.z > 0)
       {
           Debug.Log("front-right");   // play animation front right
       }
    }
}
实现方案

核心思路

放弃用位置坐标判断,改用敌人的移动方向向量(或目标方向向量)来判定,这样能精准反映当前的移动意图,避免位置漂移带来的判断错误。

修正代码

using UnityEngine;

public class EnemyAnimation : MonoBehaviour
{
    // 跟随目标(比如玩家)
    public Transform target;
    private Rigidbody rb;
    private Animator anim;

    // 方向阈值:过滤微小移动,避免动画频繁切换
    public float directionThreshold = 0.2f;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        anim = GetComponent<Animator>();
    }

    void Update()
    {
        // 1. 获取指向目标的方向(忽略Y轴,适配2.5D平面移动)
        Vector3 worldMoveDir = target.position - transform.position;
        worldMoveDir.y = 0;
        worldMoveDir.Normalize();

        // 2. 转换为敌人本地坐标系下的方向(避免世界坐标干扰)
        Vector3 localMoveDir = transform.InverseTransformDirection(worldMoveDir);

        // 3. 过滤静止状态
        bool isMoving = worldMoveDir.magnitude > 0.01f;
        if (!isMoving)
        {
            anim.Play("Idle");
            return;
        }

        // 4. 按前后→左右的优先级判断方向
        if (localMoveDir.z < -directionThreshold)
        {
            // 向后区域
            if (localMoveDir.x < -directionThreshold)
                anim.Play("BackLeft");
            else if (localMoveDir.x > directionThreshold)
                anim.Play("BackRight");
            else
                anim.Play("Back");
        }
        else if (localMoveDir.z > directionThreshold)
        {
            // 向前区域
            if (localMoveDir.x < -directionThreshold)
                anim.Play("FrontLeft");
            else if (localMoveDir.x > directionThreshold)
                anim.Play("FrontRight");
            else
                anim.Play("Front");
        }
        else
        {
            // 纯左右区域
            if (localMoveDir.x < -directionThreshold)
                anim.Play("Left");
            else if (localMoveDir.x > directionThreshold)
                anim.Play("Right");
        }
    }
}

关键说明

  • 本地坐标系转换InverseTransformDirection将世界方向转为敌人自身的本地方向,确保"前/后/左/右"始终对应敌人的朝向,适配2.5D精灵的展示逻辑。
  • 方向阈值directionThreshold可以根据游戏手感调整(建议0.1~0.3),避免物理抖动或微小移动导致动画频繁切换。
  • 优先级判断:先判断前后方向,再细化左右,确保斜向方向不会被单一方向的判断覆盖。
  • 适配自定义移动:如果不用Rigidbody驱动移动,直接把worldMoveDir换成你的自定义移动输入向量即可,核心逻辑不变。

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

火山引擎 最新活动