[Unity]保存运行时对Scene中GameObject属性的修改

xiaoxiao2021-02-28  71

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,可以看到保存的修改被加载回来了.

转载请注明原文地址: https://www.6miu.com/read-50487.html

最新回复(0)