Best way to create a dynamic container (JS Array, List, Hashtable) in an iOS game?

I have a js that works as a board manager (I hope I’m right at thinking that that’s how this type of scripts are called), in my board (obviously…) game.

On each board square (there are 48 of them) I have an empty gameObject, with just a box Collider and a Rigid Body component (so, 48 gameObjects of this kind). The tag of each of these empty gameObjects, changes between “empty” and “full”, depending on if there is an object on them (the object I control or collectibles/ tokens).

Whenever a square is empty, thus it’s tag being “empty”, I want it to get into a container (JS Array, Hashtable or List) of the board manager.

I was thinking of using something like:

static var emptySquaresArray = new Array ();

and have on each of the 48 empty gameObjects on the board squares, a script attached, that will tell it to be pushed into the Array, if it’s tag is “empty”. Then again, I’m not sure yet about how I’m supposed to remove that specific gameObject from the Array, when it’s tag becomes “full”. Probably I’ll use the Array’s current lengh (exactly after the object is pushed into it) and use that (minus 1) as an index in Array.RemoveAt to remove that same object from the Array.

What I would like to know before I try to implement this, is if you think there is a better way, so instead of using Array I’d better use List or Hashtable.

What’s important for me is low performance cost, as the game is targeted to iOS devices primarily.

If at all possible, try to use built-in arrays rather than javascript arrays. Built-in arrays perform much faster, but do not allow you to change their size at runtime without re-creating the array completely. That said, if your board always has 48 tiles, why not just have a built-in array of 48 booleans. True = occupied, false = empty. If you need to keep track of more data than just a single bool, then I would make a “tile” class that has all relevant info you’ll need to have access to, and make an array of 48 of this custom class.

If you need a dynamically-sized array, always use List or Dictionary instead of Javascript Array or HashTable. The only reason to use Array or HashTable is if you were storing more than one type in the same array, but I can’t think of a case when I’ve needed to do that.

–Eric

Thanks guys. I am thinking that I indeed needn’t change the size of the Array, as MikaMobile kindly suggested. I’ll create a bult-in Array of size 48, containing all the box-collider-objects’ booleans. I guess these booleans will be static variables, each inside a script attached to each of the box collider objects.
What I want is, to instantiate (say every 4”) a predefined gameObject (a collectible) at a random empty square. I will check if a square is empty, using a boolean in the script of each box collider object like eg:

var emptyOrNot: boolean = true;

The Array each moment, will be comprised of some booleans equal to true and some to false, 48 in total.

Now what I should do, is pick a random boolean between the ones that are true and instantiate the predefined gameObject (a collectible) at the position of the box collider object that this boolean refers to.

If the empty squares where known (and their status wasn’t supposed to change at runtime), I would instantiate the predefined collectible this way:

Instantiate(spawnedCollectible, emptySquares[emptySquaresArrayLenght].position, Quaternion.identity );

Where:
spawnedCollectible is the predefined collectible that will be instantiated
emptySquares is the Array of empty squares
emptySquaresArrayLenght is an int equal to emptySquares.lenght

How can I connect the boolean to the box collider object that it refers to? I mean that I will have an Array comprised of the Booleans and what I want, is instantiate a collectible at the position of one random box collider object that the randomly selected boolean refers to.
What I was hoping for, was a functionality similar to the one which “Array.filter(function)” described here offers, but I guess this doesn’t work in Unity (?)

If the board doesn’t change during the game then you should be able to devise a numbering scheme for the squares. You can then store the GameObjects in one array and the booleans in another. Each square’s number will be the same as its array index.

Thanks for the suggestion andeeee.

