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

Jho*_*per 6 c# unity-game-engine

在我开始之前,如果这不是高度专业的写法,我想说声抱歉,我一直在努力解决这个问题好几个小时,试图在没有运气的情况下解决这个问题,我很累而且压力很大。

我试图让一个移动的物体在特定点通过 1 个门户进入,并在它进入的同一点从另一个门户出来。所以如果球进入传送门的顶部,物体会从传送门的顶部出来,如果物体从传送门的底部进入,它就会离开另一个传送门的底部。我不是最好的插图,但这是我想要做的: 在此处输入图片说明 在这里,您可以在两个图像中看到对象进入蓝色门户并在它进入的点退出橙色,因此从上到下,从下到下。

我实际上已经让它正常工作了,但现在我需要再做一次,但这一次,门户之一需要是水平的而不是垂直的: 在此处输入图片说明 所以我所做的是,当两个都是垂直时,我不选中一个名为“exitIsHorizo​​ntal”的布尔值(假),当其中一个在水平面上的天花板上时,它将垂直轴转换为水平轴一。

我什至让它起作用了,但是它有一个需要修复的可复制夸克。当对象进入门户底部时,它会像您期望的那样正常工作,就像上图一样。但是,当您击中门户的顶部时,该对象会像您预期的那样从门户的另一侧出来,但该对象开始向相反的方向移动,如下图所示: 在此处输入图片说明 正确的出口位置,由于某种原因错误的出口方向。我还需要这个函数是动态的,这样如果说,对象从另一个方向击中蓝色门户,退出方向也会像这样切换边: 在此处输入图片说明

这是我的脚本:

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

    }
Run Code Online (Sandbox Code Playgroud)

此脚本附加到两个门户,以便两个门户都可以处理进入和退出。并且您没有看到在脚本中使用任何内容声明的任何变量使其基本上为空(例如“otherPotal”),我在编辑器中声明。

我敢打赌这是我一直想念的非常简单的东西,我只是不知道有些东西是。

Igg*_*ggy 3

所以门户网站基本上就是一个虫洞。进入的物体将保留其本地位置和方向。

\n\n

虫洞

\n\n

功能:

\n\n

Unity 具有从世界空间转换到本地空间的功能,反之亦然。

\n\n

位置:

\n\n

Transform.InverseTransformPoint

\n\n
\n

将位置从世界空间变换到局部空间。

\n
\n\n

变换.变换点

\n\n
\n

将位置从局部空间变换到世界空间。

\n
\n\n

跳跃

\n\n

方向:

\n\n

要转换方向,您必须使用:

\n\n

Transform.InverseTransformDirection

\n\n
\n

将方向从世界空间转换为局部空间。与 Transform.TransformDirection 相反。

\n
\n\n

Transform.TransformDirection

\n\n
\n

将方向从局部空间转换为世界空间。

\n
\n\n

简单示例:

\n\n

您附加到两个门户的一个脚本。它将带有标签“Ball”的对象移动到exitPortal.

