[Unity]儲存執行時對Scene中GameObject屬性的修改
阿新 • • 發佈:2018-12-26
google中原連結已失效,只剩快照了(unity3d-save-your-in-play-transform-modifications),所以寫篇文章記錄一下.
很多時候,我們想把運行遊戲時對場景中物體屬性的修改儲存下來,但一旦停止執行這些修改就恢復執行前的狀態了。對於有原Prefab的物體比較好辦,把執行中修改後的物體直接拖回去覆蓋原Prefab即可.而對只在Scene中存在的GameObject就沒法這樣做了。這裡以transform為例總結一種解決方法.
總體思路就是在執行中修改完畢後,save到某檔案中,然後停止執行後再讀取回來。但過程中又牽扯到一個問題:如果給transform新增按鈕會改變transform的佈局,而且用base.DrawDefaultInspector();或者base.OnInspectorGUI();都並不能畫出預設佈局的樣子,而是會變成這樣:
多出來個W,很難看。所以我們要先解決預設檢視佈局的問題,方法是用下面提到的DrawABetterInspector()函式來繪製.然後我們新增Save和Load兩個按鈕並新增相關功能.
程式碼如下:
using UnityEngine; using UnityEditor; using System.Collections.Generic; [CustomEditor(typeof(Transform))] public class TransformEditor : Editor { public void DrawABetterInspector(Transform t) { // Replicate the standard transform inspector gui EditorGUIUtility.labelWidth = 25; EditorGUIUtility.fieldWidth = 50; EditorGUI.indentLevel = 0; Vector3 position = EditorGUILayout.Vector3Field("Position", t.localPosition); Vector3 eulerAngles = EditorGUILayout.Vector3Field("Rotation", t.localEulerAngles); Vector3 scale = EditorGUILayout.Vector3Field("Scale", t.localScale); EditorGUIUtility.labelWidth = 0; EditorGUIUtility.fieldWidth = 0; if (GUI.changed) { Undo.RecordObject(t, "Transform Change"); t.localPosition = FixIfNaN(position); t.localEulerAngles = FixIfNaN(eulerAngles); t.localScale = FixIfNaN(scale); } } private Vector3 FixIfNaN(Vector3 v) { if (float.IsNaN(v.x)) { v.x = 0.0f; } if (float.IsNaN(v.y)) { v.y = 0.0f; } if (float.IsNaN(v.z)) { v.z = 0.0f; } return v; } public override void OnInspectorGUI() { Transform t = (Transform)target; DrawABetterInspector(t); if (GUILayout.Button("Save")) { SaveData(t.gameObject); } if (GUILayout.Button("Load")) { LoadData(t.gameObject); } } string GetInstanceFileName(GameObject baseObject) { return System.IO.Path.GetTempPath() + baseObject.name + "_" + baseObject.GetInstanceID() + ".keepTransform.txt"; } public void SaveData(GameObject baseObject) { List<string> saveData = new List<string>(); saveData.Add(this.GetInstanceID().ToString()); saveData.Add(baseObject.transform.localPosition.x.ToString()); saveData.Add(baseObject.transform.localPosition.y.ToString()); saveData.Add(baseObject.transform.localPosition.z.ToString()); saveData.Add(baseObject.transform.localRotation.eulerAngles.x.ToString()); saveData.Add(baseObject.transform.localRotation.eulerAngles.y.ToString()); saveData.Add(baseObject.transform.localRotation.eulerAngles.z.ToString()); saveData.Add(baseObject.transform.localScale.x.ToString()); saveData.Add(baseObject.transform.localScale.y.ToString()); saveData.Add(baseObject.transform.localScale.z.ToString()); System.IO.File.WriteAllLines(GetInstanceFileName(baseObject), saveData.ToArray()); } public void LoadData(GameObject baseObject) { string[] lines = System.IO.File.ReadAllLines(GetInstanceFileName(baseObject)); if (lines.Length > 0) { baseObject.transform.localPosition = new Vector3(System.Convert.ToSingle(lines[1]), System.Convert.ToSingle(lines[2]), System.Convert.ToSingle(lines[3])); baseObject.transform.localRotation = Quaternion.Euler(System.Convert.ToSingle(lines[4]), System.Convert.ToSingle(lines[5]), System.Convert.ToSingle(lines[6])); baseObject.transform.localScale = new Vector3(System.Convert.ToSingle(lines[7]), System.Convert.ToSingle(lines[8]), System.Convert.ToSingle(lines[9])); System.IO.File.Delete(GetInstanceFileName(baseObject)); } } }
將以上檔案儲存為TransformEditor.cs並儲存到Assets/Editor資料夾下即可,修改後的Transform面板如下:
建立一個Cube,執行場景,對其Transform做些修改,點Save儲存.然後停止場景,Cube恢復修改前的樣子.此時再點選Load,可以看到儲存的修改被載入回來了.