Wouldn’t using List class be quite simpler though? I’ve recently learned that now (since unity 3.0) one can use List in js, with some small differences (eg using List. instead of c#'s List).

So wouldn’t using a List (in js, as I’d prefer staying in that instead of learning c#) the size of which is modified in every movement, destruction, instantiation of collectibles, be the simplest and less cpu intensive solution?

The list will constantly contain the box collider objects tagged “empty”, as the box collider objects will have a script that will put them in the List if their tag is “empty” and remove them if their tag becomes “full”. I will then be able to randomly spawn (every 4") a collectible in the position of one of the List’s contents (which are all the “empty” tagged board squares).

Since it sounds like you want to keep track of both a “occupied” state, as well as a reference to a collider, and maybe a transform, what I’d do is make a “tile” class, and a built-in array of 48 of this class.

class boardTile {
     var tileCollider : Collider;
     var tileTransform : Transform;
     var occupied : boolean;
}

var tileArray : boardTile[];

You can populate the array in the Unity inspector pretty easily, or via script if you’d rather automate it. Accessing the properties of this array is as simple as the following…

// I want to check some information about tile #23...
if (tileArray[23].occupied == false) {
     // do stuff to tileArray[23].tileCollider, or access tileArray[23].tileTransform.position, etc.
}

I’ve been using built-in arrays of classes like this a ton lately - they perform very quickly, and IMO add great readability to your scripts, and are fully visible in the inspector which can be a nice bonus. And if you ever decide later that you need to store more information about specific tiles, you can just add more properties to the class. It’s much safer and easier to keep track of than maintaining multiple parallel arrays.

Thank you very much MikaMobile. Really - really useful and thorough answer!

So I check if the boolean of tileArray[23] is true (which means it’s occupied) and since I want to spawn a random collectible on one of the unoccupied squares, I will remove this from the Array (using tileArray.RemoveAt(22); I guess). When it’s boolean becomes false again (which means it’s unoccupied) I will want to add it again to the tileArray (using tileArray.Push(boardTile); ). After pushing it, it will have a different index (the last of the Array) correct? How am I going to remove it the next time I need to? It’s index will change again and again (as a result of the other tiles being occupied and unoccupied in the meantime) and I will need to know it every moment, in order to use RemoveAt.

This is why I have come to believe that the List class would be a better solution.

Is there a way to add and remove tiles from the array? My purpose is to have (at every moment) an array of only the empty tiles and spawn a collectible every 4’’ in a random tile of the array.

EDIT: Could I use this approach?:
never remove/ add tiles from/to the array and whenever (every 4" basically) I need to spawn a collectible on a random empty tile, make the instantiation happen randomly on one of the tiles between only those that have a false boolean (so eg select one of the 15 unoccupied tiles out of the 48 in total) and not between all the contained tiles of the array. If yes, what syntax would I use?

I would go with your second suggestion - never actually change the size of your array, so each tile has a specific index associated with it. If you just want a random, unoccupied tile, you could use a simple loop like this. It just rolls a random number, checks to see if that particular tile is flagged as occupied or not. If not, it just loops again and again with a new random number until it finally finds one that’s a valid choice.

var spawnSuccessful = false;
var randomNumber : int;
while (spawnSuccessful == false) {
     randomNumber = Random.Range(0,tileArray.length);
     if (tileArray[randomNumber].occupied == false) {
          // spawn a collectible at tileArray[randomNumber].tileTransform.position
          spawnSuccessful = true;
     }
}

If you want to maintain a minimum tile distance between collectibles, that gets a bit more complex, but its just a matter of adding additional conditions and keeping track of more information. In the end there are a lot of different ways you could structure something like this, but in regards to performance the only thing I’d strongly urge is to avoid javascript arrays (which means committing to arrays of fixed length).

While in this case I don’t see a reason to avoid fixed-length arrays, just as a point of info, using List in some cases (such as a List of GameObjects) is barely slower than a GameObject[ ] array. When it comes to basic types like int, a fixed-length int[ ] array is still somewhat faster than List., but in all cases, List.<> is much faster than Javascript Array. There’s basically no reason to use Array, really. If it would complicate the design too much to use a fixed-length array, just use List.

–Eric

Thank you so much MikaMobile Eric, I’ll try both suggested approaches today. I really appreciate your analyses on the subject!

hey - just whilst on this topic, I also have a game where all the gamepieces are stored in an array.
I had already taken the approach mentioned here (always nice to know you’re on the right track!)

But often, I’m wanting to lots of checks against subsets of all the pieces.
There are on average 144 pieces in the constant array.
Would creating a new array at run-time and iterating over this subset be quicker than the checking over the 144?
In other words… how expenses is the actual creation of an array at run-time on an iOS device?

Thanks! :slight_smile:

Using the ‘class boardTile’ from above I’m running into this error: ‘animation’ is not a member of ‘boardTile’.
when I try to play an animation with tileArray[whichOne].animation.Play(“selection_on”);
and adding var animation : Animation; to the class doesn’t generate any errors, but it doesn’t work either :confused:

is this possible?

EDIT
derp, it’s in there, I wasn’t hitting it properly.
tileArray[Convert.ToInt32(whichOne)].selected.animation.Play(“selection_on”);