PlayerPrefs Missing Arrays ??

Is this true… I don’t see anything in the Documentation and it complains if I try and pass an Array as a String. I know, it’s a hack! : )

I need to keep track of about 50 player variables and it would be a lot easier if I could just stuff the data into an array. Anyone have a simple workaround other than 50 unique strings/ints or using a whole file IO type thing?

Combine the data into one string, using commas (or some other character) as a delimiter, and write that. Then you can split the data when you read it back in.

–Eric

Yeah, i hate having to resort to that as it will push my programming skills to the limit ; )

Edit: This leads to one of the ugly points in Unity documentation… it’s not documented. String has no info on any other functions:

String Class

string Initializes a new instance of the String class…
Length Gets the number of characters in this instance.

I have found other stuff in other people scripts that I guess come from .Net or some other random location.

String class

Unity’s documentation only covers Unity classes, but since those are just a subset of Mono (edit for clarity: built on top of Mono, not part of Mono as such) you have access to most of the .NET framework as well (whatever had been implemented as of the version of Mono used - 1.2.5 in this case, which is most of .NET 2.0).

That means for anything that’s not specifically a Unity class, your source for documentation is MSDN, and it really is an excellent resource to have. You can also find much of the same information in the Mono class library here, plus whether a given class is implemented in Mono or not. The only caveat with the Mono docs is that they’re incomplete in many places, so MSDN is a better first stop.

Too bad it doesn’t highlight the code so we know what it supports and what it doesn’t - I mean without going to research it!

Either way, I appreciate the help and the links - thx.

put the code in, save, switch to the editor: you will know right of if it works

haha - dreamora… that’s a very elegant solution and so efficient : )

Okay now I’m back to stupid land: I need to split a string and I get the basics but I am not sure how I would take a WWW data string for example and split it into name/value pairs.

Say this is the returned string:
skill_level=1&name=SE7EN&score=500000&game_time=25.35&level=8&kills=270&deaths=4&accuracy=75

I could just format it like so from PHP:
1,SE7EN,500000,25.35,8,270,4,75

and make and Array to use the data
var skill_level = data[0];
var name = data[1];

but this seams pretty lame to me. Not inefficient, just kind of sloppy. I just have no idea how I would get name/value pairs from a string. If there’s not a simple solution I will just use sloppy because it will work : )

Untested (edit: now it is tested) from the top of the head code:

For clarity the code is bit too verbose.

Hope it helps :slight_smile:

function Start()
{
var s = "key:value;name:Jacobs;age:30;";

Debug.Log("Parsing data from: \n" + s);

var valuePairs = s.Split(";"[0]);

var keysArr = new String[valuePairs.length];
var valsArr = new String[valuePairs.length];
var counter = 0;

for (var pair : String in valuePairs)
{
  if (counter == 0)
  {
    // First pair will be: "key:value"
    // You can have special logic here if you need?
  }
  if (pair.IndexOf(":") != -1)
  {
	  var data = pair.Split(":"[0]);
	  var key = data[0];
	  var val = data[1];
	  Debug.Log("Key: " + key + ", Value: "+ val);

	  // Fill arrays? Or do something else with the data
	  keysArr[counter] = key;
	  valsArr[counter] = val;

	  counter++;
  }
} 
}

Tri3 thx! At least it wasn’t as simple as I though it would be : )

I miss Flash type objects/arrays the most I think. Things like easy multidimensional Arrays but the biggest is dynamic naming to call objects or any variable.

You could set a var named “David” by saying “Davi”+next_letter = 5;

Or, if I have 5 GOs named “star_destroyer_1” thru “star_destroyer_5” in the scene you could just use…

parent["star_destroyer"+i] or this[star_destroyer_"+i]

I hate that you have to expressly search for an Object by name in Unity JS even though A. the prefab has a name and B. it has an instance name. It has caused my so many headaches and long nights. Being able to evaluate any expression anywhere made the scripting so much more flexible. Maybe thats why the runtime is so much slower now that I think about it ; )

I made it look more difficult that is by making it a hashtable/dictionary instead of array, I am sure you see the point anyway.

I think the best way to do this in Unity is to use tags:

Actually, I haven’t used them much myself, but that is the impression I have got from following the forums :slight_smile:

Tags and GameObject.Find are very slow performance wise. Plus you have to tell Find the type of object a lot of times which is even stupider ; ) The general rule of thumb is to set them up at the beginning of the game or start of a level, etc. because using them in real-time will be a frame rate hit. Theoretically then Prefabs really aren’t effecient even though they are the cornerstone of Unity development.

It just seams like Unity should have a registry of named Objects in the scene at all times. You should be able to code:

Scene.star_destroyer.transform.position = Vector3(0,0,0);

or

Scene[star_destroyer]transform.position = Vector3(0,0,0);

or even better just:

star_destroyer.transform.position = Vector3(0,0,0);

without expressly telling what object you are looking for and what kind of object it is. It should just know afterall it *f___ing made it : ) haha, this is obviously a “hot button” issue for me. I can’t see how a game engine so advance and elegant as Unity could be missing such a simple protocol.

If the GameObject is not there and the engine throws an exception that fine because thats just bad programming to be trying to call something that doesn’t exist or is the wrong type for what you intend to do with it.

Maybe I am overlooking some core performance issue but I would love to know why it doesn’t do these simple things.