\n\n
public class Portal : MonoBehaviour\n{\n    [SerializeField] Portal exitPortal;\n\n    void OnTriggerEnter2D(Collider2D collider)\n    {\n        if (collider.CompareTag("Ball"))\n        {\n            GameObject ball = collider.gameObject;\n            Rigidbody2D rigidbody = ball.GetComponent<Rigidbody2D>();\n\n            Vector3 inPosition = this.transform.InverseTransformPoint(ball.transform.position);\n            inPosition.x = -inPosition.x;\n            Vector3 outPosition = exitPortal.transform.TransformPoint(inPosition);            \n\n            Vector3 inDirection = this.transform.InverseTransformDirection(rigidbody.velocity);\n            Vector3 outDirection = exitPortal.transform.TransformDirection(inDirection);\n\n            ball.transform.position = outPosition;\n            rigidbody.velocity = -outDirection;\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

你得到这个:

\n\n

乐趣

\n\n

复杂示例:

\n\n

您需要 3 个脚本才能实现此功能:

\n\n
    \n
  • Portal:接触可变形物体的东西
  • \n
  • 可变形:通过传送门传播的东西
  • \n
  • 幽灵:通过传送门时显示的镜像扭曲
  • \n
\n\n

鬼魂的样子是这样的:

\n\n

鬼

\n\n

您将需要两个额外的层 \xe2\x80\x93 Portal 和 Ghost,其碰撞矩阵设置如图所示。

\n\n

矩阵

\n\n

脚本:

\n\n

我在代码中添加了足够的注释,以便您了解它在做什么。

\n\n

门户网站:

\n\n
public class Portal : MonoBehaviour\n{\n    [SerializeField] Portal exitPortal;\n\n    void OnTriggerEnter2D(Collider2D collider)\n    {\n        // When a warpable enters a portal create a ghost\n        if (collider.TryGetComponent(out Warpable warpable))\n        {\n            // Create a ghost only if we haven\'t already\n            if (warpable.Ghost == null) warpable.CreateGhost(this, exitPortal);\n        }\n    }\n\n    void OnTriggerExit2D(Collider2D collider)\n    {\n        // When a warpable exist a portal; check if it has a ghost\n        if (collider.TryGetComponent(out Warpable warpable))\n        {\n            // Teleport to the ghost; apply its position, rotation, velocity\n            if (warpable.Ghost != null)\n            {\n                // Create vectors to compare dot product\n                Vector3 portalToWarpable = warpable.transform.position - this.transform.position;\n                Vector3 portalDownwards = -this.transform.up;\n\n                // If warpable is on the other side of the portal you get a value that\'s more than zero\n                float dot = Vector3.Dot(portalDownwards, portalToWarpable);\n                bool passedThroughPortal = dot >= 0f;\n\n                // If we passed through the portal then teleport to the ghost; otherwise just continue\n                if (passedThroughPortal)\n                {\n                    warpable.Position = warpable.Ghost.warpable.Position;\n                    warpable.Rotation = warpable.Ghost.warpable.Rotation;\n                    warpable.Velocity = warpable.Ghost.warpable.Velocity;\n                }\n\n                // Destroy the ghost\n                warpable.DestroyGhost();\n            }\n        }\n    }\n\n    void OnDrawGizmos()\n    {\n        Gizmos.color = Color.magenta;\n        Gizmos.DrawRay(this.transform.position, this.transform.up);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

可变形:

\n\n
public class Warpable : MonoBehaviour\n{\n    [SerializeField] new Rigidbody2D rigidbody;\n\n    public Ghost Ghost { get; private set; }\n\n    public void CreateGhost(Portal inPortal, Portal outPortal)\n    {\n        // 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.\n\n        // Ghost/Ghost      =   TRUE\n        // Ghost/Default    =   TRUE\n        // Ghost/Portal     =   FALSE\n\n        GameObject original = this.gameObject;\n        GameObject duplicate = GameObject.Instantiate(original);\n        duplicate.layer = LayerMask.NameToLayer("Ghost");\n\n        Physics2D.IgnoreCollision(\n            original.GetComponent<Collider2D>(),\n            duplicate.GetComponent<Collider2D>()\n        );\n\n        // Add the ghost component\n        Ghost = duplicate.AddComponent<Ghost>();\n\n        Ghost.observing = original.GetComponent<Warpable>();\n        Ghost.warpable = duplicate.GetComponent<Warpable>();\n\n        Ghost.inPortal = inPortal;\n        Ghost.outPortal = outPortal;\n    }\n\n    public void DestroyGhost()\n    {\n        GameObject.Destroy(Ghost.gameObject);\n        Ghost = null;\n    }\n\n    public Vector3 Position\n    {\n        get { return transform.position; }\n        set { transform.position = value; }\n    }\n\n    public Quaternion Rotation\n    {\n        get { return transform.rotation; }\n        set { transform.rotation = value; }\n    }\n\n    public Vector3 Velocity\n    {\n        get { return rigidbody.velocity; }\n        set { rigidbody.velocity = value; }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

鬼:

\n\n
public class Ghost : MonoBehaviour\n{\n    public Warpable observing;\n    public Warpable warpable;\n\n    public Portal inPortal;\n    public Portal outPortal;\n\n    void FixedUpdate()\n    {\n        warpable.Position = OutPosition(observing.Position);\n        warpable.Rotation = OutRotation(observing.Rotation);\n        warpable.Velocity = OutDirection(observing.Velocity);\n    }\n\n    Vector3 OutPosition(Vector3 position)\n    {\n        Vector3 inPosition = -inPortal.transform.InverseTransformPoint(position);\n        return outPortal.transform.TransformPoint(inPosition);\n    }\n\n    Quaternion OutRotation(Quaternion rotation)\n    {\n        return Quaternion.Inverse(inPortal.transform.rotation) * outPortal.transform.rotation * rotation;\n    }\n\n    Vector3 OutDirection(Vector3 velocity)\n    {\n        Vector3 inDirection = -inPortal.transform.InverseTransformDirection(velocity);\n        return outPortal.transform.TransformDirection(inDirection);\n    }\n\n    void OnDrawGizmos()\n    {\n        Gizmos.color = Color.cyan;\n        Gizmos.DrawWireSphere(warpable.Position, 1f);\n        Gizmos.DrawLine(warpable.Position, warpable.Position + warpable.Velocity);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

最终结果是这样的:

\n\n

翘曲

\n