Изменить анимацию в зависимости от положения экрана мыши в Unity 2D - PullRequest
0 голосов
/ 17 марта 2019

Я занимаюсь разработкой изометрической 2D-игры в Unity с использованием скриптов на C #.Персонаж сможет бегать в 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);
    }

Эта ориентация получена сценарием AnimationController, который запускает анимацию.

Я не могу просто повернуть символ, или перевернуть спрайт, или что-то подобноепотому что это анимация.

Ответы [ 2 ]

0 голосов
/ 18 марта 2019

Отвечая на мой собственный вопрос:

С помощью только что выпущенного патча 3.8f1 для Unity я нашел в их демонстрационном проекте способ запуска анимации очень простым способом.

Япросто используя код, который вы можете найти на официальном сайте: 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);
    }
0 голосов
/ 18 марта 2019

Здесь вы делаете работу дважды. Таким образом, с точки зрения оптимизации, которая не идеальна, но с точки зрения дизайна, которая может быть полезна для разделения работ. Вопрос в том, откуда берется параметр движения в методе 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 вам не нужно создавать новый вектор в начале, поскольку вы покрываете все возможные углы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...