2D Portal only working sometimes in Unity

Viewed 347

I'm trying to make a 2D portal in Unity that doesn't just transport the player to the other portal gameobject. But keeps the players position and movements direction and velocity after going through the portal.

I'm be no means an artist, but for example: enter image description here The player is a ball bouncing around an area, when he does through the portal his velocity is maintained, along with the fact that he entered he center of the portal.

Where here for example: enter image description here If the player enters the bottom half of the portal, he will come out the bottom half of the portal.

When this works, it works great! However, it only works 50% of the time, that 50% can have a bunch of different issues though, sometimes the ball will just not teleport. Sometimes the ball hits the first portal, teleports to the second portal, then back to the first portal, and it does this repeatedly forever. And it experiences these issues seemingly at random.

Here is my Script:

public GameObject otherPortal;
    public PortalController otherPortalScript;
    private BallController ballController;
    public float waitTime = 0.5f;

    [HideInInspector]
    public bool teleporting;

    // 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(!teleporting)
            {
                var offset = other.transform.position - transform.position;
                offset.x = 0;
                other.transform.position = otherPortal.transform.position + offset;
                otherPortalScript.teleporting = true;
                teleporting = true;
                StartCoroutine("Teleport");
            }            
        }
    }

    void OnTriggerExit2D(Collider2D other)
    {
        if (other.gameObject.tag == "Ball")
        {
            teleporting = false;
            otherPortalScript.teleporting = false;
        }

    }

    IEnumerator Teleport()
    {
        yield return new WaitForSeconds(waitTime);
        teleporting = false;
        otherPortalScript.teleporting = false;
        ballController.teleporting = false;
    }
}

The script is attached to both portals, which are both prefabs of the same object. I set both "otherPortal", "otherPortalScript", & "waitTime" in the editor. "waitTime is something I had" to add after the fact to fix another issue I was having where sometimes "teleporting" never got set to false, I believe the the cause of the that problem is the same cause of this problem, making "waitTime" just a bandage for a larger issue. Also, anytime the Portal Script changes a variable in "ballController" such as "ballController.teleporting = false;", it's only there because the ball is add/removing points from a score system, it doesn't at all affect the ball's movement.

1 Answers

Consider getting rid of the teleporting property of the portals and the ball as well as the waitTime.

Now give the ball a List<PortalController> inUseControllers (note you need to add using System.Collections.Generic). Whenever it collision-enters one portal, check if the list is empty via inUseControllers.Count == 0, and if so, add both involved PortalController's to that list and handle the teleporting movement. When the ball collision-exits a PortalController, remove it from the inUseControllers list; it will thus only be emptied again once the ball leaves every portal zone.

This approach should simplify the code, yet safely protect against accidental back-and-forth circles.

Related