【发布时间】:2019-12-12 13:28:38
【问题描述】:
我完成了一个新游戏,其中我使用序列化数据实现了保存管理器,而不是使用 PlayerPrefs 获取所有玩家信息。一切似乎都运行良好,但由于某种原因,我的 Android 构建没有正确保存或加载一些布尔值。在 Unity 编辑器中,它似乎完全可以保存和加载这些布尔变量......其他一切(保存的整数、字符串)似乎在移动设备中运行良好。
基本上,我要保存的是玩家是否与特定 NPC 交谈并正确回答了问题。
到目前为止,我已经尝试了几件事,希望它可以解决:
- 我尝试将数据保存为 List 以及 bool。最初我将此播放器信息的数据存储在列表中。当他们正确回答 NPC 时,NPC 将作为字符串添加到列表中。它也不起作用,所以我认为这是序列化列表的问题,所以我尝试了 bools。
- 已将我的项目升级到最新版本的 Unity。对问题没有影响。
- 我已经完全重建了几次,对我的代码进行了修改,并在 Android 上进行了测试,但均未成功。它仍在 Unity 编辑器中正常工作。
应该发生什么与(正在发生什么)
对话应该增加,以便下一次对话有所不同(这有效,直到我进入主菜单并返回,或退出游戏并返回)。
它应该触发一个动作,比如奖励玩家(我得到了奖励,但是由于它不记得我和谁说话,所以它让我在离开游戏并返回时收回奖励)。
我的代码: 对不起,有点厚,所以我试图在每个块之前总结一下目的。
Storyteller.cs - 附加到主游戏场景中的游戏对象。保存玩家正确回答 NPC 时的奖励方法。
using UnityEngine;
public class Storyteller : MonoBehaviour
{
[SerializeField] RPGTalk rpgTalk; // I am using this asset to help with dialogues
SaveManager saveManager;
private void Start()
{
saveManager = GameObject.FindGameObjectWithTag("SaveManager").GetComponent<SaveManager>();
}
//NPC Methods
public void RewardFromFlowerLady()
{
if (saveManager.myStats.flowerLadyGiftClaimed == true)
{
saveManager.myStats.coins += 700;
saveManager.Save();
}
}
public void RewardFromHippie()
{
if (saveManager.myStats.hippieGiftClaimed == true)
{
ReceiveMedicinalHerbsEvent(1.1f);
saveManager.Save();
}
}
public void PetFromTrashCan()
{
if (saveManager.myStats.trashCanGiftClaimed == true)
{
saveManager.myStats.trashcat = 1;
saveManager.Save();
}
}
}
DialogueProgress.cs - 附加到主游戏场景中的 Player 对象。当玩家正确回答 NPC 时,它会将我保存文件中的布尔值设置为 True 并使用保存管理器中的 Save 方法保存游戏。
using UnityEngine;
public class DialogueProgress : MonoBehaviour
{
SaveManager saveManager;
private void Awake()
{
saveManager = GameObject.FindGameObjectWithTag("SaveManager").GetComponent<SaveManager>();
}
public void NPCSpokenAdder(string npcname)
{
switch (npcname){
case "FlowerLady":
saveManager.myStats.flowerLadyGiftClaimed = true;
saveManager.Save();
break;
case "Hippie":
saveManager.myStats.hippieGiftClaimed = true;
saveManager.Save();
break;
case "TrashCan":
saveManager.myStats.trashCanGiftClaimed = true;
saveManager.Save();
break;
}
}
}
QuestionAndChoiceID.cs - 这个脚本附加到我的三个 NPC 游戏对象上,在每个游戏对象上,我都在检查器中添加了一个问题 ID 和正确答案作为整数。
using UnityEngine;
public class QuestionAndChoiceID : MonoBehaviour
{
public string questionID;
public int correctchoiceID;
RPGTalk rpgTalk;
RPGTalkArea talkArea;
SaveManager saveManager;
DialogueProgress dialogueProgress;
Storyteller storyTeller;
void Start()
{
saveManager = GameObject.FindGameObjectWithTag("SaveManager").GetComponent<SaveManager>();
rpgTalk = GameObject.FindGameObjectWithTag("RPGTalk").GetComponent<RPGTalk>();
storyTeller = FindObjectOfType<Storyteller>();
talkArea = this.gameObject.GetComponent<RPGTalkArea>();
dialogueProgress = FindObjectOfType<DialogueProgress>();
LoadCorrectResponses();
rpgTalk.OnMadeChoice += OnMadeChoice;
}
private void OnDisable()
{
rpgTalk.OnMadeChoice -= OnMadeChoice;
}
private void OnMadeChoice(string question, int choice)
{
if (question == questionID && choice == correctchoiceID)
{
switch (this.gameObject.name)
{
case "FlowerLady":
dialogueProgress.NPCSpokenAdder(this.gameObject.name);
IncrementDialogue();
storyTeller.RewardFromFlowerLady();
break;
case "Hippie":
dialogueProgress.NPCSpokenAdder(this.gameObject.name);
IncrementDialogue();
storyTeller.RewardFromHippie();
break;
case "TrashCan":
dialogueProgress.NPCSpokenAdder(this.gameObject.name);
IncrementDialogue();
storyTeller.PetFromTrashCan();
break;
}
}
}
private void IncrementDialogue()
{
if (saveManager.myStats.flowerLadyGiftClaimed && this.gameObject.name == "FlowerLady")
{
talkArea.lineToStart = this.gameObject.name + 1;
talkArea.lineToBreak = this.gameObject.name + 1 + "_end";
Debug.Log(this.gameObject.name + " dialogue incremented correctly;");
}
else if (saveManager.myStats.hippieGiftClaimed && this.gameObject.name == "Hippie")
{
talkArea.lineToStart = this.gameObject.name + 1;
talkArea.lineToBreak = this.gameObject.name + 1 + "_end";
}
else if (saveManager.myStats.trashCanGiftClaimed && this.gameObject.name == "TrashCan")
{
talkArea.lineToStart = this.gameObject.name + 1;
talkArea.lineToBreak = this.gameObject.name + 1 + "_end";
}
}
private void LoadCorrectResponses()
{
if (saveManager.myStats.flowerLadyGiftClaimed)
{
if (this.gameObject.name == "FlowerLady")
{
talkArea.lineToStart = this.gameObject.name + 1;
talkArea.lineToBreak = this.gameObject.name + 1 + "_end";
}
}
else if (saveManager.myStats.hippieGiftClaimed)
{
if (this.gameObject.name == "Hippie")
{
talkArea.lineToStart = this.gameObject.name + 1;
talkArea.lineToBreak = this.gameObject.name + 1 + "_end";
}
}
else if (saveManager.myStats.trashCanGiftClaimed)
{
if (this.gameObject.name == "TrashCan")
{
talkArea.lineToStart = this.gameObject.name + 1;
talkArea.lineToBreak = this.gameObject.name + 1 + "_end";
}
}
}
}
这里也包括我的 SaveManager.cs 脚本:
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
public class SaveManager : MonoBehaviour
{
public Stats myStats;
private void Awake()
{
if (File.Exists(Application.persistentDataPath + "/Player.dat"))
{
Load();
}
InvokeRepeating("Save", 1, 15);
}
private void OnApplicationQuit()
{
Save();
}
public void Save()
{
Debug.Log("Saving actual game.");
FileStream file = new FileStream(Application.persistentDataPath + "/Player.dat", FileMode.OpenOrCreate); // Create a file or open a file to save to
try
{
BinaryFormatter formatter = new BinaryFormatter(); // Binary formatter -- allows us to write data to a file
formatter.Serialize(file, myStats);
}
catch (SerializationException e)
{
Debug.LogError("Issue serialising this data: " + e.Message);
}
finally
{
file.Close();
}
}
public void Load()
{
FileStream file = new FileStream(Application.persistentDataPath + "/Player.dat", FileMode.Open);
try
{
BinaryFormatter formatter = new BinaryFormatter();
myStats = (Stats)formatter.Deserialize(file);
}
catch (SerializationException e)
{
Debug.LogError("Error deserialising this data: " + e.Message);
}
finally
{
file.Close();
}
}
}
来自 Stats.cs 的相关 sn-p 包含我要保存的所有数据:
using UnityEngine;
[System.Serializable]
public class Stats
{
public bool flowerLadyGiftClaimed;
public bool hippieGiftClaimed;
public bool trashCanGiftClaimed;
}
希望有人可能遇到类似问题并可以提供帮助。我是序列化数据以进行保存和加载的新手,所以也许我缺少一些东西。由于我的其他数据保存和加载正常,所以我认为这是由于我上面的代码中的一些不正确的逻辑。只是不确定为什么它在 Unity 编辑器中运行良好!这是我游戏的最后一步,也是我完成的第一步,很高兴能解决它。
感谢阅读。
【问题讨论】:
-
您在 Android 上遇到任何错误吗?
-
一般提示:我不会使用对象字符串名称,但您应该引入
enum,例如public enum NpcType { FlowerLady, Hippie, TrashCan }并在switch - case中使用它。对命名错误会更有效,更健壮;) -
另外:你知道
talkArea.lineToStart = this.gameObject.name + 1;会导致FlowerLady1对吗?或者你想在那里获得一个索引,例如使用类似talkArea.lines.IndexOf(name) + 1? -
您好 derHugo,感谢您的回复。我没有为测试设置调试的 Android 环境,所以我不知道。 (对这一切仍然很陌生,需要学习如何设置这种东西,我的下一个重点肯定是......)。 APK 运行,但我没有设置查看调试的方法。注意到枚举。我以前使用枚举来处理玩家状态等问题,但需要以其他方式合并它们——我会尝试的。是的,我希望 lineToStart 更改为 FlowerLady1,因为这是他们之前与她交谈时应该播放的“谈话”。
标签: c# android unity3d serialization save