Объект выходит из портала, двигаясь в неверном направлении в Unity 2D? - PullRequest
6 голосов
/ 22 марта 2020

Прежде чем начать, я хотел бы сказать, извините, если это не очень профессионально написано, я работал над этим часами, стуча головой о стену, пытаясь понять это без удачи, я устал и подчеркнул.

Я пытаюсь заставить движущийся объект войти через 1 портал в указанной точке c и выйти из другого портала в той же точке, в которую он вошел. Таким образом, если шарик входит в верхнюю часть портала, объект выйдет в верхнюю часть выходного портала, а если объект входит в нижнюю часть портала, он выйдет из нижней части другого портала. Я не самая лучшая иллюстрация, но вот что я хочу сделать: enter image description here Здесь вы можете видеть на обоих изображениях объект входит в синий портал и выходит из оранжевого в той точке, в которую он вошел так что сверху вниз, снизу вниз.

Я действительно заставил это работать нормально, но теперь мне нужно сделать это снова, но на этот раз один из порталов должен быть горизонтальным, а не вертикальным: enter image description here Итак, что я сделал, так это сделал так, чтобы когда оба вертикальных, я оставлял флажок «exitIsHorizontal» без проверки (false), и когда один из них находился на потолке на уровне , он переводит вертикальную ось в горизонтальную.

Я даже вроде как заставил это работать, однако у него есть воспроизводимый кварк, который нужно исправить. Когда объект попадает в нижнюю часть портала, он работает нормально, как вы ожидаете, и так же, как на картинке выше. Но когда вы попадаете на верхнюю часть портала, объект выходит с другой стороны портала, как и следовало ожидать, но объект начинает двигаться в противоположном направлении, как показано на этом изображении: enter image description here Правильное расположение выхода, неправильное направление выхода по некоторым причинам. Мне также нужно, чтобы эта функция была динамической c, чтобы, если, скажем, объект попадал на синий портал с другого направления, в котором направление выхода также поменялось бы на стороны: enter image description here

Вот мой скрипт:

    public GameObject otherPortal;
    public PortalController otherPortalScript;
    private BallController ballController;
    public bool exitIsHorizontal = false;

    List<PortalController> inUseControllers =  new List<PortalController>();

    // Use this for initialization
    void Start () 
    {

    }

    // Update is called once per frame
    void Update () 
    {

    }

    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.tag == "Ball")
        {
            ballController = other.GetComponent<BallController>();
            if (inUseControllers.Count == 0)
            {
                inUseControllers.Add(otherPortalScript);
                var offset = other.transform.position - transform.position;
                if(exitIsHorizontal)
                {
                    offset.x = offset.y;
                    offset.y = 0;
                }
                else
                {
                    offset.x = 0;
                }
                other.transform.position = otherPortal.transform.position + offset;
            }            
        }
    }

    void OnTriggerExit2D(Collider2D other)
    {
        if (other.gameObject.tag == "Ball")
        {
            inUseControllers.Clear();
        }

    }

Этот скрипт прикреплен к обоим порталам, так что оба портала могут обрабатывать как вход, так и выход. И любую переменную, которую вы не видите объявленной с помощью чего-либо в скрипте, делающей ее практически нулевой (например, «otherPotal»), я объявляю в редакторе.

Держу пари, это что-то чрезвычайно простое, что я просто пропускаю Я просто не знаю, что что-то есть.

1 Ответ

3 голосов
/ 22 марта 2020

Итак, портал - это в основном червоточина. Объект, который входит, сохранит свою локальную позицию и направление.

wormhole

Функции:

Unity имеет функции для преобразования из мирового пространства в локальное и наоборот.

Положение:

Transform.InverseTransformPoint

Преобразует положение из мирового пространства в локальное пространство.

Transform.TransformPoint

Преобразует положение из локального пространства в мировое пространство.

jumping

Направление:

Для преобразования направлений вам придется использовать:

Transform.InverseTransformDirection

Преобразует направление из мирового пространства в локальное пространство. Противоположность Transform.TransformDirection.

Transform.TransformDirection

Преобразует направление из локального пространства в мировое пространство.

Простой пример:

Один скрипт, который вы присоединяете к обоим порталам. Он перемещает объекты с тегом "Шар" на exitPortal.

public class Portal : MonoBehaviour
{
    [SerializeField] Portal exitPortal;

    void OnTriggerEnter2D(Collider2D collider)
    {
        if (collider.CompareTag("Ball"))
        {
            GameObject ball = collider.gameObject;
            Rigidbody2D rigidbody = ball.GetComponent<Rigidbody2D>();

            Vector3 inPosition = this.transform.InverseTransformPoint(ball.transform.position);
            inPosition.x = -inPosition.x;
            Vector3 outPosition = exitPortal.transform.TransformPoint(inPosition);            

            Vector3 inDirection = this.transform.InverseTransformDirection(rigidbody.velocity);
            Vector3 outDirection = exitPortal.transform.TransformDirection(inDirection);

            ball.transform.position = outPosition;
            rigidbody.velocity = -outDirection;
        }
    }
}