The other thing that severely annoys me is that any code in the Assets folder has to all be compiled without an error before you can move on. Say I worked on a script and moved it to an “Unused” folder and it is NOT linked to any active GO, why the hell does it need to compile!? Maybe I have changed vars since then but I am keeping the code handy because I just might need in the next day or two.

On the same front why does it add textures to a build that are NOT on an active GOs or GOs that are linked anywhere in the scene? I make temp texture for something to see the UV alignment and then replace it with the final texture. The next build I run I see it being added. Why?

Flash is just much smarter in some circumstances like this. If you intend to use something not in the scene you set it to be linked. Otherwise it doesn’t compile with the run time build, that would just be a waste of space.

Believe me I am a huge fan of Unity but they need to be more conscious of the fact that hundreds of thousands of Flash developers would buy Unity if they made it feel more intuitive.

The fact that you cannot control when scripts Awake, Start, etc. fire is also a mystery to me. Why not just have a layer order like Flash/Director so that you know for a fact they run in sequence?

There are workarounds for all of these issues, but without them the software SHOULD be much cheaper if it takes every programmer days to get past these problems plus is litters the forums with stupid questions. I know I have asked more than my fair share : )

So again why can we not store an Array in PlayerPrefs - thats user friendly.

back to work haha

thx again Tri3

Yes, GameObject.Find is slow. But as I understand Tags is the way to go if you do not want to create a manager class and worry about nullpointers if “starship” is destroyed by a some quick hack mine script that does not tell the manager to remove the starship from the list…

These are all different coding practices, not one is necessarily any better than the other. Depends on preference, I guess :slight_smile:

EDIT: After writing this, I made some tests and it seems indeed that if you want to find one specific go by name tags really is NOT the way:
http://forum.unity3d.com/viewtopic.php?t=21374

If you’re not expecting to hit the player pref size cap, you could also do the lazy approach and serialise a data class to a byte array, encode it and then store it in a single player pref entry.

Notice that this will take up more space than most other methods, but when it is up, you needn’t modify your save/load code when adding new factors - just add another variable to your data class.

Heres some snippets for anyone interested:

		public byte[] GetData()
		{
			MemoryStream memoryStream;
			BinaryFormatter binaryFormatter;
		
			memoryStream = new MemoryStream();
			binaryFormatter = new BinaryFormatter();
		
			binaryFormatter.Serialize( memoryStream, this );
			memoryStream.Close();
		
			return memoryStream.ToArray();
		}
		byte[] data = libraryAsset.GetData();
		
		encodedData = System.Convert.ToBase64String( data );
		PlayerPrefs.SetString( "Current library", encodedData );
			assetData = PlayerPrefs.GetString( "Current library", "Not available" );
			if( assetData != "Not available" )
			{
				asset = Asset.LoadFromData( System.Convert.FromBase64String( assetData ) );
			}
		public static Asset LoadFromData( byte[] data )
		{
			Asset asset;
			MemoryStream memoryStream;
			BinaryFormatter binaryFormatter;
			
			memoryStream = new MemoryStream( data );
			binaryFormatter = new BinaryFormatter();
		
			asset = binaryFormatter.Deserialize( memoryStream ) as Asset;
			
			return asset;
		}

Angry - that was way over my head but thx : )

Tri3 - thanks again for the code help. It too is over my head but at least it is working 95% of the time.

Any idea why the data would get changed from PHP return string to when it is split in Unity… this is sooo bizarre.

PHP return:

player_ranking=4&num_players=6&leader_name=MOEDANGER&leader_score=1650225...

then when splitting the string it keeps saying that:

player_ranking=6
num_players=6

I have triple checked that it is not being overwritten elsewhere. I also know that the WWW is updating some of the data beacuse I can change the scores in the database and a new leader name shows up in Unity.

This is the current script:

function LeaderDetailsToArray(_string : String) {

var valuePairs = _string.Split(""[0]); 

var keysArr = new String[valuePairs.length]; 
var valsArr = new String[valuePairs.length]; 
var counter = 0; 

		for (var pair : String in valuePairs) { 
  			if (counter == 0) { 
    		// First pair will be: "key:value" 
    		// You can have special logic here if you need? 
  			} 
  			if (pair.IndexOf("=") != -1) { 
     		var data = pair.Split("="[0]); 
     		var key = data[0]; 
     		var val = data[1]; 
     		Debug.Log("LDTA Key: " + key + ", Value: "+ val); 
			
     		// Fill arrays? Or do something else with the data 
     		//keysArr[counter] = key; 
     		//valsArr[counter] = val;
     			
     			if (key == "player_ranking") { online_ranking = val; }
     			if (key == "num_players") { num_players = val; }
     			if (key == "leader_name") { online_leader_name = val; }
     			if (key == "leader_score") { online_leader_score = val; }
     			if (key == "leader_efficiency") { online_leader_efficiency = parseFloat(val); }
     			if (key == "leader_accuracy") { online_leader_accuracy = parseFloat(val); }

     		counter++; 
  			} 
		}
		leaderboard_details_loaded = 1; 

}

If anyone can see the problem I would be grateful!

nm - I got it! I must have been very tired because I was missing an “=” in the send data that went to php - when I tested it in the browser I must have put it in myself like a dumb ass : )