Hello I have a question on how I can read the data from a JSON file I have already made the saving method I just can't seem to find out how to read JSON files
Code for my saving system:
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GlobalControl : MonoBehaviour
{
public GameObject Player;
public void Save()
{
var player = Player.GetComponent<PlayerScript>();
PlayerData playerdata = new PlayerData();
playerdata.pos = player.transform.position;
playerdata.curreceny = player.currency;
playerdata.playerDebug = player.IsUsingDebug;
string json = JsonUtility.ToJson(playerdata);
Debug.Log("Player data has been saved");
File.WriteAllText(Application.dataPath + "playerData.json", json);
PlayerData loadedPlayerData = JsonUtility.FromJson<PlayerData>(json);
}
public class PlayerData
{
public bool playerDebug;
public Vector3 pos;
public int curreceny;
}
}
I happened to be implementing that on my application currently
i would suggest that you add this JSON file in StreamingAssets Folder inside your project
then access it
this is my function to read it
string filePath = Path.Combine(Application.streamingAssetsPath, jsonfileName);
WWW www = new WWW(filePath);
while (!www.isDone) { }
string dataAsJson = www.text;
OnRead(dataAsJson);
and this is the full class
using UnityEngine;
using System;
using System.IO;
using System.Threading.Tasks;
public class StreamingDataHandler
{
private static StreamingDataHandler Inistance
{
get
{
if (inistance == null) inistance = new StreamingDataHandler();
return inistance;
}
}
static StreamingDataHandler inistance;
private StreamingDataHandler()
{
}
public static void ReadStringFile(string jsonfileName, Action<string> OnRead, bool isAsync = true)
{
Inistance.ReadFile(jsonfileName, OnRead, isAsync);
}
private void ReadFile(string jsonfileName, Action<string> OnRead, bool isAsync = true)
{
string filePath = Path.Combine(Application.streamingAssetsPath, jsonfileName);
if (isAsync)
{
ReadStringFileAsync(filePath, OnRead);
}
else
{
string filePath = Path.Combine(Application.streamingAssetsPath, jsonfileName);
WWW www = new WWW(filePath);
while (!www.isDone) { }
string dataAsJson = www.text;
OnRead(dataAsJson);
}
}
private async void ReadStringFileAsync(string filePath, Action<string> OnRead)
{
WWW www = new WWW(filePath);
while (!www.isDone)
{
await Task.Yield();
}
string dataAsJson = www.text;
OnRead(dataAsJson);
}
}
Related
I have been working on a customization system that allows a player to customize their skin color and particle trail of their character. I have the system working and am now attempting to save the data through JsonUtility and then load it. I plan on saving the data with the play button then transitioning to a new scene and having it load at start() of the new scene. But, for testing I have been using a load button as it should still work...but it doesn't.
My current SaveSystem script is supposedly working since the DebugLog "Save file created" for saving files appears when the button is pressed. But, when pressing the load button nothing changes yet the DebugLog "Save file found and loaded" still appears. I am kinda lost as to where to go and how to load the data into the Customization script since I am still new to C# Json and serializing in general.
Here are my 3 scripts:
SaveSystem Script
using UnityEngine;
using System.IO;
public static class SaveSystem
using UnityEngine;
using System.IO;
public static class SaveSystem
{
public static string directory = "/saveData";
public static string fileName = "MyData.txt";
public static void SavePlayer(Customization CurrentCustomization)
{
string dir = Application.persistentDataPath + directory;
if(!Directory.Exists(dir))
Directory.CreateDirectory(dir);
Debug.Log("Save file created");
string json = JsonUtility.ToJson(CurrentCustomization);
File.WriteAllText(dir + fileName, json);
}
public static Customization LoadPlayer()
{
string fullPath = Application.persistentDataPath + directory + fileName;
Customization CurrentCustomization = new Customization();
if(File.Exists(fullPath))
{
string json = File.ReadAllText(fullPath);
CurrentCustomization = JsonUtility.FromJson<Customization>(json);
Debug.Log("Save file found and loaded");
}
else
{
Debug.Log("Save file does not exist");
}
return CurrentCustomization;
}
}
CharacterCustomizaiton Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class CharacterCustomization : MonoBehaviour
{
public List<Customization> Customizations;
public int currentCustomizationIndex;
public Customization CurrentCustomization {get; private set;}
[SerializeField] private TextMeshProUGUI bodyColorText;
[SerializeField] private TextMeshProUGUI trailText;
public void Save()
{
SaveSystem.SavePlayer(CurrentCustomization);
}
public void Load()
{
CurrentCustomization = SaveSystem.LoadPlayer();
}
void Awake()
{
foreach(var customization in Customizations)
{
customization.UpdateSubObjects();
customization.UpdateRenderers();
}
}
public void SelectBodyColor(bool isForward)
{
currentCustomizationIndex = 0;
CurrentCustomization = Customizations[currentCustomizationIndex];
if(isForward)
{
CurrentCustomization.NextMaterial();
}
else
{
CurrentCustomization.PreviousMaterial();
}
bodyColorText.text = CurrentCustomization.materialIndex.ToString();
}
public void SelectLTrail(bool isForward)
{
currentCustomizationIndex = 1;
CurrentCustomization = Customizations[currentCustomizationIndex];
if(isForward)
{
CurrentCustomization.NextSubObject();
}
else
{
CurrentCustomization.PreviousSubObject();
}
trailText.text = CurrentCustomization.subObjectIndex.ToString();
}
public void SelectRTrail(bool isForward)
{
currentCustomizationIndex = 2;
CurrentCustomization = Customizations[currentCustomizationIndex];
if(isForward)
{
CurrentCustomization.NextSubObject();
}
else
{
CurrentCustomization.PreviousSubObject();
}
trailText.text = CurrentCustomization.subObjectIndex.ToString();
}
}
Customization Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Customization
{
public string DisplayName;
public List<Renderer> Renderers;
public List<Material> Materials;
public List<GameObject> SubObjects;
public int materialIndex;
public int subObjectIndex;
public void NextMaterial()
{
if(materialIndex == Materials.Count - 1)
{
materialIndex = 0;
}
else
{
materialIndex++;
}
UpdateRenderers();
}
public void PreviousMaterial()
{
if(materialIndex == 0)
{
materialIndex = Materials.Count - 1;
}
else
{
materialIndex--;
}
UpdateRenderers();
}
public void NextSubObject()
{
if(subObjectIndex == SubObjects.Count - 1)
{
subObjectIndex = 0;
}
else
{
subObjectIndex++;
}
UpdateSubObjects();
}
public void PreviousSubObject()
{
if(subObjectIndex == 0)
{
subObjectIndex = SubObjects.Count - 1;
}
else
{
subObjectIndex--;
}
UpdateSubObjects();
}
public void UpdateSubObjects()
{
for(var i = 0; i < SubObjects.Count; i++)
if (SubObjects[i])
SubObjects[i].SetActive(i == subObjectIndex);
}
public void UpdateRenderers()
{
foreach (var renderer in Renderers)
if (renderer)
renderer.material = Materials[materialIndex];
}
}
I've been trying to implement a savegame function into my game. When I load the game from the save, it doesn't load the position of the player.
I have 2 main scenes: The scene in which the game is taking place, and the main menu scene. The main menu makes use of my load function, which is supposed to read my save file and put the player at a given position, however, it just loads the scene at the default position. No errors are thrown, no warning messages. Here is all of my code:
This is my Save game system:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public static class SaveSystem
{
public static void SavePlayer (Player player)
{
BinaryFormatter formatter = new BinaryFormatter();
string path = Application.persistentDataPath + "player.fun";
FileStream stream = new FileStream(path, FileMode.Create);
PlayerData data = new PlayerData(player);
formatter.Serialize(stream, data);
stream.Close();
}
public static PlayerData LoadPlayer ()
{
string path = Application.persistentDataPath + "/player.fun";
if (File.Exists(path))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(path, FileMode.Open);
PlayerData data = formatter.Deserialize(stream) as PlayerData;
stream.Close();
return data;
}
else
{
Debug.LogError("Save file not in " + path);
return null;
}
}
}
Container for player data:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class PlayerData
{
public int level;
public int health;
public float[] position;
public int stamina;
public PlayerData (Player player)
{
level = player.level;
health = player.health;
stamina = player.stamina;
position = new float[3];
position[0] = player.transform.position.x;
position[1] = player.transform.position.y;
position[2] = player.transform.position.z;
}
}
My Scene Changing Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneChanger : MonoBehaviour
{
public static bool Isload = false;
public void gotoWelwardLoad()
{
SceneManager.LoadScene("Welward");
bool Isload = true;
}
public void gotoWelward()
{
SceneManager.LoadScene("Welward");
}
public void gotomainmenu()
{
SceneManager.LoadScene("Menu");
}
}
My Player Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Player : MonoBehaviour
{
public int health = 1;
public int stamina = 1;
public int level = 1;
public void SavePlayer ()
{
SaveSystem.SavePlayer(this);
}
public void LoadPlayer ()
{
SceneManager.LoadScene("Welward");
PlayerData data = SaveSystem.LoadPlayer();
level = data.level;
health = data.health;
stamina = data.stamina;
Vector3 position;
position.x = data.position[0];
position.y = data.position[1];
position.z = data.position[2];
transform.position = position;
}
public static void gotomenu ()
{
SceneManager.LoadScene("Menu");
}
public static void Welward()
{
SceneManager.LoadScene("Welward");
SaveSystem.LoadPlayer();
}
}
Link with full unity project files:
https://drive.google.com/open?id=1mFH5aNklC0qMWeJjMT4KD0CbTTx65VRp
As BugFinder correctly points out, your save path is different than your loading path.
Try changing Application.persistentDataPath + "player.fun"; to Application.persistentDataPath + "/player.fun"; to match your loading code. Or you could move that string path variable up into the class as a const then reference it since it will be guaranteed to match.
After that however you will also need to call Player.LoadPlayer() somewhere since in your existing project you do not do that anywhere I can find, and when you call it currently it will reload the scene (which probably isn't the behaviour you want either). I would remove SceneManager.LoadScene("Welward"); from that method.
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public static class SaveSystem
{
// This is a way to make sure your path is the same, and not about to get overwritten
public static string Path => Application.persistentDataPath + "/player.fun";
public static void SavePlayer (Player player)
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(Path, FileMode.Create);
PlayerData data = new PlayerData(player);
formatter.Serialize(stream, data);
stream.Close();
// It's helpful to print out where this is going
Debug.Log($"Wrote to {Path}");
}
public static PlayerData LoadPlayer ()
{
if (File.Exists(Path))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(Path, FileMode.Open);
PlayerData data = formatter.Deserialize(stream) as PlayerData;
stream.Close();
// It's also helpful to print out that it worked, not just log errors if it fails
Debug.Log($"Successfully read from {Path}");
return data;
}
else
{
Debug.LogError("Save file not in " + Path);
return null;
}
}
}
One thing thats noticeable is in save you use Application.persistentDataPath + "player.fun"; and in load you use, Application.persistentDataPath + "/player.fun"; So, perhaps therefore it doesnt find the file to load it. As you thought. Personally Path.Combine is a good option, platform non specific etc. So try replacing both with Path.Combine(Application.persistentDataPath,"player.fun");
From the code you provided I don't see the part where you call Player.LoadPlayer(). So add it to Player:
void Start(){
LoadPlayer();
}
Hope it helps.
I am building a game which has a high score. The data inside the high score is the number of Kills, Time and username that the player has which are stored in a list. Currently, I got a working system using binary formatter and a serialized text file, however when I load the list and its contents from the binary file only the first created entry into the binary file shows up in the list on the high score. It looks like the binary file is only reading the first line of the file.
Question 1: why can I only read the first entry from the binary file?
Question 2: how do I insert all data from a binary file into a List?
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class HighscoreManager : MonoBehaviour
{
Dictionary<string, Dictionary<string, int> > PlayerScore;
private int Time;
private int Kills;
private int Kills2;
private int Kills3;
private int Kills4;
private int Kills5;
private int Kills6;
private string userName = "User01";
public GameObject SL;
//public ArrayList savedDatas = new ArrayList();
public List<string> loadedstats = new List<string>();
// Start is called before the first frame update
void Start()
{
SetScore("Rick", "Time", 500);
SetScore("Rick", "Kills", 9);
SetScore("BOB", "Time", 1500);
SetScore("BOB", "Kills", 50);
SetScore("BBB", "Deaths", 3);
SetScore("CCC", "Time", 6);
//GetComponent<PlayerController>().LoadPlayer();
//SaveSystems.LoadPlayer();
//savedData.Add(data.savedData);
loadedstats = SaveSystems.LoadPlayer();
int.TryParse(loadedstats[0], out Kills);
int.TryParse(loadedstats[1], out Time);
//int.TryParse(loadedstats[2], out Kills2);
//int.TryParse(loadedstats[3], out Kills3);
//int.TryParse(loadedstats[4], out Kills4);
//int.TryParse(loadedstats[5], out Kills5);
//Kills = (int)data[0];
//Time = (int)data[1];
//userName = "" + data[2];
SetScore(userName, "Time", Time);
SetScore(userName, "Kills", Kills);
Debug.Log("data loaded" + " Time : " + Time + ", Kills : " + Kills + ", username : " + userName);
Debug.Log("List Counted objects = " + loadedstats.Count);
Debug.Log("List capacity = " + loadedstats.Capacity);
}
void Init()
{
if (PlayerScore != null)
{
return;
}
else
{
PlayerScore = new Dictionary<string, Dictionary<string, int>>();
}
}
public int GetScore(string userName, string scoreType)
{
Init();
if (PlayerScore.ContainsKey(userName) == false)
{
return 0;
}
if(PlayerScore[userName].ContainsKey(scoreType) == false)
{
return 0;
}
return PlayerScore[userName][scoreType];
}
public void SetScore(string userName, string scoreType, int value)
{
Init();
if (PlayerScore.ContainsKey(userName) == false)
{
PlayerScore[userName] = new Dictionary<string, int>();
}
PlayerScore[userName][scoreType] = value;
}
public void ChangeScore(string userName, string scoreType, int amount)
{
Init();
int currScore = GetScore(userName, scoreType);
SetScore(userName, scoreType, currScore + amount);
}
public string[] GetPlayerNames(string sortingScoreType)
{
Init();
return PlayerScore.Keys.OrderByDescending( n => GetScore(n, sortingScoreType) ).ToArray();
}
}
above is the highscoreManager class which builds the high score list. below is the saveSystem class which saves and loads data in a binary file.
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System;
using System.Collections;
using System.Collections.Generic;
public static class SaveSystems
{
public static ArrayList savedData = new ArrayList();
public static void SavePlayer(PlayerController player)
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(Application.persistentDataPath + "/player.savedData",
FileMode.Append);
PlayerData data = new PlayerData(player);
formatter.Serialize(stream, data);
stream.Close();
Debug.Log(Application.persistentDataPath + "/player.savedData");
}
public static List<string> LoadPlayer()
{
if (File.Exists(Application.persistentDataPath + "/player.savedData"))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(Application.persistentDataPath + "/player.savedData", FileMode.Open);
PlayerData data = formatter.Deserialize(stream) as PlayerData;
stream.Close();
return data.stats;
}
else
{
return null;
}
}
}
[Serializable]
public class PlayerData
{
public List<string> stats = new List<string>();
public PlayerData(PlayerController player)
{
//stats[0] = player.Kills;
stats.Add("" + player.Kills);
//stats[1] = player.Time;
stats.Add("" + player.Time);
}
}
I been follow the tutorial from this video.
The tutorial source code can be found at here...
I have a problem of my Json data all been stored in 1 single line,
I want the data break into new line for single object data
Here the code for the Json tutorial
Actor file
using UnityEngine;
using System.Collections;
using System;
public class Actor : MonoBehaviour {
public ActorData data = new ActorData();
public string name = "Tile";
string newline = "\n";
public void StoreData()
{
data.name = name;
data.pos = transform.position;
}
public void LoadData()
{
name = data.name;
transform.position = data.pos;
}
public void ApplyData()
{
SaveData.AddActorData(data);
}
void OnEnable()
{
SaveData.OnLoaded += LoadData;
SaveData.OnBeforeSave += StoreData;
SaveData.OnBeforeSave += ApplyData;
}
void OnDisable()
{
SaveData.OnLoaded -= LoadData;
SaveData.OnBeforeSave -= StoreData;
SaveData.OnBeforeSave -= ApplyData;
}
}
[Serializable]
public class ActorData
{
public string name;
public Vector2 pos;
}
save data file
using UnityEngine;
using System.Collections;
using System.Xml.Serialization;
using System.IO;
public class SaveData
{
public static ActorContainer actorContainer = new ActorContainer();
public delegate void SerializeAction();
public static event SerializeAction OnLoaded;
public static event SerializeAction OnBeforeSave;
public static void Load(string path)
{
actorContainer = LoadActors(path);
foreach (ActorData data in actorContainer.actors)
{
GameController.CreateActor(data, GameController.playerPath,
data.pos, Quaternion.identity);
}
OnLoaded();
ClearActorList();
}
public static void Save(string path, ActorContainer actors)
{
OnBeforeSave();
//ClearSave(path);
SaveActors(path, actors);
ClearActorList();
}
public static void AddActorData(ActorData data)
{
actorContainer.actors.Add(data);
}
public static void ClearActorList()
{
actorContainer.actors.Clear();
}
private static ActorContainer LoadActors(string path)
{
string json = File.ReadAllText(path);
return JsonUtility.FromJson<ActorContainer>(json);
}
private static void SaveActors(string path, ActorContainer actors)
{
string json = JsonUtility.ToJson(actors);
StreamWriter sw = File.CreateText(path);
sw.Close();
File.WriteAllText(path, json);
}
}
There are two overloads for the JsonUtility.ToJson function:
public static string ToJson(object obj);
public static string ToJson(object obj, bool prettyPrint);
Use the second one and pass true to it. It will format the output for readability making the json separated into lines.
Just replace string json = JsonUtility.ToJson(actors); with string json = JsonUtility.ToJson(actors, true);
If you are not satisfied with the result, use Newtonsoft.Json for Unity and format the json like this:
string json = JsonConvert.SerializeObject(actors);
string newLineJson = JValue.Parse(json).ToString(Formatting.Indented);
Im trying to save some enums in my code. Saving and converting to the string is going well. But with the loading there r some problems. I mean. I just cant load it). Im doing all that in unity. I thought to convert enum to string and after convert it back. Conversion to string works fine. But what happens with back-convestion i dont know. Thanks.
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public class GameControl : MonoBehaviour {
public static GameControl control;
public float health;
public float experience;
public string stateString;
public enum State { start_0, start_1, start_3, start_4 };
public State myState;
void Awake () {
if(control == null)
{
DontDestroyOnLoad(gameObject);
control = this;
}
else if(control != this)
{
Destroy(gameObject);
}
}
public void Save()
{
stateString = myState.ToString(); //Converts ENUM to STRING
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath +
"/playerInfo.dat");
PlayerData data = new PlayerData();
data.health = health;
data.experience = experience;
data.stateString = stateString;
bf.Serialize(file, data);
file.Close();
}
public void Load()
{
if(File.Exists(Application.persistentDataPath + "/playerInfo.dat"))
{
State loadedState = (State) Enum.Parse(typeof(State), stateString);
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath +
"/playerInfo.dat", FileMode.Open);
PlayerData data = (PlayerData)bf.Deserialize(file);
file.Close();
health = data.health;
experience = data.experience;
stateString = data.stateString;
}
}
}
[Serializable]
class PlayerData
{
public float health;
public float experience;
public string stateString;
public enum State { start_0, start_1, start_3, start_4 };
public State myState;
}