Вы получаете это:

fun

Сложный пример:

Вам нужно 3 сценария, чтобы это работало:

  • Портал: То, что касается деформируемых объектов
  • Деформация: Предмет, который путешествует по порталам
  • Призрак: Зеркальная деформация, отображаемая при прохождении через портал

Вот как выглядит призрак:

ghost

Вам понадобятся два дополнительных слоя - Portal и Ghost, с матрицей столкновений, установленной как на рисунке .

matrix

Сценарии:

Я добавил достаточно комментариев в коде, чтобы вы могли понять, что он делает.

Портал:

public class Portal : MonoBehaviour
{
    [SerializeField] Portal exitPortal;

    void OnTriggerEnter2D(Collider2D collider)
    {
        // When a warpable enters a portal create a ghost
        if (collider.TryGetComponent(out Warpable warpable))
        {
            // Create a ghost only if we haven't already
            if (warpable.Ghost == null) warpable.CreateGhost(this, exitPortal);
        }
    }

    void OnTriggerExit2D(Collider2D collider)
    {
        // When a warpable exist a portal; check if it has a ghost
        if (collider.TryGetComponent(out Warpable warpable))
        {
            // Teleport to the ghost; apply its position, rotation, velocity
            if (warpable.Ghost != null)
            {
                // Create vectors to compare dot product
                Vector3 portalToWarpable = warpable.transform.position - this.transform.position;
                Vector3 portalDownwards = -this.transform.up;

                // If warpable is on the other side of the portal you get a value that's more than zero
                float dot = Vector3.Dot(portalDownwards, portalToWarpable);
                bool passedThroughPortal = dot >= 0f;

                // If we passed through the portal then teleport to the ghost; otherwise just continue
                if (passedThroughPortal)
                {
                    warpable.Position = warpable.Ghost.warpable.Position;
                    warpable.Rotation = warpable.Ghost.warpable.Rotation;
                    warpable.Velocity = warpable.Ghost.warpable.Velocity;
                }

                // Destroy the ghost
                warpable.DestroyGhost();
            }
        }
    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.magenta;
        Gizmos.DrawRay(this.transform.position, this.transform.up);
    }
}

Деформируемый:

public class Warpable : MonoBehaviour
{
    [SerializeField] new Rigidbody2D rigidbody;

    public Ghost Ghost { get; private set; }

    public void CreateGhost(Portal inPortal, Portal outPortal)
    {
        // Move the ghost object to the Ghost layer, this is so that ghost can collide with real objects, other ghosts, but not with the portal.

        // Ghost/Ghost      =   TRUE
        // Ghost/Default    =   TRUE
        // Ghost/Portal     =   FALSE

        GameObject original = this.gameObject;
        GameObject duplicate = GameObject.Instantiate(original);
        duplicate.layer = LayerMask.NameToLayer("Ghost");

        Physics2D.IgnoreCollision(
            original.GetComponent<Collider2D>(),
            duplicate.GetComponent<Collider2D>()
        );

        // Add the ghost component
        Ghost = duplicate.AddComponent<Ghost>();

        Ghost.observing = original.GetComponent<Warpable>();
        Ghost.warpable = duplicate.GetComponent<Warpable>();

        Ghost.inPortal = inPortal;
        Ghost.outPortal = outPortal;
    }

    public void DestroyGhost()
    {
        GameObject.Destroy(Ghost.gameObject);
        Ghost = null;
    }

    public Vector3 Position
    {
        get { return transform.position; }
        set { transform.position = value; }
    }

    public Quaternion Rotation
    {
        get { return transform.rotation; }
        set { transform.rotation = value; }
    }

    public Vector3 Velocity
    {
        get { return rigidbody.velocity; }
        set { rigidbody.velocity = value; }
    }
}

Призрак:

public class Ghost : MonoBehaviour
{
    public Warpable observing;
    public Warpable warpable;

    public Portal inPortal;
    public Portal outPortal;

    void FixedUpdate()
    {
        warpable.Position = OutPosition(observing.Position);
        warpable.Rotation = OutRotation(observing.Rotation);
        warpable.Velocity = OutDirection(observing.Velocity);
    }

    Vector3 OutPosition(Vector3 position)
    {
        Vector3 inPosition = -inPortal.transform.InverseTransformPoint(position);
        return outPortal.transform.TransformPoint(inPosition);
    }

    Quaternion OutRotation(Quaternion rotation)
    {
        return Quaternion.Inverse(inPortal.transform.rotation) * outPortal.transform.rotation * rotation;
    }

    Vector3 OutDirection(Vector3 velocity)
    {
        Vector3 inDirection = -inPortal.transform.InverseTransformDirection(velocity);
        return outPortal.transform.TransformDirection(inDirection);
    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.cyan;
        Gizmos.DrawWireSphere(warpable.Position, 1f);
        Gizmos.DrawLine(warpable.Position, warpable.Position + warpable.Velocity);
    }
}

И окончательный результат таков:

warping

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