Saving the rest state of physics Simulation (To a new scene?)

I got bored and started to play around with physics2d.

But I’d like to be able to save starting from my initial level design to a new scene once everything is stabilized.

So I started out like this

6358998--707466--Start.png

and would like to save my scene (preferable in a new scene file) like this

so I can build on the result and build further on stable levels?

Is there a way to do this.

I would probably make a script that waits 5 seconds (or however long it takes to stabilize), then prints the transform data of the relevant objects out to a file. Then load that data back into the scene with an editor script.

1 Like

I have never used this API, but I think you can take Praetor’s great idea above and collapse it down into one single frame by calling this function:

You could stick one of those in during a Start() function and I think it will “pump” all your physics for however long you tell it to.

2 Likes

I might have gone about this completely the wrong way… instead of trying to save a scene in game mode, I should have simulated the physics in editor mode.

Unfortunately, for tonight I need to go to bed as I have work tomorrow but I will let you know in the following days how it goes. When I solve this I will let you all know.

1 Like

As I have promised I would post, when I had a descend answer

It is an adaptation of Activate physics in Edit mode to dynamically drop or settle objects in a scene · GitHub for 2D Physics.

What It does:

  • It creates a UI window with a button “start” and “stop”.
  • Runs the animation for 10 secs in the editor
  • Can be interrupted

Things it doesn’t do, (possible extensions for me)

  • Freeze objects before start
  • Stop objects from being updated anymore
  • Exclude objects from activating even when hit.
  • Anything else where you want to interfere.

Any questions can be sent to napivo@gmail.com or posted here

using UnityEngine;
using UnityEditor;
using System.Linq;
using UnityEngine.UIElements;
using System;

// This causes the class' static constructor to be called on load and on starting playmode
[InitializeOnLoad]
class PhysicsSettler : EditorWindow
{
    private static GUIStyle SLblRed;
    private static GUIStyle SLblBlue;

    private static int activeCount = 0;
    private static bool active = false;
    private static float activeTime = 0;
    private static float timeToSettle = 10;

    //// the work list of rigid bodies we can find loaded up
    static Rigidbody2D[] workList;
    static Color[] workListOriginalColors;

    //// we need to disable auto simulation to manually tick physics
    static bool cachedAutoSimulation;

    private void OnGUI()
    {
        if (active)
        {
            if (GUILayout.Button("Stop Physics"))
            {
                Deactivate();
            }
        }
        else
        {
            if (GUILayout.Button("Run Physics"))
            {
                Activate();
            }
        }


        if (active)
        {
            GUILayout.Space(5);
            GUILayout.Label("Working " , SLblBlue);
            GUILayout.Space(2);
            GUILayout.Label("Active Objects : " + activeCount, SLblRed);
            GUILayout.Space(5);
        }
        else
        {

            GUILayout.Space(5);
            GUILayout.Label("Stopped ", SLblBlue);
            GUILayout.Space(2);
            GUILayout.Label("Active Objects : " + activeCount, SLblRed);
            GUILayout.Space(5);
        }
    }

    void Deactivate()
    {
        active = false;
        int count = 0;
        foreach (Rigidbody2D body in workList)
        {
            body.gameObject.GetComponent<SpriteRenderer>().color = workListOriginalColors[count];
            count++;
        }

        // !!!Extremely needed!!!
        // If not executed will stop Physics in game mode

        Physics2D.autoSimulation = true;
    }

    void Activate()
    {
        SLblRed = new GUIStyle(EditorStyles.label);
        SLblRed.normal.textColor = Color.red;

        SLblBlue = new GUIStyle(EditorStyles.label);
        SLblBlue.normal.textColor = Color.blue;


        if (!active)
        {
            active = true;

            // Normally avoid Find functions, but this is editor time and only happens once
            workList = GameObject.FindObjectsOfType<Rigidbody2D>();
            workListOriginalColors = new Color[workList.Count()];

            // we will need to ensure autoSimulation is off to manually tick physics
            cachedAutoSimulation = Physics.autoSimulation;
            activeTime = 0f;

            Debug.Log("Bodies found = " + workList.Count());

            int count = 0;
            // make sure that all rigidbodies are awake so they will actively settle against changed geometry.
            foreach (Rigidbody2D body in workList)
            {
                workListOriginalColors[count] = body.gameObject.GetComponent<SpriteRenderer>().color;
                count++;

                if (DoWakeUp(body))
                {
                    body.Sleep();
                }
                else
                {
                    body.WakeUp();
                }
            }
        }
    }

    private static bool DoWakeUp(Rigidbody2D body)
    {
        // you can add code to decide if a body needs to be awake or asleep at start

        return body.bodyType == RigidbodyType2D.Kinematic;
    }

    void Update()
    {  
        if (active)
        {
            Debug.Log("Update Active");
            activeTime += Time.deltaTime;
            Debug.Log("activeTime = " + activeTime);
           
            // make sure we are not autosimulating
           
            /*
             !!!!!!!!!!!!
             Be carefull Physics2D.autoSimulation = true
             Must be execured or Physics will be diabled in game mode
             !!!!!!!!!!!
            */

            Physics2D.autoSimulation = false;

            // see if all our
            bool allSleeping = true;
            activeCount = 0;

            foreach (Rigidbody2D body in workList)
            {
                SpriteRenderer sr = body.gameObject.GetComponent<SpriteRenderer>();
                sr.color = Color.green;

                if ((body != null) && (body.bodyType != RigidbodyType2D.Kinematic))
                {
                    if (!body.IsSleeping())
                    {
                        allSleeping = false;
                        activeCount++;
                        sr.color = Color.red;
                        //Debug.Log("Body = " + body.gameObject.name);
                    }
                }
            }

            Debug.Log("Active : " + active);

            if (allSleeping || activeTime >= timeToSettle)
            {
                Physics2D.autoSimulation = cachedAutoSimulation;
                Deactivate();

                if (allSleeping)
                {
                    Debug.Log("All Alseep ending");
                }

                if (activeTime >= timeToSettle)
                {
                    Debug.Log("Active time elapsed ending");
                }
            }
            else
            {
                SaveObjectdata();
                Physics2D.Simulate(Time.fixedDeltaTime);
                CheckObjectdata();
                //Physics2D.autoSimulation = true;
            }
        }
    }

    private void SaveObjectdata()
    {
        // Will save all data needed to check if object will remain active


        //throw new NotImplementedException();
    }

    private void CheckObjectdata()
    {
        // Will check all data to check if object will remain active or fall asleep.

        //throw new NotImplementedException();
    }

    [MenuItem("Tools/Scene Physics")]
    private static void OpenWindow()
    {
        GetWindow<PhysicsSettler>(false, "Physics", true);
    }
}
1 Like