- Home /
Preserve data within a scene
I'm making a game (specifically a top-down shooter) where there is a main area and several sub-areas saved as separate scenes. This has lead to a problem: if I kill an enemy in the main area, going into a side area, and then come back into the main area, the enemy will still be alive as if I'd never killed him. This is obviously problematic.
I've previously done this with static variables, but the problem here is that all the enemies are prefabs and use the same scripts, and I haven't successfully implemented a manifest-esque script (like the one suggested here). So, in brief, is there a way to keep track of enemy information like position and whether they're alive or dead so that when the player leaves and comes back to a scene, the enemies he killed stay dead?
Here's the code I have so far of the script to remember enemy positions, just in case there's something incredibly basic I'm missing.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class EnemyStorage {
public Vector3 lastPos;
public bool dead;
public EnemyStorage(Vector3 pos, bool d) {
dead = d;
lastPos = pos;
}
}
public class EnemyPositionsCompound : MonoBehaviour {
public static List<EnemyStorage> enemySaves = new List<EnemyStorage>();
public static GameObject[] enemies;
private bool correctLevel;
private static bool hasBuiltList; //check to see if the list has already been built
// Use this for initialization
void Start () {
Debug.Log("checking enemies "+" has build list? "+hasBuiltList);
//check to see if we're on the right level
if (Application.loadedLevelName == "Compound") {
correctLevel = true;
}
else {
correctLevel = false;
}
//if we are on the right level, run the shit
if (correctLevel) {
//get all enemies in the scene
enemies = GameObject.FindGameObjectsWithTag("Enemy");
if (!hasBuiltList) {
foreach (GameObject e in enemies) {
Debug.Log(e.name);
enemySaves.Add(new EnemyStorage(e.transform.position, e.GetComponent<EnemyHealth>().dead));
}
hasBuiltList = true;
}
foreach (EnemyStorage s in enemySaves) {
Debug.Log("Enemy status: "+s.lastPos+" "+s.dead);
foreach (GameObject e in enemies) {
if (s.dead == true) {
e.GetComponent<EnemyHealth>().dead = true;
}
}
}
}
}
// Update is called once per frame
void Update () {
}
}
You are assu$$anonymous$$g GameObject.FindGameObjectsWithTag("Enemy");
always returns a list in the same order as before.
Your foreach
loops won't work. You take an EnemyStorage. Then you go through all enemies and set them all to dead if the save is dead. So a single dead save will set all enemies to dead. There needs to be a way to tell which enemy corresponds to which save, like a unique ID.
Answer by Baste · Dec 04, 2014 at 01:36 PM
PlayerPrefs is your friend! It allows you to store quite a lot of data to disk, without slowing down your application in any way. You can use the current level and some kind of enemy ID to give the enemies unique identifiers, and then you simply save them being dead on death.
So, if you put this on your enemies:
//Needs to be unique for every enemy on the same scene.
public int myId;
string playerPrefsString;
void Awake() {
playerPrefsString = Application.loadedLevelName + "/" + myId;
if (PlayerPrefs.GetInt(playerPrefsString) != 0)
Destroy(gameObject);
}
void Die() {
PlayerPrefs.SetInt(playerPrefsString, 1);
//Do the other death stuff!
}
That'll make sure that they stay dead when returning to the scene. You can use SetFloat and GetFloat in the same way to save and retrieve the enemy's coordinates when returning - I'll let you figure that out yourself.
Oh, and if this is the only thing you're using playerprefs for, you can reset the saved states when restarting the game with PlayerPrefs.DeleteAll(). Otherwise you'll have to write your own reset function.
Hope that helps!