Vector3 getNextWaterPush(int direction, Pushblock p)
    {
        Vector3 next = new Vector3(0, 0, 0);

        switch (direction)
        {
        case 270:
            next = new Vector3(p.transform.position.x + 2, p.transform.position.y, p.transform.position.z);
            break;

        case 180:
            next = new Vector3(p.transform.position.x, p.transform.position.y, p.transform.position.z - 2);
            break;

        case 90:
            next = new Vector3(p.transform.position.x - 2, p.transform.position.y, p.transform.position.z);
            break;

        case 0:
            next = new Vector3(p.transform.position.x, p.transform.position.y, p.transform.position.z + 2);
            break;
        }
        return(next);
    }
    void simulatePhysics()
    {
        //Find all Voidblocks - physics sometimes applies to things inside a void
        List <VoidManager> voidblocks = new List <VoidManager>();

        foreach (GameObject v in GameObject.FindGameObjectsWithTag("Void"))
        {
            if (v != null)
            {
                voidblocks.Add(v.GetComponent <VoidManager> ());
            }
        }

        //Pushblock physics
        List <Pushblock> pushables = new List <Pushblock>();

        foreach (GameObject x in GameObject.FindGameObjectsWithTag("Pushblock"))
        {
            if (x != null)
            {
                pushables.Add(x.GetComponent <Pushblock> ());
            }
        }

        foreach (Pushblock p in pushables)
        {
            Vector3 below = new Vector3(p.transform.position.x, p.transform.position.y - 2, p.transform.position.z);
            if (!SpawnTiles.tileExists(below))
            {
                SpawnTiles.blocks.Remove(SpawnTiles.roundVector(p.transform.position));
                p.transform.position = below;
                SpawnTiles.blocks.Add(below, p.gameObject);
            }
            if (p.transform.position.y < killPlane)
            {
                SpawnTiles.blocks.Remove(SpawnTiles.roundVector(p.transform.position));
                Destroy(p.gameObject);
            }
        }

        //Black Hole Physics
        List <GameObject> blackholes = new List <GameObject>();

        foreach (GameObject b in GameObject.FindGameObjectsWithTag("Blackhole"))
        {
            if (b != null)
            {
                blackholes.Add(b);
            }
        }

        foreach (GameObject b in blackholes)
        {
            Vector3 up      = b.transform.position + Vector3.up * 2;
            Vector3 down    = b.transform.position + Vector3.down * 2;
            Vector3 left    = b.transform.position + Vector3.left * 2;
            Vector3 right   = b.transform.position + Vector3.right * 2;
            Vector3 forward = b.transform.position + Vector3.forward * 2;
            Vector3 back    = b.transform.position + Vector3.back * 2;

            Vector3[] reachable = new Vector3[] { up, down, left, right, forward, back };

            foreach (Vector3 v in reachable)
            {
                if (SpawnTiles.tileExists(v))
                {
                    Destroy(SpawnTiles.blocks[v].gameObject);
                    SpawnTiles.blocks.Remove(v);
                }
            }
        }

        //Water physics
        List <WaterManager> waterblocks = new List <WaterManager>();

        foreach (GameObject w in GameObject.FindGameObjectsWithTag("Water"))
        {
            if (w != null)
            {
                waterblocks.Add(w.GetComponent <WaterManager> ());
            }
        }
        //add water blocks in voids
        foreach (VoidManager v in voidblocks)
        {
            foreach (GameObject g in v.getAllObjects())
            {
                if (g.GetComponent <WaterManager> () != null)
                {
                    waterblocks.Add(g.GetComponent <WaterManager>());
                }
            }
        }

        foreach (WaterManager wtr in waterblocks)
        {
            Vector3 below = new Vector3(wtr.transform.position.x, wtr.transform.position.y - 2, wtr.transform.position.z);
            Vector3 next  = getNextWater(wtr);

            //flow down
            if (!SpawnTiles.tileExists(below) && below.y > killPlane)
            {
                generateWater(wtr, below, false);
            }
            //flow to next tile if free and not void, and there is not water below
            else if (!SpawnTiles.tileExists(next) &&
                     SpawnTiles.tileExists(below) &&
                     SpawnTiles.blocks [SpawnTiles.roundVector(below)].GetComponent <WaterManager> () == null)
            {
                generateWater(wtr, next, false);
            }

            //flow into void block next
            else if (SpawnTiles.tileExists(next) && SpawnTiles.blocks [next].GetComponent <VoidManager> () != null)
            {
                SpawnTiles.blocks [next].GetComponent <VoidManager> ().addObject(generateWater(wtr, next, true));
            }
            //flow into void block below
            else if (SpawnTiles.tileExists(below) && SpawnTiles.blocks [below].GetComponent <VoidManager> () != null)
            {
                SpawnTiles.blocks [below].GetComponent <VoidManager> ().addObject(generateWater(wtr, below, true));
            }

            //push pushblock
            if (SpawnTiles.tileExists(next) &&
                SpawnTiles.blocks [SpawnTiles.roundVector(next)].GetComponent <Pushblock> () != null)
            {
                Pushblock p        = SpawnTiles.blocks [SpawnTiles.roundVector(next)].GetComponent <Pushblock> ();
                Vector3   nextNext = getNextWaterPush(wtr.getDirection(), p);

                if (!SpawnTiles.tileExists(nextNext))
                {
                    SpawnTiles.blocks.Remove(SpawnTiles.roundVector(p.transform.position));
                    p.transform.position = nextNext;
                    SpawnTiles.blocks.Add(p.transform.position, p.gameObject);
                }
            }

            //stop water if parent is destoryed
            if (!wtr.isSource() && wtr.getParent() == null)
            {
                SpawnTiles.blocks.Remove(SpawnTiles.roundVector(wtr.transform.position));
                Destroy(wtr.gameObject);
            }
        }
    }