【发布时间】:2021-09-13 13:03:38
【问题描述】:
有点长,但是这些脚本是相互关联的。整个保存系统还有一些脚本,但是这 3 个脚本对于这种情况是最重要的。
现在,我可以保存变换位置旋转缩放的状态。
但保存是静态的,我的意思是我可以保存当前的变换位置旋转缩放,但我想在运行时动态保存中保存它的状态。
例如,如果我有一个移动到某个位置或某些位置之间的变换,那么我想保存变换当前位置,但也要保存变换移动方向,当加载回保存的游戏状态时,变换应该继续移动以相同的速度和方向到达下一个位置。
如果变换放大/缩小(例如从 5 到 1 和从 1 到 5),则逻辑相同,这样既可以保存当前缩放,也可以在加载时继续缩放。
旋转也一样。
这是转换保护类:
使用系统; 使用 System.Collections; 使用 System.Collections.Generic; 使用 UnityEngine;
[Serializable]
public class TransformSaver
{
public Vector3 position;
public Vector3 scaling;
public Quaternion rotation;
}
然后是保存加载脚本:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class SaveLoad : MonoBehaviour
{
public FadeInOutSaveGameText fadeInOutSaveGame;
public float timeToStartSaving;
public float savingFadeInOutTime;
private string saveString;
private void Awake()
{
SaveSystem.Init();
}
public void Save(string Folder, string FileName)
{
var objectsToSave = UpdateObjectsToSave();
SaveGame saveGame = new SaveGame();
saveGame.saveObjects = new List<SaveObject>();
for (int i = 0; i < objectsToSave.Count; i++)
{
SaveObject saveObject = new SaveObject();
saveObject.transformSaver = new TransformSaver();
Debug.Log($"{i}");
Debug.Log($"{objectsToSave[i].name}");
saveObject.gameObjectUniqueID = objectsToSave[i].GetComponent<GenerateGuid>().uniqueGuidID;
var x = objectsToSave[i].GetComponents<Component>();
var stateQueryComponent = x.Where(component => component is IStateQuery).ToList();
List<KeyToValue> componentsState = new List<KeyToValue>();
foreach (var z in stateQueryComponent)
{
var w = z as IStateQuery;
componentsState.Add(new KeyToValue(w.UniqueId.ToString(), w.GetState()));
}
saveObject.transformSaver.position = objectsToSave[i].transform.position;
saveObject.transformSaver.rotation = objectsToSave[i].transform.rotation;
saveObject.transformSaver.scaling = objectsToSave[i].transform.localScale;
saveObject.componentsState = componentsState;
saveGame.saveObjects.Add(saveObject);
}
string json = JsonUtility.ToJson(saveGame);
if (Folder == null && FileName == null)
{
SaveSystem.Save(json);
}
else
{
SaveSystem.Save(Folder, FileName, json);
}
}
public void Load(string Folder, string FileName)
{
var objectsToLoad = UpdateObjectsToSave();
Dictionary<string, GameObject> uniqueIdToObject = objectsToLoad
.ToDictionary(o => o.GetComponent<GenerateGuid>().uniqueGuidID, o => o);
saveString = SaveSystem.Load(Folder, FileName);
if (saveString != null)
{
SaveGame saveGame = JsonUtility.FromJson<SaveGame>(saveString);
foreach (var saveObject in saveGame.saveObjects)
{
List<KeyToValue> loadedComponents = saveObject.componentsState;
if (uniqueIdToObject.ContainsKey(saveObject.gameObjectUniqueID))
{
var objectToSetState = uniqueIdToObject[saveObject.gameObjectUniqueID];
objectToSetState.transform.position = saveObject.transformSaver.position;
objectToSetState.transform.rotation = saveObject.transformSaver.rotation;
objectToSetState.transform.localScale = saveObject.transformSaver.scaling;
var y = objectToSetState.GetComponents<Component>();
var z = y.Where(component => component is IStateQuery).ToList();
Dictionary<string, IStateQuery> zz = z.ToDictionary(sq => (sq as IStateQuery).UniqueId.ToString(), sq => sq as IStateQuery);
foreach (KeyToValue keyvalue in loadedComponents)
{
zz[keyvalue.Key].SetState(keyvalue.Value);
}
}
}
}
}
private List<GameObject> UpdateObjectsToSave()
{
var objectsWithGenerateGuid = GameObject.FindObjectsOfType<GenerateGuid>().ToList();
var objectsToSave = new List<GameObject>();
if (objectsWithGenerateGuid.Count > 0 && objectsToSave.Count == 0)
{
for (int i = 0; i < objectsWithGenerateGuid.Count; i++)
{
objectsToSave.Add(objectsWithGenerateGuid[i].gameObject);
}
}
return objectsToSave;
}
public IEnumerator AuatomaticSaveWithTime()
{
yield return new WaitForSeconds(timeToStartSaving);
Save(null, null);
StartCoroutine(fadeInOutSaveGame.OverAllTime(savingFadeInOutTime));
}
public IEnumerator SaveWithTime(string Folder, string FileName)
{
yield return new WaitForSeconds(timeToStartSaving);
Save(Folder, FileName);
StartCoroutine(fadeInOutSaveGame.OverAllTime(savingFadeInOutTime));
}
}
在第 46-48 行的 Save 方法中,我得到了 positon 、 rotation 、 scaling 的变换信息,然后将它们保存到一个子文件中。
但现在我想检查变换是否处于移动状态,然后保存当前的移动状态,如速度和方向。
在 Lod 方法的第 86-88 行中,我获取了转换信息并将其返回。
这是一个简单的状态脚本示例,用于在这种情况下保存状态为标志状态:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StateTest : MonoBehaviour, IStateQuery
{
private bool hasOpened;
private State m_state = new State();
public Guid UniqueId => Guid.Parse("88EE7288-1B1C-47D2-9981-29D1804B71A7");
private class State
{
public bool open;
// bool the kid holding the navi is true
}
public string GetState()
{
return JsonUtility.ToJson(m_state);
}
public void SetState(string jsonString)
{
m_state = JsonUtility.FromJson<State>(jsonString);
if(m_state.open)
{
hasOpened = true;
Debug.Log("Open !");
}
else
{
hasOpened = false;
Debug.Log("Close !");
}
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.O))
{
hasOpened = true;
Debug.Log("Open !");
}
if (Input.GetKeyDown(KeyCode.C))
{
hasOpened = false;
Debug.Log("Close !");
}
m_state.open = hasOpened;
}
}
我刚刚创建了一个本地打开/关闭标志状态,但是如果我想保存脚本状态附加到移动的转换怎么办?所以加载时它会将变换定位在保存的位置,但也会继续移动变换。
【问题讨论】:
-
JsonUtility.ToJson(m_state)实际上只会将m_state变量的布尔值保存到 json。如果你想添加额外的数据,比如转换的位置,你应该创建一个结构化的类来存储所有这些,并使用 json 来序列化和反序列化所述类的实例。 -
您可以将保存延迟一帧并使用这两帧来计算增量,从而计算两帧之间的速度