[英]How to Save / Load game-time? (Unity Engine)
我的游戏中有两个场景 - 主菜单和游戏。 我已经使用二进制格式化程序和序列化制作了播放器的 position 和旋转在 2 个场景之间持续存在。 但是,我很难让游戏场景中的时间在两个场景(和游戏会话)之间持续存在。 简而言之:
我粘贴了一些代码(保存和加载 pos & rot),这样你就知道发生了什么。
public static class DataSerializer
{
public static void SerializeData(Player player)
{
BinaryFormatter bf = new BinaryFormatter();
string dataPath = Application.persistentDataPath + "/data.txt";
FileStream stream = new FileStream(dataPath, FileMode.Create);
PlayerData data = new PlayerData(player);
bf.Serialize(stream, data);
stream.Close();
}
public static float[] DeserializeData()
{
string dataPath = Application.persistentDataPath + "/data.txt";
if (File.Exists(dataPath))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream stream = new FileStream(dataPath, FileMode.Open);
PlayerData data = bf.Deserialize(stream) as PlayerData;
stream.Close();
return data.stats;
}
else
{
Debug.LogError("File does not exist.");
return new float[6];
}
}
}
[Serializable]
public class PlayerData
{
public float[] stats;
public PlayerData(Player player)
{
stats = new float[6];
stats[0] = player.transform.position.x;
stats[1] = player.transform.position.y;
stats[2] = player.transform.position.z;
stats[3] = player.transform.eulerAngles.x;
stats[4] = player.transform.eulerAngles.y;
stats[5] = player.transform.eulerAngles.z;
}
}
public class Player : MonoBehaviour
{
public GameObject player;
void Start()
{
float[] loadedStats = DataSerializer.DeserializeData();
Vector3 position = new Vector3(loadedStats[0], loadedStats[1], loadedStats[2]);
Vector3 rotation = new Vector3(loadedStats[3], loadedStats[4], loadedStats[5]);
player.transform.position = position;
player.transform.rotation = Quaternion.Euler(rotation);
}
public void Save()
{
DataSerializer.SerializeData(this);
}
}
如果您能以同样的方式帮助我保存和加载游戏时间,我将不胜感激。
谢谢!
首先,为什么float[]
如此复杂。 在我看来,它只会让人难以阅读/理解并且容易出错。
我会简单地使用如下结构(如果你不喜欢它 - 一定要坚持float[7]
为什么不 ^^)
public static class DataSerializer
{
private static readonly dataPath = Path.Combine(Application.persistentDataPath, "data.txt");
public static void SerializeData(Player player)
{
var data = new PlayerData(player);
using(var stream = File.Open(dataPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write))
{
var bf = new BinaryFormatter();
bf.Serialize(stream, data);
}
}
public static bool DeserializeData(out PlayerData data)
{
data = null;
if (!File.Exists(dataPath))
{
Debug.LogError("File does not exist.");
return false;
}
using(var stream = File.Open(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var bf = new BinaryFormatter();
data = bf.Deserialize(stream) as PlayerData;
}
return data != null;
}
}
[Serializable]
public class PlayerData
{
public SerializableVector3 Position;
public SerializableVector3 EulerAngles;
public float TotalTimePlayed;
public PlayerData(Player player)
{
Position = player.transform.position;
EulerAngles = player.transform.eulerAngles;
TotalPlayTime = player.TotalTimePlayed;
}
}
[Serializable]
public class SerializableVector3
{
public float x;
public float y;
public float z;
public SerializableVector3(Vector3 vec)
{
x = vec.x;
y = vec.y;
z = vec.z;
}
public Vector3 ToVector3()
{
return new Vector3(x,y,z);
}
public static implicit operator Vector3(SerializableVector3 vec)
{
return vec.ToVector3();
}
public static implicit operator SerializableVector3(Vector3 vec)
{
return new SerializableVector3(vec);
}
}
那么跟踪总播放时间有多种方法。
要么存储上次保存的DateTime.Now
,这样您就可以在保存时简单地添加当前播放的时间:
float timePlayedThisSession = (DateTime.Now - dateTimeLastSaved).TotalSeconds;
优点:系统会处理它,这是一次计算
缺点:用户可以简单地更改系统时间 -> 可能“破解”您的应用统计信息
或者您可以简单地使用Time.unscaledTime
,它是自上次应用程序启动以来的时间。
优点:用户不能简单地改变这个值
缺点:根据您的用例,您可能无法使用Time.unscaledTime
如果您允许重置到应用程序中的最后一次保存(因为在这种情况下Time.time
只是从应用程序启动开始继续计数)
或者你可以 go 完全“手动”并使用Time.unscaledDeltaTime
完全自己跟踪播放时间,例如
private float timePlayedThisSession; private void Update() { timePlayedThisSession += Time.unscaledDeltaTime; }
Pro:完全控制 + 可以轻松地重置或将值加载到该字段中。
缺点:每帧调用Update
方法的开销……但这太小了,根本不重要; ;)
Fazit 我会用最后一个选项 go 做例如
public class Player : MonoBehaviour
{
public GameObject player;
private float totalTimePlayed;
// Read-only access
public float TotalTimePlayed => totalTimePlayed;
void Start()
{
ResetToLastSave ();
}
private void Update ()
{
totalTimePlayed += Time.unscaledDeltaTime;
}
// Just adding this to show you could even simply add a method to allow your user revert to the last save
public void ResetToLastSave()
{
if(!DataSerializer.DeserializeData(out var loadedStats))
{
Debug.LogWarning("Could not load!", this);
return;
}
player.transform.position = loadedStats.Position;
player.transform.eulerAngles = loadedStats.Rotation;
totalTimePlayed = loadedStats.TotalTimePlayed;
}
public void Save()
{
DataSerializer.SerializeData(this);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.