While developing this Phaser game, I have come across all manner of issues and problems that would likely be tiny bumps in an otherwise smooth road for those who are experts with the framework. For me, many of these obstacles have seemed like mountains. My most recent example has to do with destroying an enemy card when it dies.
Seems easy enough, right? Simply have the object delete itself when its health reaches 0. Phaser even has built-in methods for this! GameObject.destroy() and GameObject.setVisable(false) can both be used to remove objects from the user’s view, and are built-in methods in Phaser.
It was much to my dismay, then, when I tried to have a card .destroy() itself, and I was alerted that “enemy.destroy() is not a function”. It seemed like I had done everything right, what could possibly have gone wrong?
This is not the Object you are Looking for.
It turns out, that as a novice to Phaser, I had actually been programming two kind of separate objects when creating enemies, which I had mistakenly believed were the same. One was a Phaser GameObject: the kind that you can delete, move, and set the visibility of. Somewhere in my code, this GameObject existed: the enemies were clearly visible, and had been rendered as this object type.
The second type was the culprit. I had actually been programming all of the game logic surrounding enemies using a JavaScript class called Enemy. This class was straight JavaScript: though it was able to reference Phaser objects since once of its class variables was the Phaser Scene, it had no connection to the rendered GameObject that it was supposed to represent. In short, the statistics and methods of the enemy were completely separate from its visual representation.
This meant that when I was calling enemy.destroy(), the program was looking for a destroy() method in my class Enemy, instead of a method of the GameObject that was supposed to be representing that enemy.
How do we Solve the Problem?
Honestly, I still have no idea what the most elegant solution to this problem is. It is very likely that a skilled Phaser programmer would be able to handle all the enemy commands and stats through the Phaser GameObject, with no need for a separate class at all.
I am not that programmer.
My solution was to tie the GameObject representation to the instance of the JavaScript class that it was supposed to be with a class variable. Then whenever I needed to delete the enemy, I would erase both the visual representation AND the JavaScript class representation of the enemy at the same time. Simple, right?
Simple, Wrong
It turns out that connecting the two was much more difficult than first imagined. When the GameObject was initialized, it was almost a throwaway: when I created the generating code, I did not yet realize how important keeping track of it was going to be. The first step involved breaking the whole program multiple times as I tried to root out every place that referenced the GameObject version of the enemy and move it to a better place.
I then had to do some calculations and refactoring to make sure that the connection between the two representations of the enemy was intuitive. It would be very confusing for my partners if the code that referenced the GameObject and code that referenced the JavaScript Class object were seemingly aimed at separate entities. I used an index number common to both to connect the two, so that when an enemy GameObject with index 1 is being referenced, it is connected to the enemy JavaScript class object with index value 1.
In the end, this solution seems to work well enough. I wish in some ways that i could start the project over entirely with my current knowledge, but in life we have to deal with what we have been given, and what we were able to accomplish with it.
Let this be a lesson to all: always make sure that you are ACTUALLY accessing the object that you think that you are!
Leave a Reply