Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

What I Learned

Going through all of this really did help cement a lot of the things that I had really not gathered from going through the Phaser tutorials. Basically, all of the challenges I faced with that probably will not be repeated, and I will find its actions much more predictable than I did.

I additionally found out a few lessons about organizing game code. The first, and most important, is to let objects handle their own rendering/positioning, rather than doing it as part of an update loop. That is, when a party member was moved from one hex to another, I had been trying to do the positioning update right then and there. It was vastly easier to just move it to the group and then have the group "fix" its members, and it looked better in the end. It also handled taking members out of the middle of the group better.

The next is the basic way an entity-component system works with immutability. I had made small games in Clojure before, and knew the necessity of passing a state object to functions. I did not really get how this "pipeline" method of working and threading state through could be made easier, through returning an "updated" version of the state object. I really did not "get" the -> and ->> threading operators until they become so necessary to avoid writing messy code.

But in a wider sense, reasoning about what would happen on update became easier as I divided up responsibility between namespaces. I now understand that namespaces in Clojure(Script) are somewhat like the equivalent of classes in object-oriented programming languages, just that they are (ideally) limited to functionality rather than also keeping track of data as with a class. So this makes them very much like static-only classes in C#, my normal language.

So all together, if one namespace (system) determines it needs to update an entity, it can delegate the update to a different namespace, and get back the new state object, not needing to know the gory details, and move on. This made a very neat and clean pipeline. The tricky thing is that the phzr/Phaser objects are instead "mutable" rather than immutable. So that became an additional "pipeline" where a phzr object was passed off to a method, that returned the same object after it was updated. Working with those could definitely be cleaner...

Expanding on working with phzr objects, my original intention was to go very deep into splitting out object into entity components. I would have entities that had separate gameplay components and phzr object components. For example, an entity would have an ExplorationGroup component for the game-level data, and a Group component for the phzr object. That was probably an abstraction too far. I eventually needed to do one check on the game-level data, and then another call to get the phzr object to update it, and was doing this constantly, leading to repetitive code. I started just including the phzr object as a property of the game-level component, which made for much shorter code, especially when I figured out how to use map destructuring.

The last thing I feel like I learned is to strongly consider when you actually need to have things participate as an entity. Many of the components I made ended up being singletons. This added repetitive code because I would use brute's functions to get all the entities with a specific component, and then immediately pass it to first. I didn't write up a function wrapping that up until very late. Comparatively, I did not place the phzr game object in an entity and just accessed it through a normal property on the state object. That probably would have made more sense in the long run for the singletons. Basically, if you may have multiple "instances" of an object, using the entity system makes sense. But if you know you're going to have only one, ever, make your life easier and make it visible at the top as a property.

So to sum up:

  • Understand the ins and outs of your engine
  • Delegate very specific code to namespaces handling certain "systems"
  • Tie your systems into a pipeline that operate on the game state
  • Don't divide things up into components until you're sure you want to
  • Don't divide things up into entities until you're sure you want to

What I'm Going to Do Next

I do want to finish up the game, though it's going to have vastly different flavor than I originally intended, simply because I don't think it's worth me to dive down too deep into making this the most perfect game I had originally intended. It's just not a story or gameplay experience I care that much about. I'll also probably do some work to pull out the more common code into a template so I can make a Phaser game all that much quicker.

And then, make more even more games!