Environment reset on episodebegin.

Hi everyone, i’m working on a self driving car, and i’m having troubles with the environment reset.

I’ve always kept my simulation quite small, so i’ve been able to easily store position and rotation of every object and use them for the reset.
now the scene is full of stuff, tires barriers, barrels, street cones and so on.
needless to say that after every episode, there’s ton of stuff scattered around.

is there a more efficient way of putting everything back in place, than storing every single object pos and rot?

also, i don’t like to use “search by tag”, because if i make multiple training areas in the same scene, they will then interfere with each other.

You can try a recursive approach.

using UnityEngine;
using System.Collections.Generic;

namespace MBaske
{
    public class ResettableItem
    {
        private Transform tf;
        private Vector3 pos;
        private Quaternion rot;
        private Rigidbody rb;

        public ResettableItem(Transform tf)
        {
            this.tf = tf;
            pos = tf.localPosition;
            rot = tf.localRotation;
            rb = tf.GetComponent<Rigidbody>();
        }

        public void Reset()
        {
            if (rb != null)
            {
                rb.velocity = Vector3.zero;
                rb.angularVelocity = Vector3.zero;
                rb.Sleep();
            }

            tf.localPosition = pos;
            tf.localRotation = rot;
        }
    }

    public class Resetter
    {
        private List<ResettableItem> items;

        public Resetter(Transform tf)
        {
            items = new List<ResettableItem>();
            Add(tf);
        }

        public void Reset()
        {
            foreach (ResettableItem item in items)
            {
                item.Reset();
            }
        }

        private void Add(Transform tf)
        {
            items.Add(new ResettableItem(tf));

            for (int i = 0; i < tf.childCount; i++)
            {
                Add(tf.GetChild(i));
            }
        }
    }
}

Create a resetter field:
Resetter resetter;
On initialize you would call:
resetter = new Resetter(environment_transform);
On reset, call:
resetter.Reset();

3 Likes

Wow ty i’ll try that immediately

works like a charm, the only problem is that lots of obstacles have a fixed joint linked to the ground. on impact, the joint component doesn’t get deactivated, but it gets removed from the gameObject.
So now i have to find a way to identify which of them needs a fixed joint, add it on reset, and link it to the ground :frowning:

Should be easy to add to ResettableItem. Something like this (haven’t tested it).

...
private Rigidbody connected;

public ResettableItem(Transform tf)
{
    this.tf = tf;
    pos = tf.localPosition;
    rot = tf.localRotation;
    rb = tf.GetComponent<Rigidbody>();

    var joint = tf.GetComponent<FixedJoint>();
    if (joint != null)
    {
        connected = joint.connectedBody;
    }
}

public void Reset()
{
    if (rb != null)
    {
        rb.velocity = Vector3.zero;
        rb.angularVelocity = Vector3.zero;
        rb.Sleep();
    }

    tf.localPosition = pos;
    tf.localRotation = rot;

    if (connected != null)
    {
        var joint = tf.gameObject.AddComponent<FixedJoint>() as FixedJoint;
        joint.connectedBody = connected;
    }
}
...

EDIT: Probably should check in Reset() if the old joint still exists, before adding a new one.

...
if (connected != null)
    {
        var joint = tf.GetComponent<FixedJoint>();
        if (joint == null)
        {
            joint = tf.gameObject.AddComponent<FixedJoint>() as FixedJoint;
            joint.connectedBody = connected;
        }
    }
...

thanks again, and yes, i need to check first if the joint has been detached to avoid adding duplicates.

ok, so i’ve tinkered a bit with the code because i’m a noob and i was getting too many errors using List , so i switched to List.

when i try to set the fixedJoint breakforce, i get a pretty weird behavior.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ResettableItem : MonoBehaviour
{
        private Vector3 pos;
        private Quaternion rot;
        private Rigidbody rb;
        private Rigidbody connected;
        public float connectionStrenght;


        public void Awake(){
            pos = transform.position;
            rot = transform.rotation;
            rb = GetComponent<Rigidbody>();

            var joint = GetComponent<FixedJoint>();
            if (joint != null)
            {
                connected = joint.connectedBody;
                connectionStrenght = joint.breakForce;
                Debug.Log(joint.breakForce);
            }

        }
        public void Reset()
        {
            gameObject.SetActive(true);

            if (rb != null)
            {
                rb.velocity = Vector3.zero;
                rb.angularVelocity = Vector3.zero;
                rb.Sleep();
            }
            transform.position = pos;
            transform.rotation = rot;     

            if (connected != null)
            {
                var joint = GetComponent<FixedJoint>();
                if (joint == null)
                {
                    joint = gameObject.AddComponent<FixedJoint>() as FixedJoint;
                    joint.breakForce = connectionStrenght;
                    joint.connectedBody = connected;
                   
                }
            }       
           
        }
    }

position, rotation and rigidbody work as intended, but the joint doesn’t appear to be applied. If i remove, the line:
joint.breakForce = connectionStrenght;
the joint gets created, connected to the environment with a default breakForce/torqueForce = infinity

tooltip says Joint.breakForce{ get; set; } but i don’t know what does that mean.

i’ve searched online but i haven’t been able to figure out how to set the breakforce of a joint via script