在Unity 2D中根据鼠标屏幕位置更改动画

问题描述 投票:0回答:2

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

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

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

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

我写了一个方法,它返回一个基于运动的Orientations值。这是因为我想基于运动触发动画,因此角色将始终关注运动的方向:

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);
    }

此Orientation由触发动画的AnimationController脚本接收。

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

c# unity3d 2d
2个回答
0
投票

你在这里做两次工作。因此,从优化的角度来看,这不是理想的,但在设计的角度来看,可以很好地分离作品。问题是运动参数在GetOrientationByMovement方法中来自何处?你可以使用方向枚举吗?如果是,那么这大大简化了你的代码!你最终得到:

public static Orientations AngleToVectorDirection(Transform transform)
    {
        float angle = GetMousePosition(transform);

        if(angle >= 67.5 && angle < 112.5)
        {
            return Orientations.N;
        }
        else if (angle >= 112.5 && angle < 157.5)
        {
            return Orientations.NW;
        }
        else if (angle >= 157.5 && angle < 202.5)
        {
            return Orientations.W;
        }
        else if (angle >= 202.5 && angle < 247.5)
        {
            return Orientations.SW;
        }
        else if (angle >= 247.5 && angle < 292.5)
        {
            return Orientations.S;
        }
        else if (angle >= 292.5 && angle < 337.5)
        {
            return Orientations.SE;
        }
        else if (angle >= 337.5 || angle < 22.5)
        {
            return Orientations.E;
        }
        else if (angle >= 22.5 && angle < 67.5)
        {
            return Orientations.NE;
        }
    }

还要尽量保持代码的一致性。如果你在if语句中使用返回值,那么对于这两个函数都要这样做,在外面使用它时,无处不在。请注意,在AngleToVectorDirection的实现中,您不需要在开头创建新向量,因为您可以覆盖所有角度。


0
投票

回答我自己的问题:

通过刚刚发布的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()作为参数传递string []的值,基于玩家移动。

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);
    }
© www.soinside.com 2019 - 2024. All rights reserved.