-1

I'm trying to create a minigame where I have the picture below, sliced into 32 pieces.

enter image description here

On Play/Start all the pieces are rotated randomly in multiplications of 90. From 0 -> [90,180,270].
The goal of the game is to rotate all the pieces to 0 Z-Axis Rotation, then a UI will pop up stating that you win.

The game plays as I expected it to, up to the point of the last 1-3 pieces, where even their rotation is not 0, the UI triggers and the game ends.
Example below, see piece top-right above the UI text.
enter image description here
GameControllerSlice Script

    public class GameControllerSlice : MonoBehaviour
{
    [SerializeField]
    private GameObject[] PicturePieces;
    [SerializeField]
    private GameObject winText;
    [SerializeField]
    private GameObject winTextBackground;

    public static bool youWin = false;
    private readonly int[] randomZ = new int[] {90, 180, 270};
    private int randomIndex;

    void Start()
    {
        Randomizer();
        winText.SetActive(false);
        winTextBackground.SetActive(false);
    }

    void Update()
    {
        RotationCheck();
    }

    //Randomizes the rotation of the Z-axis value.
    private void Randomizer()
    {
        for (int i = 0; i < 4; i++)
        {
            randomIndex = Random.Range(1, randomZ.Length - 1);
            PicturePieces[i].transform.Rotate(0, 0, randomZ[randomIndex]);
        }
    }

    //Checks if the rotation of each pieces is 0.
    private void RotationCheck()
    {
        if (Pictures.All(pic => (int) pic.transform.rotation.z == 0f))
        {
            youWin = true;
            winText.SetActive(true);
            winTextBackground.SetActive(true);
        }
    }
}

On each individual piece I have a the script with the simple code below.
TouchRotate Script

public class TouchRotate : MonoBehaviour
{
    private void OnMouseDown()
    {
     if (!GameControllerSlice.youWin)
     {
        transform.Rotate(0f, 0f, -90);
     }
    }
}

I've spend the past 3 days doing trial & error, with no success.
Also tried a different approach shown below, but that gave me a whole other problem, because I can't read/update the index properly from TouchRotate back into the GameControllerSlice script.
Excuse some leftover comments I was trying different things.

public class GameControllerSlice : MonoBehaviour
{
    [SerializeField]
    private GameObject[] PicturePieces;
    [SerializeField]
    private GameObject winText;
    [SerializeField]
    private GameObject winTextBackground;

    public static bool youWin = false;
    public static int[] RandomizedPics = new int[32];
    private readonly int[] randomZ = new int[] {0, 90, 180, 270};
    private int randomIndex;

    void Start()
    {
        FillRandomList();
        Randomizer();
        winText.SetActive(false);
        winTextBackground.SetActive(false);
    }

    void Update()
    {
        RotationCheck();
    }

    public void FillRandomList()
    {
        foreach (int i in RandomizedPics)
        {
            RandomizedPics[i] = randomZ[0];
            // Debug.Log("Value " + RandomizedPics[i]);
        }
    }

    //Randomizes the rotation of the Z-axis value.
    private void Randomizer()
    {
        for (int i = 0; i < 4; i++)
        {
            randomIndex = Random.Range(1, randomZ.Length - 1);
            PicturePieces[i].transform.Rotate(0, 0, randomZ[randomIndex]);
            RandomizedPics[i] = randomIndex;
        }
    }

    //Checks if the rotation of each pieces is 0.
    private void RotationCheck()
    {
        for (int i =0; i < 32; i++)
        {
            if (RandomizedPics[i] != 0)
            {
                Debug.Log("Picture " + PicturePieces[i] + "value " + RandomizedPics[i]);
            }
        }
    }
}

public class TouchRotate : MonoBehaviour
{
    private void OnMouseDown()
    {
        //if (!GameControllerSlice.youWin)
        transform.Rotate(0f, 0f, -90);
        //Debug.Log("Clicked Pic " + name + "with value " + System.Array.IndexOf(gameController.Pictures, this));
        // Debug.Log(System.Array.IndexOf(gameController.Picturesgo, this.transform.gameObject));
    }
}

Appreciate any help or pointers to the right direction for either approach.
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86

1 Answers1

1

First of all due to floating point imprecision you never want to rely on ==/!= for float values!

You rather want to check within a certain range

if(Mathf.Abs(x - 0f) <= threshold)

e.g. using Mathf.Aproximately

if(Mathf.Approximately(x, 0f))

which basically equals using

if(Mathf.Abs(x - 0f) <= Mathf.Epsilon)

where Mathf.Epsilon is the smallest value two floats can differ.


And then Transform.rotation is a Quaternion which doesn't have 3 but 4 components x,y,z,w and they all move in ranges -1 to 1.

Never access/set those values directly unless you know exactly what you are doing.

(int) pic.transform.rotation.z

is not what you want to check for.


Either check on the Transform.localEulerAngles - I would use local space since Transform.Rotate is also applied in local space by default which might just be an additional issue in your case since you check the global rotation

if(Mathf.Approximately(pic.transform.localEulerAngles.z, 0))

or in general to not have to deal with rotations and Euler angles issues I usually would rather just go vector math wise and use this little "trick"

if(pic.transform.up == Vector3.up)

which already uses a reduced precision of 0.00001. This is way less error prone and simply compares the two up vectors.

Or if you want a little less precision e.g. if later the user can actually rotate these freely I would go for Vector3.Angle

if(Vector3.Angle(pic.transform.up, Vector3.up) <= thresholdAngle) 

Oh and a final note:

randomIndex = Random.Range(1, randomZ.Length - 1);

will always return 1 -> 180.

Arrays are indexed 0-based and for int the Random.Range returns values between min and max - 1.

You probably rather wanted

randomIndex = Random.Range(0, randomZ.Length);

in order to pick any of the available options ;)

derHugo
  • 83,094
  • 9
  • 75
  • 115
  • WoW, you are a life saver! The Vector3.up worked perfectly. I had figured out that I should not mess with Quaternions and float checks, that's why I tried the index approach, but in the end I just made a bigger mess for myself. Thank you for your detailed explanation. Lesson learned! – Christos Fotos Feb 04 '22 at 10:15
  • @ChristosFotos just added a little update at the very bottom ;) – derHugo Feb 04 '22 at 10:19
  • Saw it right after, I edited my response. Thanks for that one too, I missed it. Once again thanks for the quick, detailed and comprehensive response. Learned a lot. – Christos Fotos Feb 04 '22 at 10:26