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.
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.
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);
}
}