简体   繁体   English

对象退出门户在 Unity 2D 中移动错误的方向?

[英]Object exits portal moving the wrong direction in Unity 2D?

Before I start I'd like to say sorry if this isn't highly professionally written, I've been working on this for hours banging my head against the wall trying to figure this out with no luck, I'm tired and stressed.在我开始之前,如果这不是高度专业的写法,我想说声抱歉,我已经为此工作了好几个小时,试图在没有运气的情况下解决这个问题,我累了,压力很大。

I'm trying to get a moving object to enter through 1 portal at a specific point, and come out the other portal at the same point it entered.我试图让一个移动的物体在特定点通过 1 个门户进入,并在它进入的同一点从另一个门户出来。 So if the ball enters the top of the portal, the object will come out at the top of the exit portal, and the if the object enters from the bottom of the portal it will exit the bottom of the other portal.所以如果球进入传送门的顶部,物体会从传送门的顶部出来,如果物体从传送门的底部进入,它就会离开另一个传送门的底部。 I'm not the best a illustration, but here's what I want to it do:我不是最好的插图,但这是我想要做的: 在此处输入图片说明 Here you can see in both images the object enters the blue portal and exits the orange at the point that it entered, so top to top, bottom to bottom.在这里,您可以在两个图像中看到对象进入蓝色门户并在它进入的点退出橙色,因此从上到下,从下到下。

I've actually gotten this to work fine, but now I need to do it again but this time, one of the portals needs to be horizontal instead of vertical:我实际上已经让它正常工作了,但现在我需要再做一次,但这一次,门户之一需要是水平的而不是垂直的: 在此处输入图片说明 So what I've done, is make it so when both a vertical, I leave a bool called "exitIsHorizontal" unchecked (false), and when one of them is on the ceiling on the level, it translates the vertical axis to a horizontal one.所以我所做的是,当两个都是垂直时,我不选中一个名为“exitIsHorizo​​ntal”的布尔值(假),当其中一个在水平面上的天花板上时,它将垂直轴转换为水平轴一。

I even sort of got that to work, however it's got a reproducible quark that needs to be fixed.我什至让它起作用了,但是它有一个需要修复的可复制夸克。 When the object enters the bottom of the portal, it works fine like you'd expect and just like the image above.当对象进入门户底部时,它会像您期望的那样正常工作,就像上图一样。 But when you hit the top of the portal, the object comes out the other side of the portal like you'd expect, but the object begins moving in the opposite direction as see in this image:但是,当您击中门户的顶部时,该对象会像您预期的那样从门户的另一侧出来,但该对象开始向相反的方向移动,如下图所示: 在此处输入图片说明 Correct exit location, wrong exit direction for some reason.正确的出口位置,由于某种原因错误的出口方向。 I also need this function to be dynamic so that if say, the object hit the blue portal from the other direction that the exit direction would switch sides as well like this:我还需要这个函数是动态的,这样如果说,对象从另一个方向击中蓝色门户,退出方向也会像这样切换边: 在此处输入图片说明

Here is my script:这是我的脚本:

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

    }

This script is attached to both portals so that both Portals can handle both entering and exiting.此脚本附加到两个门户,以便两个门户都可以处理进入和退出。 And any variable you don't see declared with anything in the script making it essentially null (such as "otherPotal") I declare the in editor.并且您没有看到在脚本中使用任何内容声明的任何变量使其基本上为空(例如“otherPotal”),我在编辑器中声明。

I'll bet it's something extremely simple that I just keep missing, I just don't know that something is.我敢打赌这是我一直想念的非常简单的东西,我只是不知道有些东西是。

So a portal is basically a wormhole.所以门户基本上是一个虫洞。 An object that enters will retain its local position and direction.进入的物体将保持其本地位置和方向。

虫洞

Functions:职能:

Unity has functions for transforming from world space to local space and vice versa. Unity 具有从世界空间转换到本地空间的功能,反之亦然。

Position:位置:

Transform.InverseTransformPoint Transform.InverseTransformPoint

Transforms position from world space to local space.将位置从世界空间转换为局部空间。

Transform.TransformPoint 变换.变换点

Transforms position from local space to world space.将位置从局部空间转换到世界空间。

跳跃

Direction:方向:

For transforming directions you will have to use:对于转换方向,您必须使用:

Transform.InverseTransformDirection Transform.InverseTransformDirection

Transforms a direction from world space to local space.将方向从世界空间转换为局部空间。 The opposite of Transform.TransformDirection.与 Transform.TransformDirection 相反。

Transform.TransformDirection 变换.变换方向

Transforms direction from local space to world space.将方向从局部空间转换到世界空间。

Simple Example:简单示例:

One script that you attach to both portals.您附加到两个门户的一个脚本。 It moves objects with the tag "Ball" over to the exitPortal .它将带有“Ball”标签的对象移动到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;
        }
    }
}

You get this:你得到这个:

乐趣

Complex Example:复杂示例:

You need 3 scripts for this to work:您需要 3 个脚本才能工作:

  • Portal: The thing that touches warpable objects传送门:接触可变形物体的东西
  • Warpable: A thing that travels through the portals Warpable:穿过传送门的东西
  • Ghost: A mirrored warpable that shows while going through a portal幽灵:通过门户时显示的镜像可变形

This is what the ghost looks like:鬼魂的样子是这样的:

鬼

You will need two additional layers – Portal and Ghost, with the collision matrix set as in the image.您将需要两个额外的层 - Portal 和 Ghost,碰撞矩阵设置为图像中。

矩阵

Scripts:脚本:

I've added enough comments within the code for you to make sense as to what it's doing.我在代码中添加了足够多的注释,让您了解它在做什么。

Portal:门户网站:

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

Warpable:可变形:

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

Ghost:鬼:

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

And the final result is this:最后的结果是这样的:

翘曲

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM