Search Unity

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

Discussion in 'Scripting' started by Napivo, Sep 28, 2020.

  1. Napivo

    Napivo

    Joined:
    Feb 9, 2015
    Posts:
    39
    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

    Start.png

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

    Result.png


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

    Is there a way to do this.
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    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.
     
    Joe-Censored likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    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:

    https://docs.unity3d.com/ScriptReference/Physics2D.Simulate.html

    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.
     
    Joe-Censored and PraetorBlue like this.
  4. Napivo

    Napivo

    Joined:
    Feb 9, 2015
    Posts:
    39
    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.

    https://answers.unity.com/questions/158766/physics-in-scene-editor-mode.html

    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.
     
    PraetorBlue likes this.
  5. Napivo

    Napivo

    Joined:
    Feb 9, 2015
    Posts:
    39
    As I have promised I would post, when I had a descend answer

    It is an adaptation of https://gist.github.com/gekidoslair/aa9f9685b3ff4077c3209976635ecce8 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
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Linq;
    4. using UnityEngine.UIElements;
    5. using System;
    6.  
    7. // This causes the class' static constructor to be called on load and on starting playmode
    8. [InitializeOnLoad]
    9. class PhysicsSettler : EditorWindow
    10. {
    11.     private static GUIStyle SLblRed;
    12.     private static GUIStyle SLblBlue;
    13.  
    14.     private static int activeCount = 0;
    15.     private static bool active = false;
    16.     private static float activeTime = 0;
    17.     private static float timeToSettle = 10;
    18.  
    19.     //// the work list of rigid bodies we can find loaded up
    20.     static Rigidbody2D[] workList;
    21.     static Color[] workListOriginalColors;
    22.  
    23.     //// we need to disable auto simulation to manually tick physics
    24.     static bool cachedAutoSimulation;
    25.  
    26.     private void OnGUI()
    27.     {
    28.         if (active)
    29.         {
    30.             if (GUILayout.Button("Stop Physics"))
    31.             {
    32.                 Deactivate();
    33.             }
    34.         }
    35.         else
    36.         {
    37.             if (GUILayout.Button("Run Physics"))
    38.             {
    39.                 Activate();
    40.             }
    41.         }
    42.  
    43.  
    44.         if (active)
    45.         {
    46.             GUILayout.Space(5);
    47.             GUILayout.Label("Working " , SLblBlue);
    48.             GUILayout.Space(2);
    49.             GUILayout.Label("Active Objects : " + activeCount, SLblRed);
    50.             GUILayout.Space(5);
    51.         }
    52.         else
    53.         {
    54.  
    55.             GUILayout.Space(5);
    56.             GUILayout.Label("Stopped ", SLblBlue);
    57.             GUILayout.Space(2);
    58.             GUILayout.Label("Active Objects : " + activeCount, SLblRed);
    59.             GUILayout.Space(5);
    60.         }
    61.     }
    62.  
    63.     void Deactivate()
    64.     {
    65.         active = false;
    66.         int count = 0;
    67.         foreach (Rigidbody2D body in workList)
    68.         {
    69.             body.gameObject.GetComponent<SpriteRenderer>().color = workListOriginalColors[count];
    70.             count++;
    71.         }
    72.  
    73.         // !!!Extremely needed!!!
    74.         // If not executed will stop Physics in game mode
    75.  
    76.         Physics2D.autoSimulation = true;
    77.     }
    78.  
    79.     void Activate()
    80.     {
    81.         SLblRed = new GUIStyle(EditorStyles.label);
    82.         SLblRed.normal.textColor = Color.red;
    83.  
    84.         SLblBlue = new GUIStyle(EditorStyles.label);
    85.         SLblBlue.normal.textColor = Color.blue;
    86.  
    87.  
    88.         if (!active)
    89.         {
    90.             active = true;
    91.  
    92.             // Normally avoid Find functions, but this is editor time and only happens once
    93.             workList = GameObject.FindObjectsOfType<Rigidbody2D>();
    94.             workListOriginalColors = new Color[workList.Count()];
    95.  
    96.             // we will need to ensure autoSimulation is off to manually tick physics
    97.             cachedAutoSimulation = Physics.autoSimulation;
    98.             activeTime = 0f;
    99.  
    100.             Debug.Log("Bodies found = " + workList.Count());
    101.  
    102.             int count = 0;
    103.             // make sure that all rigidbodies are awake so they will actively settle against changed geometry.
    104.             foreach (Rigidbody2D body in workList)
    105.             {
    106.                 workListOriginalColors[count] = body.gameObject.GetComponent<SpriteRenderer>().color;
    107.                 count++;
    108.  
    109.                 if (DoWakeUp(body))
    110.                 {
    111.                     body.Sleep();
    112.                 }
    113.                 else
    114.                 {
    115.                     body.WakeUp();
    116.                 }
    117.             }
    118.         }
    119.     }
    120.  
    121.     private static bool DoWakeUp(Rigidbody2D body)
    122.     {
    123.         // you can add code to decide if a body needs to be awake or asleep at start
    124.  
    125.         return body.bodyType == RigidbodyType2D.Kinematic;
    126.     }
    127.  
    128.     void Update()
    129.     {  
    130.         if (active)
    131.         {
    132.             Debug.Log("Update Active");
    133.             activeTime += Time.deltaTime;
    134.             Debug.Log("activeTime = " + activeTime);
    135.            
    136.             // make sure we are not autosimulating
    137.            
    138.             /*
    139.              !!!!!!!!!!!!
    140.              Be carefull Physics2D.autoSimulation = true
    141.              Must be execured or Physics will be diabled in game mode
    142.              !!!!!!!!!!!
    143.             */
    144.  
    145.             Physics2D.autoSimulation = false;
    146.  
    147.             // see if all our
    148.             bool allSleeping = true;
    149.             activeCount = 0;
    150.  
    151.             foreach (Rigidbody2D body in workList)
    152.             {
    153.                 SpriteRenderer sr = body.gameObject.GetComponent<SpriteRenderer>();
    154.                 sr.color = Color.green;
    155.  
    156.                 if ((body != null) && (body.bodyType != RigidbodyType2D.Kinematic))
    157.                 {
    158.                     if (!body.IsSleeping())
    159.                     {
    160.                         allSleeping = false;
    161.                         activeCount++;
    162.                         sr.color = Color.red;
    163.                         //Debug.Log("Body = " + body.gameObject.name);
    164.                     }
    165.                 }
    166.             }
    167.  
    168.             Debug.Log("Active : " + active);
    169.  
    170.             if (allSleeping || activeTime >= timeToSettle)
    171.             {
    172.                 Physics2D.autoSimulation = cachedAutoSimulation;
    173.                 Deactivate();
    174.  
    175.                 if (allSleeping)
    176.                 {
    177.                     Debug.Log("All Alseep ending");
    178.                 }
    179.  
    180.                 if (activeTime >= timeToSettle)
    181.                 {
    182.                     Debug.Log("Active time elapsed ending");
    183.                 }
    184.             }
    185.             else
    186.             {
    187.                 SaveObjectdata();
    188.                 Physics2D.Simulate(Time.fixedDeltaTime);
    189.                 CheckObjectdata();
    190.                 //Physics2D.autoSimulation = true;
    191.             }
    192.         }
    193.     }
    194.  
    195.     private void SaveObjectdata()
    196.     {
    197.         // Will save all data needed to check if object will remain active
    198.  
    199.  
    200.         //throw new NotImplementedException();
    201.     }
    202.  
    203.     private void CheckObjectdata()
    204.     {
    205.         // Will check all data to check if object will remain active or fall asleep.
    206.  
    207.         //throw new NotImplementedException();
    208.     }
    209.  
    210.     [MenuItem("Tools/Scene Physics")]
    211.     private static void OpenWindow()
    212.     {
    213.         GetWindow<PhysicsSettler>(false, "Physics", true);
    214.     }
    215. }
     
    Kurt-Dekker likes this.