Jump to content

Is it possible to create an Array of objects within one State, and access it from another State?


Recommended Posts

I built a "game" that was essentially just a copy of the Periodic Table of Elements" inside of a Table with dynamically generated rows and columns.  A working example of how the "game" should work is hosted on my web site, http://literaryhodor.us/.  Except for the fact that you can't change the element being displayed when clicking on an Element within the table (I wasn't sure how to do this...which is what lead me to using States).


Each <td> (cell) within the table had an Id, which I used to return the atomic number of the element that was clicked in the table.  When an element was clicked, I wanted the atom for that element to display in the table.  That became a problem.  I could set the element to load when the canvas loaded, and it would display what I wanted.  But in order to re-load the canvas, I'd have to dispose of the canvas and create it all over again...something that I don't know how to do, and something that I'm fairly certain isn't recommended.


So I've been trying for the past hour to set up States within the game, so that I could do something like this:

		<script>			(function() {			    var game = new Phaser.Game(768, 480, Phaser.CANVAS, 'model');			    	game.state.add('Boot', PeriodicTable.Boot);				    game.state.add('Preloader', PeriodicTable.Preloader);				    game.state.add('CreateElementArray', PeriodicTable.CreateElementArray);				    game.state.add('LoadTable', PeriodicTable.LoadTable);				    game.state.add('LoadElement', PeriodicTable.LoadElement);				    game.state.add('UpdateAngles', PeriodicTable.UpdateAngles);				    game.state.start('Boot');			})();				</script>

This would allow me to do the following:

  1. Load any assets I needed beforehand (in case I wanted a menu or something),
  2. Create the array of elements,
  3. Load the periodic table (build the table cells in JavaScript),
  4. Load an element (for example, loading Hydrogen's atom at the start),
  5. Update the angles of the electrons that are orbiting the nucleus of the atom,
  6. Call the LoadElement state again when a different table cell is clicked, pass the atomic number for that element, and display it.

I think I understand how the State system works, but this is my first time using it, and so I figured there would be problems.  The way I created and loaded the element array in the CreateElementArray state was like this:

PeriodicTable.CreateElementArray = function(game) {};PeriodicTable.CreateElementArray.prototype = {    preload: function() {                function Element(number, symbol, name, mass, valenceElectrons) {            this.Number = number;            this.Symbol = symbol;            this.Name = name;            this.Mass = mass;            this.NumValenceElectrons = valenceElectrons;        }        var Elements = [];        // Element(atomic number, symbol, name, atomic weight, number of valence electrons)        Elements[1] = new Element(1, 'H', 'Hydrogen', 1.008, 1);        Elements[2] = new Element(2, 'He', 'Helium', 4.003, 2);        Elements[3] = new Element(3, 'Li', 'Lithium', 6.941, 1);        Elements[4] = new Element(4, 'Be', 'Beryllium', 9.012, 2);        Elements[5] = new Element(5, 'B', 'Boron', 10.81, 3);	// And so on...        // Output the first 5 elements to the console to verify load        var index;        for (index = 0; index < 5; ++index) {            console.log(Elements[index]);        }    },    create: function() {        this.game.state.start('LoadTable');    }};

And that's my problem...from what I understand of States, everything in here gets disposed of once the State changes, right?  Which explains why my first major hurdle is getting this exception:

Element {Number: 1, Symbol: "H", Name: "Hydrogen", Mass: 1.008, NumValenceElectrons: 1} CreateElementArray.js:139Element {Number: 2, Symbol: "He", Name: "Helium", Mass: 4.003, NumValenceElectrons: 2} CreateElementArray.js:139Element {Number: 3, Symbol: "Li", Name: "Lithium", Mass: 6.941, NumValenceElectrons: 1} CreateElementArray.js:139Element {Number: 4, Symbol: "Be", Name: "Beryllium", Mass: 9.012, NumValenceElectrons: 2} CreateElementArray.js:139Element {Number: 5, Symbol: "B", Name: "Boron", Mass: 10.81, NumValenceElectrons: 3} CreateElementArray.js:139Uncaught ReferenceError: Elements is not defined LoadTable.js:56

So it's reading the array within that State, but when it moves on to creating the HTML table in the LoadTable State (which requires this array of Elements from the previous state), it gives that ReferenceError at the point at which I try to assign the atomic number to a table cell.

var cellText = atomicNumber + "<br /><strong>" + Elements[atomicNumber].Symbol + "</strong><br />" + Elements[atomicNumber].Mass;

Ugh, I'm confused by all this, but it seems to be the only way to do what I'm trying to do. 


Where should this array of elements be stored within the State system in order for it to be accessed outside of the State that it was created in?  Even if I put the code to create the elements, the array, and the table all within the same State, whenever I call the State "LoadElement" to load a new element, it'll dispose of the table and the array, right?

Link to comment
Share on other sites

Forgive me but this seems like an overly elaborate way to do what should be a fairly simple task. In your canvas all you need to do is create a function which creates a group with game.add.group(), then add your shells, electrons and nucleus to the group, start them animating and that's it. Have another function call .destroy() on the group when you're done, and then get the original function to construct the new atom requested when your user clicks a new element. You could even rather than destroy the group just hide it (visible = false) and save it into an array so you can retrieve it again if the user clicks on an element they've clicked before.


To answer your question however, you could always create a global object (or at least an object in a higher context than the states) for anything that needs to be used between multiple states.

Link to comment
Share on other sites

That's a good idea, I hadn't thought of that.  Sometimes I try to modularize things too much...a failing that I have a hard time catching on my own, lol.


I took your advice, created an over-arching "atom" group, and then whenever the element was changed in the table, I did this:

				// If the newly clicked atom is not the same as the last atom,				if (currentAtom != lastAtom) {					// Remove all child groups from the "atom" group					atom.removeAll();					// select the new element					SELECTED_ELEMENT = Elements[atomicNumber].Number;					// Create the new atom					loadAtom(SELECTED_ELEMENT);					// Assign the current atom as the previous atom					lastAtom = currentAtom;				}

Since GROUP.removeAll() removes all children, but keeps the parent container, I can just re-use that group as many times as needed.  One problem that I ran into (more than a few times) was not realizing when the group was going to be undefined because it didn't exist in the context in which I was calling it...I gotta work on that (in JavaScript) some more, now that I'm feeling more comfortable with the language.


Thanks for your help ;-)  I'll update the web site in a moment and tinker with it some more later on.  Cheers!

Link to comment
Share on other sites


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...