【问题标题】:How can I save a transform movement state to json?如何将变换运动状态保存到 json?
【发布时间】: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 来序列化和反序列化所述类的实例。
  • 您可以将保存延迟一帧并使用这两帧来计算增量,从而计算两帧之间的速度

标签: c# unity3d


【解决方案1】:

我有一个移动到某个位置或某些位置之间的变换

当您的变换开始移动时,您是否调用了一个事件?如果是这样,您可以保存:

  • 变换开始移动时的初始位置,
  • 开始移动的时间值,
  • 变换的实际位置(您实际在做什么),
  • 以及保存位置时的时间值。

利用这些信息,您可以在加载时定位变换,然后使用变换的初始位置计算它前进的方向。 然后用开始移动到保存位置的那一刻所花费的时间和行进的距离来计算速度(formula to calculate the speed

【讨论】:

    猜你喜欢
    • 2017-03-15
    • 1970-01-01
    • 2021-01-13
    • 2010-09-14
    • 2016-09-15
    • 1970-01-01
    • 2011-04-02
    • 1970-01-01
    • 2019-08-25
    相关资源
    最近更新 更多