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