Search Unity

Bug Instantiated prefabs of the same type 'stick together', even when their transform.position is edited

Discussion in 'Scripting' started by Gwob, Mar 15, 2023.

  1. Gwob

    Gwob

    Joined:
    Mar 11, 2023
    Posts:
    1
    I'm making a slot machine. This is a 2D game that has 5 rollers. Each one has a preset layout as to how the objects should be configured. When the roller spins, all objects in the roller move downward, and when verticalDistanceBetweenObjects (the distance between two objects on the y axis) elapsed in downward movement, the bottom object is inserted at the front of the list, removed from the bottom, and the new reference to it, has its transform.position changed to physically be at the top of the roller within the scene.

    I previously had this functionality (and still do) in my first attempt at making this, however I did not like the structure of the code so I decided to rearrange it. Now, I'm certain it's much cleaner than before and should work better, but there's 2 huge problems (and maybe more that I'm yet to discover).

    The first problem, is that I can no longer instantiate the objects in the pattern that I once had them. Each item in the roller is instantiated and spaced our downwards on the y axis, to be a visual representation of the list of GameObjects. However when this is done, Prefabs of the same type, are stuck together in the scene (all piled on top of one another), and despite altering their transform.position property, the game objects still stick together. The instantiated prefabs that there are only one of appear to be in their respective positions, but all the prefabs of which there are multiple, are pilled up in one spot.

    To bring my objects into the scene, I set my layout of objects in an array, just by creating strings that correspond to the names of the prefabs of the objects, like this:

    Code (CSharp):
    1.     readonly string[] roller1Layout = new string[]
    2.     { "Orange", "Bell", "Melon", "Cherry", "Blueberry", "Lemon", "Blackberry", "Blueberry", "Bell", "Bell", "Orange", "Blackberry", "Lemon", "Lemon", "Empty" };
    I then use this method to bring them into the scene:

    Code (CSharp):
    1. List<GameObject> InstantiatePrefabFromArray(string[] layout)
    2.     {
    3.         List<GameObject> listToReturn = new List<GameObject>();
    4.         foreach (string value in layout)
    5.         {
    6.             switch (value)
    7.             {
    8.                 case "Bell":
    9.                     Instantiate(bell);
    10.                     listToReturn.Add(bell);
    11.                     break;
    12.                 case "Orange":
    13.                     Instantiate(orange);
    14.                     listToReturn.Add(orange);
    15.                     break;
    16.                 case "Blueberry":
    17.                     Instantiate(blueberry);
    18.                     listToReturn.Add(blueberry);
    19.                     break;
    20.                 case "Cherry":
    21.                     Instantiate(cherry);
    22.                     listToReturn.Add(cherry);
    23.                     break;
    24.                 case "Lemon":
    25.                     Instantiate(lemon);
    26.                     listToReturn.Add(lemon);
    27.                     break;
    28.                 case "Melon":
    29.                     Instantiate(melon);
    30.                     listToReturn.Add(melon);
    31.                     break;
    32.                 case "Blackberry":
    33.                     Instantiate(blackberry);
    34.                     listToReturn.Add(blackberry);
    35.                     break;
    36.                 case "Empty":
    37.                     Instantiate(empty);
    38.                     listToReturn.Add(empty);
    39.                     break;
    40.             }
    41.         }
    42.         return listToReturn;
    43.     }
    And this works. So, after having done this, I naturally need to set the position, so I then do this (instantiatedRewards = InstantiatePrefabFromArray(roller1) for example):

    Code (CSharp):
    1. for (int i = 0; i < instantiatedRewards.Count; i++)
    2.         {
    3.             instantiatedRewards[i].transform.position = new Vector3(xStartingPosition + (xToIncrementBy * xMultiplier), yStartingPosition - verticalDistanceBetweenObjects * i, -1);
    4.             if (rollerName == "Roller1")
    5.             {
    6.                 Debug.Log(instantiatedRewards[i].name + " " + i);
    7.                 Debug.Log(instantiatedRewards[i].transform.position);
    8.             }
    9.         }
    These are the values of the involved numbers:

    Code (CSharp):
    1. private const float verticalDistanceBetweenObjects = 2.49f;
    2.     private const float xStartingPosition = -6;
    3.     private const float yStartingPosition = 3.43f;
    xMultiplier is set in another method. If (rollerName = "Roller1") {xMultuiplier = 0}, going up 1 each roller along.

    So what happens here is that each object along in the list is instantiated 2.49 down on the y axis. And that almost happens, but it doesn't really. The x axis is, at least, (mostly) always correct (sometimes it takes some weird liberties). But the y axis is, only partially correct. In my working version before, they would instantiate in their correct positions (I previously set these with a List<Vector3> that had a certain configuration of absolute positions for each roller, I'm sure you can see why I wanted to change this).

    What's more is that, the debug information, tells me that the objects are in the places I want them to be, which is a flat out lie. They are absolutely not there in the scene. I cannot wrap my head around why this is the case. The editor is telling me that the objects are in a place that they visibly are not.



    That's my first of 2 problems (that I know of so far). My second, is that my coroutines to move my objects no longer work. The objects within the scene now no longer react to them whatsoever.

    This is them (I was about to refactor them, but haven't got around to it yet):

    Code (CSharp):
    1. //this coroutine will spin the roller for 5 seconds
    2.     IEnumerator SpinRoller()
    3.     {
    4.         for (float timeElapsed = 0; timeElapsed < spinTimeLimit; timeElapsed += calculatedTickLimit)
    5.         {
    6.             foreach (GameObject rewardItem in instantiatedRewards)
    7.             {
    8.                 StartCoroutine(MoveObject(rewardItem));
    9.             }
    10.             yield return new WaitForSeconds(calculatedTickLimit);
    11.             MoveRoller();
    12.         }
    13.     }
    14.  
    15.  
    16.     //this coroutine will move the parent object downwards, and will place the bottom object at the top
    17.     IEnumerator MoveObject(GameObject rewardItem)
    18.     {
    19.         for (float distanceToMove = verticalDistanceBetweenObjects; distanceToMove >= 0; distanceToMove -= 1f)
    20.         {
    21.             if (rewardItem != null)
    22.             {
    23.                 rewardItem.transform.Translate(0, -1f, 0);
    24.             }
    25.             yield return new WaitForSeconds(calculatedTickLimit / verticalDistanceBetweenObjects);
    26.         }
    27.     }
    28.  
    29.  
    30.     void MoveRoller()
    31.     {
    32.         // Move the last item to the top
    33.         GameObject lastItem = instantiatedRewards[instantiatedRewards.Count - 1];
    34.         instantiatedRewards.RemoveAt(instantiatedRewards.Count - 1);
    35.         instantiatedRewards.Insert(0, lastItem);
    36.  
    37.         // Set the position of the first item relative to the second item
    38.         instantiatedRewards[0].transform.position = instantiatedRewards[1].transform.position + new Vector3(0, verticalDistanceBetweenObjects, 0);
    39.     }
    This previously, would move the roller for a predetermined random amount of time, to give a random 3 objects showing at the top of the slot machine (in the visible part of the roller within the interface). Now they no longer move at all.



    Both the functional project, and this one were made in 2022.2.7f1, in the 2DURP. I'm kind of pulling my hair out here and am hoping someone can be my salvation to show me where I'm going wrong.

    If you have any ideas let me know. Thanks!