I have recently been creating a game with tutorials. Unfortunately, they didn't cover a save score feature. Thanks to another user, I was able to figure out that I needed to use playerprefs. I watched tutorials online, but none of them were helpful. If you can, please help me!
Gold Per Sec Script:
using UnityEngine;
using System.Collections;
public class GoldPerSec : MonoBehaviour {
public UnityEngine.UI.Text gpsDisplay;
public Click click;
public ItemManager[] items;
void Start () {
StartCoroutine(AutoTick ());
}
void Update () {
gpsDisplay.text = GetGoldPerSec() + " Money Per Sec";
}
public float GetGoldPerSec() {
float tick = 0;
foreach (ItemManager item in items) {
tick += item.count * item.tickValue;
}
return tick;
}
public void AutoGoldPerSec() {
click.gold += GetGoldPerSec() / 10;
}
IEnumerator AutoTick() {
while (true) {
AutoGoldPerSec();
yield return new WaitForSeconds(0.10f);
}
}
}
Gold Per Click script:
using UnityEngine;
using System.Collections;
public class Click : MonoBehaviour {
public UnityEngine.UI.Text gpc;
public UnityEngine.UI.Text goldDisplay;
public float gold = 0.00f;
public int goldperclick = 1;
void Update () {
goldDisplay.text = "" + gold.ToString("F0");
gpc.text = "Money Per Click: " + goldperclick;
}
public void Clicked(){
gold += goldperclick;
}
}
My idea was for the game to save when the game is quit, and load as soon as you load the game back up. I am a complete beginner, if anyone can tell me how to do this, please tell me! Thanks! :D
You can use unity's existing functions to achieve this.
For saving data use unity's OnApplicationQuit function like this
void OnApplicationQuit() {
PlayerPrefs.SetFloat("key", value);
}
And for Restoring the values use unity's Awake function like this
void Awake(){
value = PlayerPrefs.GetFloat("key");
}
Please note that PlayerPrefs is an easy way to save data but also an very unsafe way. The player can easily manipulate his "goldValue" since it's just stored as an integer in some file on his device. PlayerPrefs should usually just be used for values the player can changed any way within in game, like volume setting etc.
EXAMPLE CODE
void Save()
{
string filename = "/filename.dat";
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath+filename);
bf.Serialize(file, goldValue); //Use can easily use e.g. a List if you want to store more date
file.Close();
}
bool Load()
{
string filename = "/filename.dat";
if (File.Exists(Application.persistentDataPath + filename))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + filename, FileMode.Open);
goldValue=(int) bf.Deserialize(file);
file.Close();
return true;
}
return false;
}
Add the following code to Click class:
void Awake()
{
LoadData();
}
void OnApplicationQuit()
{
SaveData();
}
void SaveData()
{
PlayerPrefs.SetFloat("gold",gold);
}
void LoadData()
{
gold = PlayerPrefs.GetFloat("gold",0f);
}
Related
So I have been debugging for hours at this point to no avail. I call my function in another class and it keeps returning 0 I have tried logging everything to see if there is an error with it, and I can't find one. The target device prints out as UnityEngine.XR.InputDevice and nothing errors or warns. please if anyone has any insight. here's how I call it
Debug.Log(RightHand.AButtonDown());
and here is my code for the functions
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
public static class RightHand
{
private static InputDevice targetDevice;
static RightHand()
{
TryInitialize();
}
private static void TryInitialize()
{
Debug.Log("ran inital");
List<InputDevice> devices = new List<InputDevice>();
InputDeviceCharacteristics rightControllerCharacteristics = InputDeviceCharacteristics.Right | InputDeviceCharacteristics.Controller;
InputDevices.GetDevicesWithCharacteristics(rightControllerCharacteristics, devices);
foreach (var item in devices)
{
Debug.Log("ran log");
Debug.Log(item.name + item.characteristics);
}
Debug.Log("right controler characteristics" + rightControllerCharacteristics);
if (devices.Count > 0)
{
targetDevice = devices[0];
}
Debug.Log(targetDevice);
}
public static bool AButtonDown()
{
targetDevice.TryGetFeatureValue(CommonUsages.primaryButton, out bool primaryButtonOut);
if (primaryButtonOut)
{
return true;
}
else
{
return false;
}
}
}
My best guess is the list of devices needs to be updated each time a device value is accessed. The method I use uses Unity's XR Toolkit and had the same problem as yours until I moved InputDevice assignment into Update.
using UnityEngine.XR;
public class InputDeviceSample : MonoBehaviour
{
InputDevice left;
InputDevice right;
void Start()
{
}
void Update()
{
// needs to be in Update
right = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
// left = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
// more https://docs.unity3d.com/ScriptReference/XR.XRNode.html
// assigns button value to out variable, if expecting Vector3 replace bool
right.TryGetFeatureValue(CommonUsages.triggerButton, out bool isPressed);
Debug.Log(isPressed);
}
}
CommonUsages is the list of input actions you can read in, here's a list with brief descriptions:
https://docs.unity3d.com/ScriptReference/XR.CommonUsages.html
Hello? I'm studying the MIRROR Network Now.
enter image description here
However, I have a problem about getting other player's value. This image explain what I want to do.
enter image description here
I create 3 projects. One is server(local host) and other is Client A , the other is Client B.
Firstly, I wrote code like this :
public class PlayerManager : NetworkBehaviour
{
[SyncVar(hook = nameof(onValueChanged))]
int value = 0;
private void Update()
{
if(isServer && Input.GetKeyDown("x"))
{
Message();
}
}
public override void OnStartServer()
{
Debug.Log("Here is Game Room Scene, Player add Successfully");
}
[Command]
private void Hola()
{
value++;
Debug.Log("Received Hola from the client!");
Debug.Log("Server Value : " + value);
ReplyHola();
}
[TargetRpc]
private void ReplyHola()
{
Debug.Log("Received Hola from Client!");
}
[ClientRpc]
private void Message()
{
Debug.Log("Ping...");
}
[ClientRpc]
private void UpdateValue(int value)
{
this.value = value;
}
private void onValueChanged(int oldValue, int newValue)
{
Debug.Log("New Value Detective :");
Debug.Log("Old Value : " + oldValue);
Debug.Log("New Value : " + newValue);
Debug.Log("Sum Value : " + PlayerStat.Value);
}
}
3 Projects have all same code. I referenced code from this video(https://www.youtube.com/watch?v=8tKFF0RP9Jw).
And, I wrote code about sum client A and B's code like this:
private void SumDatas()
{
foreach(var playerObj in FindObjectsOfType(typeof(GameObject)) as GameObject[])
{
if(gameObject.name == "Player(Clone)")
{
PlayerStat.Value += GameObject.Find("Player(Clone)").transform.GetComponent<PlayerManager>().GetValue();
}
}
}
PlayerStat is a static class and Code is like this:
public static class PlayerStat
{
public static int Value { get; set; }
}
Is there anybody help me?
I solved this problem. I will not delete this question for other people who will have same problem with me.
I add this code at my server project, Client A and B project:
[SyncVar(hook = nameof(onValueChanged))]
int value = 0;
int myValue = 0;
private void Update()
{
myValue = PlayerStat.Value;
}
I am new to learning C# so I'm trying to figure out little bits at a time. Today's task is to have my cursor appear and disappear as I open a panel. I know that unity is weird and you have to build your project to see the cursor changes. However, on said build, when I press escape my panel appears but my cursor doesn't. If I close and reopen the panel the cursor will show up and then everything works as it should.
Something in my code that is causing this or is it just a unity bug?
Also, since I am new to this, any advice is appreciated. Thank you for your time!
public class MenuManager : MonoBehaviour
{
public GameObject pauseMenu;
public bool gamePause = false;
bool cursorHide = true;
// Start is called before the first frame update
void Start()
{
UpdateCursor();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
cursorHide = !cursorHide;
UpdateCursor();
PauseMenuOpen();
}
}
private void PauseMenuOpen()
{
if (!gamePause)
{
pauseMenu.SetActive(true);
gamePause = true;
}
else
{
pauseMenu.SetActive(false);
gamePause = false;
}
}
private void UpdateCursor()
{
Cursor.visible = !cursorHide;
}
public void QuitGame()
{
Application.Quit();
}
}
Use this code. it'll work
private bool isCursorHide;
private void Update(){
if (Input.GetKeyDown(KeyCode.Escape))
CursorToggler();
}
private void CursorToggler(){
if(isCursorHide){
isCursorHide =!isCursorHide;
Cursor.visible = isCursorHide;
}
else{
isCursorHide =!isCursorHide;
Cursor.visible = isCursorHide;
}
}
I have a ScriptableObject reference in a MonoBehaviour class.
Modify its values with CustomEditor button.
Save It.
Values seems changed.
Even selected ScriptableObject Inspector displays data modified.
But asset file on disk don't have any data.
And there's no data available from code of any another MonoBehaviour instance.
Here is a code snippet used to save my ScriptableObject.
public TextAsset text;
[SerializeField]
//Thats My Scriptable Object
public PathFramesList pathFramesList;
[SerializeField]
public List<List<ICurveData>> frameDatasList = new List<List<ICurveData>>();
// Called By CustomEditor Button
public void ReadData()
{
#region BlahBlahBlah generating some data to save
var separator = new string[] { "%" };
var framesUnparsedData = text.text.Split(separator, StringSplitOptions.None);
foreach (var f in framesUnparsedData)
frameDatasList.Add(ParseFrame(f));
var result = new ICurveData[frameDatasList.Count][];
for (int i = 0; i < frameDatasList.Count; i++)
result[i] = frameDatasList[i].ToArray();
#endregion
#region Trying to save data
pathFramesList.frameDatasList = result; // Set data to object
EditorUtility.SetDirty(pathFramesList); // Even This didn't help
AssetDatabase.SaveAssets(); // Looks it doesn't work
AssetDatabase.Refresh(); // Hoped this will help, whatever it do
#endregion
}
And that's my ScriptableObjectClass
And Its CustomEditor
[CreateAssetMenu(fileName = "ParsedPathData", menuName = "Create Path Data Asset")]
[System.Serializable]
public class PathFramesList : ScriptableObject
{
[SerializeField]
public ICurveData[][] frameDatasList;
}
#if UNITY_EDITOR
[CustomEditor(typeof(PathFramesList))]
public class PathFramesListEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
PathFramesList pathFrameList = (PathFramesList)target;
if(pathFrameList.frameDatasList == null)
{
GUILayout.TextField("Frames Count is 0");
}
else
{
// It still has all data
GUILayout.TextField("Frames Count is " + pathFrameList.frameDatasList.Length, 200);
}
if(GUILayout.Button("SaveAsset"))
{
// Tried to force saving with this) Didn't help
EditorUtility.SetDirty(target);
EditorUtility.SetDirty(serializedObject.targetObject);
serializedObject.Update();
serializedObject.ApplyModifiedProperties();
AssetDatabase.SaveAssets();
}
}
}
#endif
Ok.
Looks like scriptable objects files just can't store interface implementations examples.
Any else data was written to file well,
Correct me, please, if i'm wrong.
Im new in developing so need some help for my game!
On my game I have 2 buttons one is "Play" and other "Level Select"
I stuck at the "Play" button, need to make a script that is always loading the highest level that is unlocked, not current but highest.
Here is the code that im using for level manager
public List<Button> levelButton;
public Sprite lockimage;
public bool delete;
private void Start()
{
int saveIndex = PlayerPrefs.GetInt("SaveIndex");
for (int i = 0; i < levelButton.Count; i++)
{
if (i <= saveIndex)
{
levelButton[i].interactable = true;
}
else
{
levelButton[i].interactable = false;
levelButton[i].GetComponent<Image>().sprite = lockimage;
}
}
}
public void LevelSelect()
{
int level = int.Parse(EventSystem.current.currentSelectedGameObject.name);
SceneManager.LoadScene(level);
}
public void PlayGame()
{
//code here
}
public void ResetGame()
{
PlayerPrefs.SetInt("SaveIndex", 0);
SceneManager.LoadScene(0);
}
public void DontResetGame()
{
SceneManager.LoadScene(0);
}
}
SceneManager.LoadScene(PlayerPrefs.GetInt("SaveIndex"));
edit: adding some info/context.
I realized that you set level buttons interactivity on the start functions based on the int save_index value you get from PlayerPrefs.
From there, I assumed that you could load the level directly using that same value on the PlayGame function.
Do note that the code I wrote will throw an error, if the "SaveIndex" key is not yet on PlayerPrefs