Reset multiple Child Gameobjects position,rotation

I have searched online for solutions to this and have found similar questions but not quite the same for my application and so I will post here.

I have an empty parent object called bookstack that has 5 child objects which are various books. Each individual book has a box collider and rigidbody.

I want to write one script attached to the parent object ( bookstack) which will reset each of the individual child book gameobjects to their initial position and rotation.

At the start, I am trying to create an array of the child book objects and a list of their initial transforms. Then later when I want to reset them, I want to take each child book gameobject and assign it to its transform stored earlier. I am stuck on how to iterate through the list of transforms while simultaneously iterating through the array of gameobjects with the foreach loop, ie. move to the next index of the List when the foreach loop iterates, so that the 1st gameobject is assigned the first transform stored earlier, 2nd GO gets the 2nd transform, etc.

public class bookStack : MonoBehaviour
{
  
    List<Transform> initialBookTransform = new List<Transform>();
  
    void Start()
    {
        foreach(GameObject child in GameObject.FindGameObjectsWithTag("bookStack"))
        {
            //set all the child books to be stationary
            child.GetComponent<Rigidbody>().velocity = Vector3.zero;
            child.GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
            //store the initial transform of the individual books
            initialBookTransform.Add(child.GetComponent<Transform>());
        }
    }

    public void resetBook()
    {
        int i = 0;

        foreach(GameObject child in GameObject.FindGameObjectsWithTag("bookStack"))
        { 
            //set all the child books to be stationary
            child.GetComponent<Rigidbody>().velocity = Vector3.zero;
            child.GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
            //set the current child book object transform to equate to the initially stored transforms
            child.transform.position = initialBookTransform[i].position;
            child.transform.rotation = initialBookTransform[i].rotation;
            i++;
        }
    }
}

Any help on how to accomplish this would be greatly appreciated!

Relying on the ordering returned by FindGameObjectsWithTag is not a good idea. It;'s not guaranteed to be the same. instead, store the initial positions and rotations in a dictionary. That way you can look up exactly which one it was, without worrying about positions in an array etc…

Another problem you have is that you’re referencing the actual transforms of the objects within your array, so reading the position and rotation in resetBook will simply give you the current position and rotation… not the initial one.

So let’s create a struct to store the data:

    struct PositionAndRotation {
        public Vector3 position;
        public Quaternion rotation;
    }

And then to save and reset it:

        Dictionary<Transform, PositionAndRotation> initialPositions = new Dictionary<Transform, PositionAndRotation>();

        void Start() {
            foreach (GameObject stack in GameObject.FindGameObjectsWithTag("bookStack")) {
                //set all the books to be stationary
                var rb = stack.GetComponent<Rigidbody>();
                rb.velocity = Vector3.zero;
                rb.angularVelocity = Vector3.zero;

                //store the initial transform of the individual books
                PositionAndRotation pandr;
                pandr.position = stack.transform.position;
                pandr.rotation = stack.transform.rotation;
                initialPositions[stack.transform] = pandr;
            }
        }

        void ResetBooks() {
            foreach (var pair in initialPositions) {
                Transform t = pair.Key;
                t.position = pair.Value.position;
                t.rotation = pair.Value.rotation;
                var rb = t.GetComponent<Rigidbody>();
                rb.velocity = Vector3.zero;
                rb.angularVelocity = Vector3.zero;
            }
        }
2 Likes

Thank you very much! I’ve implemented and initially tested this and it seems to work perfectly. Although I don’t totally follow how this actually works to set the current position and rotation to the initial.

  • One minor correction, in case others reference this code in the future, is that Line 7 should be:

var rb = stack.GetComponent();

Thanks again for your help, I really appreciate it.