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

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


猜你喜欢

转载自blog.csdn.net/tlrainty/article/details/77750706