Hello! I’ve been working on an extensive project for a while now, and I’m up to the point of integrating a saving system. I figure there isn’t a built in saving system for Unity 3D, and the simplest way of going about it is to use PlayerPrefs. So far I have this:
New Game.js
This deletes any Prefs in the project and starts the first level of the game, place on the “New Game” button. Simple enough.
var level = 2;
function OnMouseDown(){
Application.LoadLevel(level);
PlayerPrefs.DeleteAll();
}
Save.js
This code will be placed at the start of each level, basically, saving it.
function Start(){
PlayerPrefs.SetInt("SavedLevel", Application.loadedLevel);
}
Let’s say the player exits the game and boots it up and want to continue from that level. Here’s the script placed on the “Continue” button.
Continue.js
function OnMouseDown(){
if(PlayerPrefs.HasKey("SavedLevel")){
Application.LoadLevel(PlayerPrefs.GetInt("SavedLevel"));
}
if(PlayerPrefs.HasKey("SavedLevel") == null){
Debug.Log("There is no saved game. Select the 'New Game' option to start!");
}
}
In my game, there are maybe 3 static variables that need to be saved: the number of collectibles, the maxHealth of the player, and some kind of checkpoint value, but that can be saved for later. Is there a way to also save the collectibles and maxHealth, then completely shutting down the game, then hitting continue to have those same values, all while using PlayerPrefs?
You can save PlayerPrefs anytime using Save() method. Unity will save it for you if you quit the game orderly (not in case of a crash). Saved values will be loaded automatically on your game restart.
The only bad part is possible size limitations (mostly in webplayer I believe):
It will save everything you set in PlayerPrefs and load them as well. I recommend to read notes from PlayerPrefs.Save() documentation. It explains all of this. You don’t need to load anything. Unity does it for you. IMO, PlayerPrefs is very simplistic and you would need to write some functionality on top to achieve a fully functional save system. Like, for example, saving separate profiles would be a bit inelegant using PlayerPrefs. So a lot of people write their own mechanisms using xml (or in my case I like JSON). If your requirements are simple then PlayerPrefs will do.
Only if there’s only one coin, because you’re saving the value “1” into PlayerPrefs. You probably want to save the value “coin”, since that seems to be where you’re tracking the number of coins the player has.
And obviously sometime during your application load you need to get “Coin” from PlayerPrefs and put the value into your coin variable (assuming it is a member of your player representation class).
Question: The variable coin, which is actually called “coins” in my script, is a static variable. Does that have some reason why it doesn’t work? Also, I’m displaying coins like this:
function OnGUI(){
GUI.Box(new Rect(20,70,100,20),coins + " ");
}
The number starts from 0, of course, and whenever coins are collected, the number increments. But when I cut the game off, and press the “Continue” button, it’s back at 0. I’m also doing this in the editor. Is that a factor too?
I’m not sure how editor behaves in this situation but I would not let Unity do saves by itself. I would call Save() method explicitly at the logical point (end of level/game). Also, did you assign your static variable somewhere using PlayerPrefs (like I indicated above in point #1)?
Holy s***! I think I finally got it to work! Here’s what I did.
This is my Health/Coin collection script, might be confusing:
#pragma strict
#pragma implicit
#pragma downcast
var spawnPoint : Transform;
static var curHealth = 3;
static var coins = 0;
var hudDepth : float = 0.0;
static var maxHealth = 3;
private var damage = 1;
private var barLength = 600;
coins = PlayerPrefs.GetInt("Coin");
function Start(){
}
function OnGUI(){
GUI.Box(new Rect(20,70,100,20),coins + " ");
GUI.Box(new Rect(20,20,barLength,20),curHealth + " ");
GUI.depth = hudDepth;
}
function FixedUpdate(){
//-----------------------THE PLAYER HAS BEEN KILLED-------------------
if(curHealth <= 0){
Application.LoadLevel(Application.loadedLevel);
curHealth = maxHealth;
}
//-----------------------HEALTH UPGRADES BY RELIC COLLECTION---------------------------
if(coins < 100){
curHealth = curHealth;
}
if(coins == 100){
maxHealth ++;
curHealth = maxHealth;
coins = 0;
}
}
//------------------------COLLECTABLES DAMAGE CONTROL--------------------------------
function OnTriggerEnter(other : Collider){
if(other.tag == "Killzone"){
InvokeRepeating("Killzone",0.3,1.0);
}
if(other.gameObject.tag == "Health"){
Destroy(other.gameObject);
curHealth = maxHealth;
}
if(other.gameObject.tag == "Coin"){
coins ++;
Destroy(other.gameObject);
PlayerPrefs.SetInt("Coin",coins);
}
}
function OnTriggerExit(other : Collider){
if(other.tag == "Killzone"){
CancelInvoke("Killzone");
}
if(other.tag == "Doom"){
transform.position = spawnPoint.transform.position;
/*This is now a cube instead of a floor. Fix a cube around the level,
making the bottom cube the hieght level of "fall off", and fix the y
hieght and x width to fit the level to you're liking.
*/
}
}
function Killzone(){
curHealth -= damage;
}
I did what you told me, and put point 2 in, but this time, instead of putting point 1 in the start function, I left it out of all functions like a variable without the “var” part. Both the quit button on the main menu and the quit option on the pause menu has Save(). So, I played the game, select new game which deletes all prefs, so PlayerPrefs…DeleteAll(), then collected some objects, returned to the main menu, quit the game, started it up, pressed continue, and bam! The values remain. I’m still going to play around with it to set up health saves and checkpoints, and post those here as well.
And of course, I ran into another problem with saving the health. In this part, I am trying to save the health upgrades(probably maxHealth). This is kinda an extension on the coin thing. Here are some important snippets of the script.
Sometimes the level restarts every frame. YIKES! Sometimes, the starting health, which is supposed to by curHealth = 3 and maxHealth = 3, goes down to 1 when I collect 100 coins, then increments from there. Then sometimes I reload the level voluntary and the maxHealth goes up without collecting 100 coins.
The player takes damage by the curHealth
I know I may be asking a lot, and that this may be difficult for some people, but help would be appreciated.
Get rid of statics (specially curHealth and coins). You are using Monobehaviour that seems to be attached to a player GO. Since there is only 1 player, there will be only one Monobehaviour. And that way your statics will not persist between level initializations.
If your maxHealth is always 3 then why are you getting it from PlayerPrefs on top? Also, any initializations like that should probably be done in your Start() method.
Describe exactly the rules of how your health, max health and coins have to interact. Otherwise it is difficult to see if your code is doing something intentionally or if you have a bug.
Describe what needs to be saved between level loads and game restarts. I see at least one place where your “coins” value get set to 0 but you don’t reflect that in your PlayerPrefs (when your coins reach 100).
Also, please, publish your latest code snippets since 2 versions above differ a lot.
Okay. Taking the static off of curHealth makes sense now that you mention it.
2)My maxHealth won’t stay to 3 throughout the entire game. I was just trying out something, but I’ll try setting it in the Start() too.
3)The rules are that the player starts off with level 3 health. curHealth maxHealth are both started off as 3. curHealth is the one being displayed, since it is the health that goes down every time the player takes damage. Every time the player collects 100 sets of coin, the health upgrade(the maxHealth) will go up one, and the curHealth will match the maxHealth. Now, it would take 4 hits to kill the player. The maxHealth maximum upgrade is 10, but I haven’t gotten there yet.
4)What I want to save is first the coins. It would suck for the player to go and collect 100 coins every time, without starting from the number of coins in the last sequence. But that’s solved. Next, I wanted to save the maxHealth(upgrades). I don’t think you would save the curHealth, makes more since to save the maxHealth, and on Start(), curHealth = maxHealth.
ok. All of this looks reasonable. So, are you still experiencing issues? Based on the above - you shouldn’t. The only thing is missing is if you want to persist maxHealth then you need to write a similar code for it as you did for coins. Also, you are not explicitly saving PlayerPrefs so I assume you are still relying on Unity for that.
Yeah, I’m using Save() on two quit buttons on the game. The only thing left is the maxHealth. I’ll try to play around with it for the day or so to see if I can come up with anything and update here. I should just reference the coins for help.