So I'm only a week into learning C# and I've been working on this one problem for 8 hours. I'll describe what I'm trying to do, and if there's a better way I would really appreciate any guidance.
In the code below, I'm storing info from a Firebase database called snapshot, and trying to save it as a text file data.json. Later in the code, it reads data.json and calls allRoundData from the file.
Right now in Unity the application doesn't compile and says "Object reference not set to an instance of an object" for allRoundData = loadedData.allRoundData;
I also checked and nothing is writing to the text file when I open it in explorer.
I'm pulling trivia questions and answers from a Firebase database, so however I do this it's important that the user can't access the answers. Would it be more secure to skip writing it to a text file and just declare allRoundData = snapshot.allRoundData? The problem is that allRoundData is a string array and the snapshot is an object. Is there a way to easily convert it or how can I solve this in the simplest way?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.IO;
using Firebase;
using Firebase.Unity.Editor;
using Firebase.Database;
public class DataController : MonoBehaviour
{
public class FirebaseStart: MonoBehaviour
{
void Start()
{
// Set up the Editor before calling into the realtime database.
FirebaseApp.DefaultInstance.SetEditorDatabaseUrl("https://FIREBASEDATABASE");
// Get the root reference location of the database.
DatabaseReference reference =
FirebaseDatabase.DefaultInstance.RootReference;
FirebaseDatabase.DefaultInstance
.GetReference("allRoundData")
.GetValueAsync().ContinueWith(task => {
if (task.IsFaulted)
{
// Handle the error...
}
else if (task.IsCompleted)
{
string gameDataFileName = "data.json";
string filePath =
Path.Combine(Application.streamingAssetsPath, gameDataFileName);
DataSnapshot snapshot = task.Result;
// Do something with snapshot...
string rawData = snapshot.GetRawJsonValue();
StreamWriter sw = new StreamWriter(filePath);
sw.WriteLine(rawData);
sw.Close();
}
});
}
}
private RoundData[] allRoundData;
private PlayerProgress playerProgress;
// Use this for initialization
void Start ()
{
DontDestroyOnLoad(gameObject);
LoadGameData();
LoadPlayerProgress();
SceneManager.LoadScene("MenuScreen");
}
public RoundData GetCurrentRoundData()
{
return allRoundData [0];
}
public void SubmitNewPlayerScore(int newScore)
{
if (newScore > playerProgress.highestScore)
{
playerProgress.highestScore = newScore;
SavePlayerProgress();
}
}
public int GetHighestPlayerScore()
{
return playerProgress.highestScore;
}
// Update is called once per frame
void Update () {
}
private void LoadPlayerProgress()
{
playerProgress = new PlayerProgress();
if (PlayerPrefs.HasKey("highestScore"))
{
playerProgress.highestScore = PlayerPrefs.GetInt("highestScore");
}
}
private void SavePlayerProgress()
{
PlayerPrefs.SetInt("highestScore", playerProgress.highestScore);
}
private void LoadGameData()
{
string gameDataFileName = "data.json";
string filePath = Path.Combine(Application.streamingAssetsPath, gameDataFileName);
if (File.Exists(filePath))
{
string dataAsJson = File.ReadAllText(filePath);
GameData loadedData = JsonUtility.FromJson<GameData>(dataAsJson);
allRoundData = loadedData.allRoundData;
}
else
{
Debug.LogError("Cannot load game data!");
}
}
}
Related
[EDIT] Everything is working now! Thank's to #MrMoonMan!
As the title says, I'm working on a mobile game and I just implemented a Check Update popup.
The thing is, the popup is displayed every time the menu scene is loaded, and this is very annoying because if the player goes to the weapon menu and then comes back to the main menu 10 times, he will see the popup 10 times. The goal is to have the popup appear only once per game session, Here is what I tried for the moment but without success:
Using a bool variable
Destroy the gameobject to which the checkupdate script is attached when the user presses the "No Thank's" button
Here is the code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class CheckUpdate : MonoBehaviour
{
public string versionUrl = "";
public string currentVersion;
private string latestVersion;
public GameObject newVersionAvailable;
private static bool hasBeenChecked = false;
void OnAwake()
{
DontDestroyOnLoad(this);
StartCoroutine(LoadTxtData(versionUrl));
}
private IEnumerator LoadTxtData(string url)
{
UnityWebRequest loaded = new UnityWebRequest(url);
loaded.downloadHandler = new DownloadHandlerBuffer();
yield return loaded.SendWebRequest();
latestVersion = loaded.downloadHandler.text;
CheckVersion();
}
private void CheckVersion()
{
Debug.Log("currentVersion = " + currentVersion);
Debug.Log("latestVersion = " + latestVersion);
Version versionDevice = new Version(currentVersion);
Version versionServer = new Version(latestVersion);
int result = versionDevice.CompareTo(versionServer);
if ((latestVersion != "") && (result < 0))
{
newVersionAvailable.SetActive(true);
}
if (GetChecked())
return;
}
public void ClosePopUp(GameObject obj)
{
obj.SetActive(false);
Destroy(this);
}
public void OpenURL(string url)
{
Application.OpenURL(url);
}
public static bool GetChecked()
{
if (hasBeenChecked)
{
return hasBeenChecked;
}
hasBeenChecked = true;
return false;
}
}
EDIT
Ok so you mentioned that it still happens every time the scene is reloaded. That is because the object is created when the scene is loaded. It isn't saved between scenes. To handle that properly you need to tell it to not get destroyed when the scene is unloaded and to do that is simple, and that is by Adding DontDestroyOnAwake. Here is an example of the code:
public class CheckUpdate : MonoBehaviour
{
public string versionUrl = "";
public string currentVersion;
private string latestVersion;
public GameObject newVersionAvailable;
void OnAwake()
{
DontDestroyOnLoad(this);
}
void OnStart()
{
StartCoroutine(LoadTxtData(versionUrl));
}
private IEnumerator LoadTxtData(string url)
{
UnityWebRequest loaded = new UnityWebRequest(url);
loaded.downloadHandler = new DownloadHandlerBuffer();
yield return loaded.SendWebRequest();
latestVersion = loaded.downloadHandler.text;
}
private void CheckVersion()
{
Debug.Log("currentVersion = " + currentVersion);
Debug.Log("latestVersion = " + latestVersion);
Version versionDevice = new Version(currentVersion);
Version versionServer = new Version(latestVersion);
int result = versionDevice.CompareTo(versionServer);
if ((latestVersion != "") && (result < 0))
{
newVersionAvailable.SetActive(true);
}
}
public void ClosePopUp(GameObject obj)
{
obj.SetActive(false);
}
public void OpenURL(string url)
{
Application.OpenURL(url);
}
}
,,Menu scene''? It sound some suspicious. If you load and unload whole new scene as menu, state as bool field in MonoBehaviours or modifing the scene structure (destory, create object) will not work beacuse allways will be loaded new scene from scratch. ;)
If you have to have menu on seperated scene use someting other to manage the state. For example:
DontDestoryOnLoad objects.
Or some C# static class or singleton (not a MonoBehaviour).
So in our visual novel game using the ink/inkle API for unity, I'm trying to implement a save and load system, but I am currently having trouble with loading the saved state the way I intend to.
Based on the API's documentation, to save the state of your story within your game, you call:
string savedJson = _inkStory.state.ToJson();
then to load it:
_inkStory.state.LoadJson(savedJson);
Here is the how I save the current state of the story using PlayerPrefs, which is working just fine.
public void saveGame()
{
DialogueSystem dialogueSystem = GetComponent<DialogueSystem>();
dialogueSystem.savedJson = dialogueSystem.dialogue.state.ToJson();
PlayerPrefs.SetString("saveState", dialogueSystem.savedJson);
Debug.Log(dialogueSystem.savedJson);
}
and here is how I'm trying to load the saved state on Start(), which doesn't load the saved state.
private void Start()
{
dialogue = new Story(dialogueJSON.text);
currentActiveBG = BGs[0];
historyScript = GetComponent<History>();
counterScript = GetComponent<counter>();
if (PlayerPrefs.HasKey("saveState")) { // for loading the saved state
dialogue = new Story(dialogueJSON.text);
savedJson = PlayerPrefs.GetString("saveState");
dialogue.state.LoadJson(savedJson);
loadLine(); //this function contains story.Continue, which loads the next line
Debug.Log(savedJson);
}
else {
loadGame("Pre_Prep1"); // default starting line
}
}
How can I make this work? And is there a better way of implementing this save/load feature?
I'm not sure which game you're going to make but, I use the following saving system in my project and it's working perfectly and you can also use it.
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// Saving System
public class UserData{
#region Save Data Var's
// file Path
private static readonly string FILE_PATH = Application.dataPath +
"/SaveFiles";
public int carToLoad;
public int levelToLoad;
public int unlockLevels;
#endregion
#region Methods
// Save
public static void SaveData(string contents){ // for Car Selection
File.WriteAllText(FILE_PATH + "/UserData.txt",contents);
}
// Load
public static UserData LoadData(){
string _data = File.ReadAllText(FILE_PATH + "/UserData.txt");
return JSONToUserData(_data);
}
// Init
public static void UserData_init(){
CheckFilesPreviousData();
CheckDirectory();
}
// Selection Level Data
public static void SaveData(UserData LevelData) { // for Level
UserData tempObj = LoadData();
tempObj.levelToLoad = LevelData.levelToLoad;
SaveData(UserDataToJSON(tempObj));
}
// UnLock Level Data
public static void SaveUnLockedLevelData(int LevelValue){
UserData tempObj = LoadData();
tempObj.unlockLevels = LevelValue;
File.WriteAllText(FILE_PATH + "/UnLockLevels.text",
UserDataToJSON(tempObj));
}
// Load UnLock Level Data
public static UserData LoadUnLockLevelData(){
string _data= File.ReadAllText(FILE_PATH+"/UnLockLevels.text");
UserData tempObj = JSONToUserData(_data);
return tempObj;
}
#endregion
#region Helper Methods
// !! important
public static UserData JSONToUserData(string path) =>
JsonUtility.FromJson<UserData>(path);// JSON to Obj
public static string UserDataToJSON(UserData obj) => JsonUtility.ToJson(obj);//
Obj to JSON
// Making Directory if not present
private static void CheckDirectory(){
if (!Directory.Exists(FILE_PATH)){
Directory.CreateDirectory(FILE_PATH);
}
}
// Reset Data If User Play 1st Time
private static void CheckFilesPreviousData(){
// Checking File is not Null
UserData tempObj = LoadUnLockLevelData();
if(tempObj == null){
const int FIRSTLEVEL = 1;
SaveUnLockedLevelData(FIRSTLEVEL);
Debug.Log("Donee");
}
}
#endregion
}
So I've been making a save/load script for my Unity project, and it looks like this (please don't copy):
using UnityEngine;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System;
using System.Runtime.Serialization;
using System.Reflection;
// Made By Wasabi.
// === This is the info container class ===
[Serializable ()]
public class SaveData : ISerializable {
// === Values ===
public bool foundKeyCard1 = false;
public bool foundKeyCard2 = false;
public bool foundKeyCard3 = false;
public bool foundKeyCard4 = false;
public bool foundKeyCard5 = false;
public bool foundKeyCard6 = false;
public bool foundKeyCard7 = false;
public bool foundKeyCard8 = false;
public bool foundKeyCard9 = false;
public bool foundKeyCard10 = false;
public bool foundCarKeys1 = false;
public float expscore = 0;
public int levelReached = 1;
// === /Values ===
public SaveData () {}
public SaveData (SerializationInfo info, StreamingContext ctxt)
{
foundKeyCard1 = (bool)info.GetValue("foundKeyCard1", typeof(bool));
foundKeyCard2 = (bool)info.GetValue("foundKeyCard2", typeof(bool));
foundKeyCard3 = (bool)info.GetValue("foundKeyCard3", typeof(bool));
foundKeyCard4 = (bool)info.GetValue("foundKeyCard4", typeof(bool));
foundKeyCard5 = (bool)info.GetValue("foundKeyCard5", typeof(bool));
foundKeyCard6 = (bool)info.GetValue("foundKeyCard6", typeof(bool));
foundKeyCard7 = (bool)info.GetValue("foundKeyCard7", typeof(bool));
foundKeyCard8 = (bool)info.GetValue("foundKeyCard8", typeof(bool));
foundKeyCard9 = (bool)info.GetValue("foundKeyCard9", typeof(bool));
foundKeyCard10 = (bool)info.GetValue("foundKeyCard10", typeof(bool));
foundCarKeys1 = (bool)info.GetValue("foundCarKeys1", typeof(bool));
expscore = (float)info.GetValue("expscore", typeof(float));
levelReached = (int)info.GetValue("levelReached", typeof(int));
}
public void GetObjectData (SerializationInfo info, StreamingContext ctxt)
{
info.AddValue("foundKeyCard1", (foundKeyCard1));
info.AddValue("foundKeyCard2", (foundKeyCard2));
info.AddValue("foundKeyCard3", (foundKeyCard3));
info.AddValue("foundKeyCard4", (foundKeyCard4));
info.AddValue("foundKeyCard5", (foundKeyCard5));
info.AddValue("foundKeyCard6", (foundKeyCard6));
info.AddValue("foundKeyCard7", (foundKeyCard7));
info.AddValue("foundKeyCard8", (foundKeyCard8));
info.AddValue("foundKeyCard9", (foundKeyCard9));
info.AddValue("foundKeyCard10", (foundKeyCard10));
info.AddValue("foundCarKeys1", (foundCarKeys1));
info.AddValue("expscore", expscore);
info.AddValue("levelReached", levelReached);
}
}
// === This is the class that will be accessed from scripts ===
public class SaveLoad {
public static string currentFilePath = "SaveData.cjc";
public static void Save () // Overloaded
{
Save (currentFilePath);
}
public static void Save (string filePath)
{
SaveData data = new SaveData ();
Stream stream = File.Open(filePath, FileMode.Create);
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Binder = new VersionDeserializationBinder();
bformatter.Serialize(stream, data);
stream.Close();
}
public static void Load () { Load(currentFilePath); } // Overloaded
public static void Load (string filePath)
{
SaveData data = new SaveData ();
Stream stream = File.Open(filePath, FileMode.Open);
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Binder = new VersionDeserializationBinder();
data = (SaveData)bformatter.Deserialize(stream);
stream.Close();
}
}
// === This is required to guarantee a fixed serialization assembly name, which Unity likes to randomize on each compile
// Do not change this
public sealed class VersionDeserializationBinder : SerializationBinder
{
public override Type BindToType( string assemblyName, string typeName )
{
if ( !string.IsNullOrEmpty( assemblyName ) && !string.IsNullOrEmpty( typeName ) )
{
Type typeToDeserialize = null;
assemblyName = Assembly.GetExecutingAssembly().FullName;
// The following line of code returns the type.
typeToDeserialize = Type.GetType( String.Format( "{0}, {1}", typeName, assemblyName ) );
return typeToDeserialize;
}
return null;
}
}
And I think that's it. The CS1513 isn't in there. If you spot any errors, please let me know. But the problem is in this other script I'm making that autosaves when I close the application. It looks like this (Please don't copy):
using UnityEngine; // For Debug.Log, etc.
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System;
using System.Runtime.Serialization;
using System.Reflection;
// Made by Wasabi.
void OnApplicationQuit()
{
public class SaveLoad {
public static string currentFilePath = "SaveData.cjc";
public static void Save () // Overloaded
{
Save (currentFilePath);
}
public static void Save (string filePath)
{
SaveData data = new SaveData ();
Stream stream = File.Open(filePath,
FileMode.Create);
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Binder = new
VersionDeserializationBinder();
bformatter.Serialize(stream, data);
stream.Close();
}
}
}
Now I know the code under void OnApplicationQuit() is supposed to be my save routine. Well I'm not exactly sure what part of my save script is my save routine. So If you could help me with that, feel free to examine my save/load script and tell me what is my actual save routine. But anyways, it keeps on telling me "Error, "}" expected (11,7) CS1513." and I check my script. I've read another post and the answer was that the error meant that I had forgotten a closing "}" at the end f my script. Well it seems as though that is not true in my case, because it is not missing any "}". I even tried adding an extra "}" at the end, and yet it still said the same thing. So it only clears the error when I put another "}" directly after the opening "{" after
void OnApplicationQuit() which doesn't make any sense. But when I do, it then says another error at
void OnApplicationQuit() (to be specific: the beginning of OnApplicationQuit() of void OnApplicationQuit()) and that I can't use methods or functions for that namespace, which I don't know what that means, and I don't think that's true. I believe that the second error is only triggered because I had to put void OnApplicationQuit() {}. What is going on here and how in the world do I fix it? Another thing: I constructed my Save/Load script after researching on how to do that, but how does the code know when I collect a keycard1? Do I have to make a script in the keycard1 that tells the Save/Load script when I collect it? And will this result in me having to add more scripts in the Save/Load script to detect the keycard1 script telling the Save/Load script that I picked it up? I'm still new to the whole C# part of Unity and I'm entirely self-taught. You see, I'm just beginning to make my first serious project. So I need to know what exactly are the save and load routines in my save/load script that I use to call save and load; because I need to make a menu screen with buttons that when pressed, call the save or load routine. So when I press he Save or Load button(s), looking at my script, will the Script know that I have the KeyCard, or will I have to manually put that into the script? And lastly, how do I make a script that calls a save when I obtain, say, KeyCard2?
Sincerely,
Wasabi.
Please don't copy
I assure you that I don't even want to ^^
What is your second snippet supposed to do?
You have a method declaration OnApplicationQuit() and within that method you declare public static fields and other methods.
-> None of this is allowed in c#.
your method OnApplicationQuit() should be inside of a type of type MonoBehaviour {...}
and then you can't have access modifiers inside a method. You rather want to simply call that static method SaveLoad.Save().
You would rather have a GameObject in your scene with a component attached like
public class SaveLoadBehavior : MonoBehaviour
{
private void Awake ()
{
SaveLoad.Load();
}
void OnApplicationQuit()
{
SaveLoad.Save();
}
}
See OnApplicationQuit.
Note herefor that every component in Unity needs to be written in a individual and equally named file. So in the example it should be in SaveLoadBehaviour.cs (where the .cs is hidden inside Unity)
Actually alternative to this you might want to rather use e.g. RuntimeInitializeOnLoadMethod and Application.quitting this way you don't need the afore mentioned component and GameObject at all:
public class SaveLoad
{
// will be automatically called on application start
[RuntimeInitializeOnLoadMethod]
private static void Init()
{
Load();
// register a callback to the application quitting event
Application.quitting += OnQuit;
}
// will be automatically called on application quit
private static void OnQuit()
{
Save();
}
.... // Your load and save methods just the way you have them already
}
The save state class :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
[Serializable]
public class SaveState
{
public float RotationX { set; get; }
public float RotationY { set; get; }
public float RotationZ { set; get; }
public DateTime LastSaveTime { set; get; }
}
The save manager :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System;
using System.IO;
public class SaveManager : MonoBehaviour
{
#region Instance
private static SaveManager instance;
public static SaveManager Instance
{
get
{
if (instance == null)
{
instance = FindObjectOfType<SaveManager>();
if (instance == null)
{
instance = new GameObject("Spawned SaveManager", typeof(SaveManager)).GetComponent<SaveManager>();
}
}
return instance;
}
set
{
instance = value;
}
}
#endregion
[Header("Logic")]
[SerializeField] private string saveFileName = "data.dat";
[SerializeField] private bool loadOnStart = true;
private BinaryFormatter formatter;
private SaveState state;
public SaveState State { get => state; set => state = value; }
private void Start()
{
// Init the formatter.
formatter = new BinaryFormatter();
DontDestroyOnLoad(this.gameObject);
// If loadOnStart is true try to load the saved file.
if (loadOnStart == true)
{
Load();
}
}
public void Save()
{
// If no state
if (state == null)
{
state = new SaveState();
}
//Set the time when trying to save.
state.LastSaveTime = DateTime.Now;
//Open the file.
var file = new FileStream(saveFileName, FileMode.OpenOrCreate, FileAccess.Write);
formatter.Serialize(file, state);
file.Close();
}
public void Load()
{
// Open file
try
{
var file = new FileStream(saveFileName, FileMode.Open, FileAccess.Read);
// Read file.
state = (SaveState)formatter.Deserialize(file);
file.Close();
}
catch
{
Debug.Log("No save file found, creating a new entry");
Save();
}
}
}
And a test script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SaveTest : MonoBehaviour
{
private void Update()
{
SaveManager saveManager = SaveManager.Instance;
if(Input.GetKeyDown(KeyCode.T))
{
var player = GameObject.Find("Player");
saveManager.State.RotationX = player.transform.position.x;
saveManager.State.RotationY = player.transform.position.y;
saveManager.State.RotationZ = player.transform.position.z;
saveManager.Save();
}
if(Input.GetKeyDown(KeyCode.L))
{
SaveManager.Instance.Load();
}
}
}
When I press the T key I used a break point it's getting there finding the player.
But when pressing the L key it does nothing it's not changing the player rotation to what have been saved.
I can see the file is created data.dat 256 bytes size.
You are only loading in the data from your save file, but not actually doing anything with the data. If you want to set the player's rotation based on whatever data is inside your downloaded state you need to make a call to that data.
public void Load()
{
// Open file
try
{
var file = new FileStream(saveFileName, FileMode.Open, FileAccess.Read);
// Read file.
state = (SaveState)formatter.Deserialize(file);
file.Close();
//After obtaining the SaveState we apply the values to our player's local rotation
player.transform.localRotation = Quaternion.Euler(state.RotationX, state.RotationY, state.RotationZ);
}
catch
{
Debug.Log("No save file found, creating a new entry");
Save();
}
}
(Note that although i'm assigning the values to the player inside your Load method here, I would recommend doing that in a separate method for cleaner code)
I was building an application and wanted to get data through text file. when i put the location of any folder of computer then it is working properly but when i changed the location and use that app with android smart phone it doesn't save txt file in mobile's internal storage or sdcard.
How can i save .txt file in mobile internal storage?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEngine.UI;
public class click2 : MonoBehaviour
{
public static bool mobileSD;
public static string saveLocation;
public void onclick()
{
// in order to save at sdcard, make it 'true'
mobileSD = true;
if (mobileSD == false) { saveLocation = "d:/"; }
else { saveLocation = "/sdcard/Download/"; }
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#saveLocation + 1 + ".txt", true))
{
file.Write("a");
file.Close();
}
}
}
}
Save Data in your Application.persistentDataPath
https://unity3d.com/learn/tutorials/topics/scripting/persistence-saving-and-loading-data
First :
Write Your Data when you start the app.
Second: when you want to load your Data
Check if the File Existed in the Application.persistentDataPath
and if true you can read it normally, if not write your default settings in It.
Try This code and Customize it depending on Your Requirements :
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public class SaveData : MonoBehaviour
{
// Start is called before the first frame update
public string DATA_PATH = "player.json";
void Start()
{
GamePalyer p = new GamePalyer();
p.Id = 1;
p.Name="John Smith";
p.Score = 100;
Debug.Log("Starts Saving");
SaveDataToFile(p);
ReadData();
}
public void SaveDataToFile(GamePalyer _player)
{
string filePath = Application.persistentDataPath + "/" + DATA_PATH;
Debug.Log("Saving At : "+ filePath);
string savedData = JsonUtility.ToJson(_player);
File.WriteAllText(filePath, savedData);
}
public void ReadData()
{
string filePath = Application.persistentDataPath + "/" + DATA_PATH;
if (File.Exists(filePath))
{
string data = File.ReadAllText(filePath); ;
GamePalyer player = JsonUtility.FromJson<GamePalyer>(data);
Debug.Log(player.Id);
Debug.Log(player.Name);
Debug.Log(player.Score);
}
}
}
[System.Serializable]
public class GamePalyer
{
public int Id;
public string Name;
public float Score;
}