首页 > 解决方案 > 在 Unity 2D 中根据鼠标屏幕位置更改动画

问题描述

我正在使用 C# 脚本在 Unity 中开发等距 2D 游戏。角色将能够以 8 个不同的方向奔跑。

我正在尝试根据鼠标位置触发运行动画。我的脚本运行良好,但我认为这不是解决这个问题的最佳方法。

首先,我有一个带有可能方向的枚举:

public enum Orientations {N,NE,E,SE,S,SW,W,NW,NONE}

我编写了一个基于运动返回方向值的方法。这是因为我想根据运动触发动画,所以 Character 将始终注视运动的方向:

public static Orientations GetOrientation(Vector2 movement)
    {
        if (movement.x == 0 && movement.y == 1)
        {
            return Orientations.N;
        }
        else if (movement.x == 1 && movement.y == 0)
        {
            return Orientations.E;
        }
        else if (movement.x == 0 && movement.y == -1)
        {
            return Orientations.S;
        }
        else if (movement.x == -1 && movement.y == 0)
        {
            return Orientations.W;
        }
        else if (movement.x == -1 && movement.y == 1)
        {
            return Orientations.NW;
        }
        else if (movement.x == 1 && movement.y == 1)
        {
            return Orientations.NE;
        }
        else if (movement.x == -1 && movement.y == -1)
        {
            return Orientations.SW;
        }
        else if (movement.x == 1 && movement.y == -1)
        {
            return Orientations.SE;
        }
        return Orientations.NONE;
    }

接下来,我得到角色和屏幕之间的鼠标角度。

public static float GetMousePosition(Transform transform)
    {
        float cameraDistance = Camera.main.transform.position.y - transform.position.y;
        Vector3 mousePosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, cameraDistance));
        float angleRadius = Mathf.Atan2(mousePosition.y - transform.position.y, mousePosition.x - transform.position.x);
        float angle = (180 / Mathf.PI) * angleRadius;
        angle = (angle < 0) ? angle + 360 : angle;
        return angle;
    }

然后,我在 Vector2 中转换角度,因此我可以通过角色移动和鼠标位置在触发动画之间切换:

public static Vector2 AngleToVectorDirection(Transform transform)
    {
        Vector2 direction = new Vector2(0,0);
        float angle = GetMousePosition(transform);

        if(angle >= 67.5 && angle < 112.5)
        {
            direction = new Vector2(0,1);
        }
        else if (angle >= 112.5 && angle < 157.5)
        {
            direction = new Vector2(-1,1);
        }
        else if (angle >= 157.5 && angle < 202.5)
        {
            direction = new Vector2(-1, 0);
        }
        else if (angle >= 202.5 && angle < 247.5)
        {
            direction = new Vector2(-1, -1);
        }
        else if (angle >= 247.5 && angle < 292.5)
        {
            direction = new Vector2(0, -1);
        }
        else if (angle >= 292.5 && angle < 337.5)
        {
            direction = new Vector2(1, -1);
        }
        else if (angle >= 337.5 || angle < 22.5)
        {
            direction = new Vector2(1, 0);
        }
        else if (angle >= 22.5 && angle < 67.5)
        {
            direction = new Vector2(1, 1);
        }
        return direction;
    }

最后,我返回我提到的方向:

public static Orientations GetOrientationByMovement(Transform transform, Vector2 movement)
    {
        Vector2 orientation;

        if (!Input.GetButton("Fire1"))
        {
            orientation = movement;
        }

        else
        {
            orientation = AngleToVectorDirection(transform);
        }
        return GetOrientation(orientation);
    }

这个方向由触发动画的 AnimationController 脚本接收。

我不能简单地旋转角色、翻转精灵或类似的东西,因为它是基于动画的。

标签: c#unity3d2d

解决方案


回答我自己的问题:

在刚刚发布的 unity 3.8f1 补丁中,我在他们的演示项目中发现了一种以非常简单的方式触发动画的方法。

我只是使用您可以在官方网站上找到的代码: https ://blogs.unity3d.com/2019/03/18/isometric-2d-environments-with-tilemap/?_ga=2.120446600.1010886114.1552829987-288556513.1552829987

他们使用 IsometricCharacterRenderer 脚本,其中使用 Animator.Play() 根据玩家的移动将字符串 [] 的值作为参数传递。

public static readonly string[] staticDirections = { "Static N", "Static NW", "Static W", "Static SW", "Static S", "Static SE", "Static E", "Static NE" };
public static readonly string[] runDirections = { "Run N", "Run NW", "Run W", "Run SW", "Run S", "Run SE", "Run E", "Run NE" };

public void SetDirection(Vector2 direction)
    {

        //use the Run states by default
        string[] directionArray = null;

        //measure the magnitude of the input.
        if (direction.magnitude < .01f)
        {
            //if we are basically standing still, we'll use the Static states
            //we won't be able to calculate a direction if the user isn't pressing one, anyway!
            directionArray = staticDirections;
        }
        else
        {
            //we can calculate which direction we are going in
            //use DirectionToIndex to get the index of the slice from the direction vector
            //save the answer to lastDirection
            directionArray = runDirections;
            lastDirection = DirectionToIndex(direction, 8);
        }

        //tell the animator to play the requested state
        animator.Play(directionArray[lastDirection]);
    }

为了获得方向索引,他们将运动转换为一个角度,就像我所做的那样,但以一种聪明的方式。

public static int DirectionToIndex(Vector2 dir, int sliceCount)
    {
        //get the normalized direction
        Vector2 normDir = dir.normalized;
        //calculate how many degrees one slice is
        float step = 360f / sliceCount;
        //calculate how many degress half a slice is.
        //we need this to offset the pie, so that the North (UP) slice is aligned in the center
        float halfstep = step / 2;
        //get the angle from -180 to 180 of the direction vector relative to the Up vector.
        //this will return the angle between dir and North.
        float angle = Vector2.SignedAngle(Vector2.up, normDir);
        //add the halfslice offset
        angle += halfstep;
        //if angle is negative, then let's make it positive by adding 360 to wrap it around.
        if (angle < 0)
        {
            angle += 360;
        }
        //calculate the amount of steps required to reach this angle
        float stepCount = angle / step;
        //round it, and we have the answer!
        return Mathf.FloorToInt(stepCount);
    }

推荐阅读