I’m coming from PHP, where things like this is very simple. I also think I’ve done this in regular JS before, but that doesn’t seem to apply here. I’ve been trying for two days now, googling and searching on this forum, testing everything I can find. But still I can’t figure this out.
I’m reading lines from a text file. The text file contains the names of game objects and data for each game objects. I want an array, with dynamically created keys, that looks like this:
I would do it using a custom class, not a multi-dimentional array.
class myClass(){
var description:String;
var actionwhenclicked:String;
var hurr:String;
function myClass(description:String, actionwhenclicked:String, hurr:String){
this.description = description;
this.actionwhenclicked = actionwhenclicked;
this.hurr = hurr;
}
}
import System.Collections.Generic;
var myArray:List.<myClass>;
function Start(){
myArray = new List.<myClass>();
myArray.Add(new myClass("descfromfile1", "push", "durr"));
Debug.Log(myArray[0].description);
}
However, you can of course use a Multi-Dimensional array. or a Multi-Dimensional list or even a Dictionary.
import System.Collections.Generic;
var mArry:String[,];
var lList:List.< List.<String> >;
var dList:List.< Dictionary.<String, String> >;
var dDict:smile:ictionary.<String, Dictionary.<String, String> >;
function x(){
// MArray does not do lookups
mArry = new String[10,3];
mArry[0,0]="mArry Test";
Debug.Log(mArry[0,0]);
//Lists are indexed and expandable
lList = new List.< List.<String> >();
lList.Add(new List.<String>());
lList[0].Add("lList Test");
Debug.Log(lList[0][0]);
// dictionaries are great lookups.
dList = new List.< Dictionary.<String, String> >();
dList.Add(new Dictionary.<String, String>());
dList[0].Add("index", "dList Test");
Debug.Log(dList[0]["index"]);
// dictionaries are awesome.. just so you know
dDict = new Dictionary.<String, Dictionary.<String, String> >();
dDict.Add("headIndex", new Dictionary.<String, String>());
dDict["headIndex"].Add("subIndex", "dDict Test");
Debug.Log(dDict["headIndex"]["subIndex"]);
}
First, UnityScript or what some (even unity) calls javascript, looks like javascript, it doesn’t implement what a web developer is used to when it comes to javascript, it uses a BOO compiler to build out the final assembly. Anywho, technically and for readability it would be better to create a class to represent each item/entry in a collection(array).
import System.Collections.Generic;
private var FileEntries : List.<FileEntry> = new List.<FileEntry>();
// Javascript/UnityScript
class FileEntry {
var Description : String;
var ActionWhenClicked : String;
var Hurr : String;
// Constructor to make making objects easier;
function FileEntry ( desc : string, action : String, hurr : String ) {
this.Description = desc;
this.ActionWhenClicked = action;
this.Hurr = hurr;
}
}
function LoadFileStuff(file : string) {
// blah blah blha loading file blah readline or however you do your file streaming
// some while look while seeking/peeking into a file and reading the line into a string or something
// LOOP
FileEntries.Add(new FileEntry(dsc, act, hur));
// END LOOP
}
Now, i have no idea what your expectations are from reading/streaming a file, so the above will not work out of the box, so please don’t copy and paste and assume this is working code. At the very least i don’t know what your file format looks like. But instantiating a type and adding it to a collection is much better then dynamically creating stuff, which is very non-specific.
.net is type safe or whether you are explicitly setting the type or doing it through inference, when an assembly is created in .net, it’s strongly typed. The exception to this is COM programming and the dynamic keyword which you will not use.
Great! That last one seems closest to what I’m looking for. But is there a way to add indexes (= keys in PHP?) with dynamic names? Can I do something like this (pseudo code)?:
var keyvar = stringlinefromtextfile;
dDict[keyvar].Add("desc", "long description");
Landern: Thanks. I can work with this. Maybe I should have explained further in my first post. This is what I’m doing.
I have a script that checks if the mouse is over an object, each object have a name that matches a name in my text file. So if I mouseover ‘Apple’, the script should look in the dictionary, find the corresponding key/index/what have you and read its description etc.
Like this:
on mouseover:
get objectname;
var currentdescription = objectdata[objectname]['description'];
var currentclickaction = objectdata[objectname]['clickaction'];
Is there a way to set up the dictionary so that this is possible?
That is what bigmisterb did in the second example in the above post.
var dDict:smile:ictionary.<String, Dictionary.<String, String> >; //<-- this part
in this case you would after instantiating and filling the Dictionary, you can look up values like:
// var for found value in dic
var result : Dictionary.<String, String>;
if ( dDict.ContainsKey("Apple"))
result = dDict["Apple"]; // Returns a dictionary of type Dictionary<string, string>
if (result != null)
Log.Debug(result.Key + " " + result.Value);
So how do I populate the dictionary using the data from the text file? I want the keys to have names read from the file and so far I haven’t been able to set a key name using a variable. Or maybe I’ve been confused by some other error?
var keyvar = stringlinefromtextfile;
dDict[keyvar].Add("desc", "long description"); <<keyvar
I’ve managed to parse the text file, I just need to create keys and values from that data. The text file looks something like this:
Start:Apple
Action:pickup
Description:You can't go alone, take this apple
End:Apple
The thing I still can’t figure out is how to create dictionary keys with strings taken från the textfile. Lets say I get a variable from the text parser that contains the string ‘Apple’. Now I need to dynamically create the dictionary key with the name of ‘Apple’:
keyvar = 'Apple'; (from text file)
dDict[keyvar].Add("desc", "long description"); <<keyvar
I need a dictionary that looks like this:
var allobjectdata['Apple'] => 'Action' => 'pickup'
'Description' => 'You can't go alone, take this apple'
Sorry, I’m a JS/US noob, I’m probably not explaining this very well. I only have problems creating dynamic dictionary keys.
In essence you ahve to build your Dictionary as you parse your text. you split it by line, then split each line by :'s
Then you start parsing. If it is Start, then you add a new entry (if the entry does not exist), you will have to store the key.
// check your end (will be listed later)
Each time you hit an entry, you will need to store that entry into the dictionary under that key. (replace it if it already exists) store that key as well
if it is the end, you will need to clear your last key (to be safe)
If you can’t find a : then you should add the line to the last key you used.
Have a go at it, post your code and see what you come up with.
Hint: I already created a working copy of it, but I want to see what you come up with.
You had a pretty good go. But I am finally back at work now. (where the code is. )
As promised:
var trimLetters:char[];
function ParseText(text:String):smile:ictionary.<String, Dictionary.< String, String > >{
if(trimLetters == null){
var a:Array = new Array();
a.Add(" "[0]);
a.Add("\n"[0]);
a.Add("\r"[0]);
a.Add("\t"[0]);
trimLetters = a.ToBuiltin(char);
}
text = text.Replace("\r", "\n");
text = text.Replace("\n\n", "\n");
var b:String[] = text.Split("\n"[0]);
var dic1:smile:ictionary.<String, Dictionary.< String, String > > = new Dictionary.<String, Dictionary.< String, String > >();
var key:String;
var lastKey:String;
for(var c:String in b){
c = SuperTrim(c); // Supertrim will trim the white, new lines and tabs.
var d:String[] = c.Split(":"[0], 2); // split it now by the :
d[0] = SuperTrim(d[0]);
if(d.Length == 2){
d[1] = SuperTrim(d[1]);
if(d[0] == "Start"){
key = d[1];
if(!dic1.ContainsKey(key)){
dic1.Add(key, new Dictionary.< String, String >()); // if the main dic does not contain the key, add one.
}
} else if(d[0] == "End"){
lastKey = ""; // if you are in the end, you should clear the keys you are using
} else {
lastKey = d[0];
if(dic1[key].ContainsKey(lastKey)){
dic1[key][lastKey] = d[1]; // replace it if its already in use.
} else {
dic1[key].Add(lastKey, d[1]); // add if you dont have it.
}
}
} else {
if(lastKey != ""){
if(dic1[key].ContainsKey(lastKey)){
dic1[key][lastKey] += "\n" + d[0]; // if you have it, add a line to it.
} else {
dic1[key].Add(lastKey, d[0]); // if you dont have it, add the entry (this should never happen)
}
}
}
}
Debug.Log(dic1["Apple"]["Description"]);
return dic1;
}
function SuperTrim(text:String){
//return text;
if(text == "")return text;
var a:String = text;
var x:int = a.IndexOfAny(trimLetters);
//Debug.Log(new Array(x, a));
while(x == 0){
a = a.Substring(1);
//Debug.Log(new Array(x, a));
x = a.IndexOfAny(trimLetters);
}
x = a.LastIndexOfAny(trimLetters);
//Debug.Log(new Array(x, a));
while(x == a.Length - 1){
a = a.Substring(0, a.Length - 1);
//Debug.Log(new Array(x, a));
x = a.IndexOfAny(trimLetters);
}
return a;
}