Skip to main content

No Pain, No Game

For once, I am getting my wish of self-fulfillment in life by actually doing some game development.  If I had to take a stab at the factors that attributed to my success, it was a combination of integrating morning exercise into my daily routine and utilizing an easy procrastination hack to get myself started.
I have done some variation of that procrastination hack many times in my life, but the daily exercise is something I never really got around to that I should have earlier.  Exercise is easily as effective as caffeine at getting you up in the morning.  Can I Google some affirmation on that?  You bet I can.

As for how I achieved the motivation to get up on that treadmill in the first place, it's a little harder to nail, but basically it comes down to this: I can either spend half an hour on the treadmill in the morning, and be woken up enough to do something with the rest of my day, or not, and don't.  Put in such simple terms, there was no need for motivation: a significant amount of the value of my days off is being held for ransom.  You win again, physics!

Back to bit-slinging.

As I indicated in the last entry, I was really interested in giving Construct 2 a serious shakedown, because the elegance of Scirra's design really makes developing in it a joy compared to my alternatives.  However, I ended up crawling back to GameMaker Studio instead.

Part of the reason is because it suits my natural inclinations better.  I've said before that Construct 2 (and Clickteam Fusion) are probably best-employed by people whose weakness is programming and strength is visual skills, and I'm the other way around.  So, as enticing as Construct 2's sleek design is, it might not be right for me... although I am going to miss how well the intelligent code completion works compared to GameMaker Studio's rudimentary implementation.

Even more important than that is another thing I said: the engine you choose has a lot to do with the type of game you are making.  Though they endeavor to be versatile, Construct 2 and Clickteam Fusion lean very heavily on putting together action games.  Sure, like any of these engines, the developers have provided means for you to code around that, but it quickly becomes an uphill battle against what the engine is built to do.  Though GameMaker Studio is more than ready to go in the direction of an action game, the incline is significantly reduced, mostly because of the utter lack of prefab movement modes: you have to define how everything moves anyway.

This is so far from finished that virtually everything you see here
is merely a placeholder.  Thank God for David Gervais, who provides
this Tileset under a creative commons license, or I may not even
have even gotten this far.
Put that all together.  Do I want to access the code more directly?  Yes; a point for GameMaker Studio.  Do I want to make an action game?  No.  In fact, for my first game, I decided to make a traditional tile-based RPG: I figure if I like Ultima V, then I should like this, too.  Should I be using RPG Maker then?  While it would be starting much closer to that idea than GameMaker Studio, the abysmal resolution limitation (640x400) and the inability to port to other platforms makes it a bad choice for me.

Of course, there are many other options in this big world of ours.  Unity is likely capable of doing everything I need and has a great code completion implementation... but it also has a huge price tag and considerably bigger technical overhead to use.  The dirt cheap option to have an engine that does exactly what I want to do would be to code it myself, and LibGDX would be a great way to go there, but making your own engine also takes about five times as long.  The nice thing about working in something like GameMaker Studio or Unity that is you let them worry about if the engine works, your job is to create.

The first major ball breaker I encountered in GameMaker Studio.

Here I was, two days into development, drunk on power with just how easily and effectively this old school RPG I was developing was coming together.  I had groups of orcs and guards spawning at towns (completely arbitrarily) and wandering around randomly.  They would soon fill this little island I made as a testbed, not a problem in sight, this was great.  I seemed to know what I was doing, the scripts were performing exactly as I thought they would, and I was just a little overconfident.

For my next milestone, I decided that what I was going to do was have these groups of soldiers and orcs interact.  If a group collided with a different kind of group, it would create a conflict marker and their data would be absorbed into that.  If a group collided with the same kind of group, those groups would merge into a larger fighting force.  Of course, the logical place to put this collision check would be on the collision event of the objects in GameMaker Studio.
Derpy demonstrates what happens to the coder when
GameMaker Studio executes a counter-collision
with a destroyed instance.

Now, if you are an experienced GameMaker Studio developer, you are probably cringing at that last sentence.  What I did not know at the time, and eventually came to realize after hours of painstaking debugging, is that the collision event will always trigger twice, once on both instances that collided. 

It gets worse.  The other half of the puzzle turned out to be this: destroyed instances continue to run until the code that called for their destruction terminates.  Experienced GameMaker Studio developers are probably used to putting instance_exists() checks where necessary to prevent the problems this causes, but I was not yet that experienced.

It seems silly.  Why the heck would you allow code to run, AT ALL, on an object that was destroyed earlier in the step?  Well, as the instance_destroy() reference explains, it is to allow the freedom to do things like incrementing scoreboards.  If this were a lower-level programming language than GM, the second you destroy an instance of an object, it is gone, but I guess this kind of wishy washiness is a major difference between writing a script and writing code.

The way I had coded it, the code was running through every unit on the map before it terminated and executing a NPC turn processing script and, somewhere around there, the collision code on the object was run when it came in contact with another NPC.  I noticed that three things seemed to happen, and I can only guess what was causing them:
  1. The merge would seem to go through just fine.  (I see some units were above the maximum possible number of starting members, indicating a successful merge.)

    Unit A performs a random move, moving on top of Unit B.  Unit A's collision event goes off, and destroys Unit B.  Then we reached the end of the unit list, and Unit B was properly recycled.  Unit B's counter-collision event must have never run, or was misdirected somehow, because Unit A was not deleted. 

    Despite the fact that it produced the desired result, this is the most wrong of the results, because the counter-collision is always supposed to happen, so why didn't it?
  2. The merge would go through, but delete both units.  (I see both units disappear.)

    Unit A performs a random move, moving on top of Unit B.  Unit A's collision event goes off, and destroys Unit B.  Despite being deleted, Unit B's counter-collision event goes off, finds Unit A's data in tact (even though Unit B's data was wiped) and rebuilds itself from Unit A's data... then Unit B deletes Unit A.  When we reach the end of the unit list, the instance_destroy processes complete, but both units are now scheduled for deletion, and are.
  3. Attempting to merge with an already deleted unit CRASHES THE GAME.  (Or so I gather from the crash message.)

    A merge as in case #1 or #2 has already occurred earlier this turn.  Unit C performs a random move, moving on top of a scheduled-to-be-destroyed example of Unit A or Unit B, and Unit C's collision event goes off.   Despite Unit A or B being deleted, an object_is_ancestor check successfully determines that this unit is of the correct object index (possibly because that data is read only and part of the environment). 

    However, when it comes time to pull data from Unit A or B's data structures, the game crashes because it is unable to find that data anymore.  If I changed where the script was executed, it caused an, "unable to find any instance for object" error, which is closer to the truth.
The issue I had with initializing new conflicts was similar, as the code for merging had much the same mistakes going on as the code for new conflicts: units absorbed into the conflicts would try to execute their scripts, or have scripts executed on them, when they should have had nothing to do with the game once absorbed and instance_destroy() had been run on them.
This is probably the biggest issue with working with GameMaker Studio right now, that destroyed instances can interact or be interacted with at all, and I thinik solution is basically this:
  1. Use instance_exists() checks to make sure scripts are not being run on destroyed instances.
  2. Use instance_exists() checks to make sure not-destroyed instances are not trying to interact with destroyed instances.
  3. Do not use the collision event for collisions that are only supposed to be one-way.  Use instance_place() or instance_position() checks on events not triggered by a collision.
  4. Try not to run scripts that call several different instances to make them execute code.  GameMaker Studio already does that for you with events like Step or Alarm, and so this is redundant.  Scripts that call scripts probably keep all the involved variables in scope, and the instance_destroy() help document says that the instance is not properly destroyed until after the current script is completed, and this will likely include all running scripts that called that script.
In any case, this whole idea of merging units and starting conflicts was really some wobbly test code that ultimately had nothing to do with the game I was making.  So instead of resolving this properly this time, I deleted the idea of merging units (whether with each other or into conflict objects) and went back to the drawing board to decide what I really want to do here.  I should have done that in the first place instead of goofing around with the overland units.
Post a Comment

Popular posts from this blog

Ancient Warfare - What Is It Good For?

The Ancient Warfare mod for Minecraft threw me for a loop.  I was looking for "villagers" that would perform useful tasks while simultaneously resolving the glut of food with a need to eat, thereby turning Minecraft into a bit of 4X game you can play from the inside.  Millenaire wasn't quite there, partly because recent updates to Forge had broken its compatibility with Minecraft 1.7.10, and Minecolony's development is not quite fast enough to keep up with the state of mods in general (they probably need to make a core API).
In comes Ancient Warfare, which does indeed provide workers and soldiers who need to eat, you can even order around a little army of them to defeat your enemies.  It has working waterwheels and windmills, something I thought was awesome in Resonant Induction.  It has a warehouse with a built-in sorting system, as well as courier NPCs that can move things from building to building, and crafting NPCs that can create things for you automatically - w…

Resonant Induction Really Grinds My Gears... In A Good Way

From about 2pm yesterday until 8pm today, I've been dabbling with my latest custom mod mix for Minecraft 1.6.4, which is this time very much Universal Electricity focused.
Aside from the usual GUI enhancers and Somnia, the primary contenders in this mix were:
Calclavia Core - Of course: this is the base of the Universal Electricity system.Resonant Induction - This seems to be largely focused on increasingly more advanced methods of refining ores divided across 4 ages of technological progression.  It also includes some really cool things such as assembly lines.  I'll primarily be talking about just a few blocks out of this mod today.Atomic Science - A mod dedicated to generating more of those lovely universal electricity volts via the power of splitting the atom.  Build your own nuclear reactor!  Deal with nuclear meltdowns!  You maniac!ICBM - A mod dedicated to generating more destruction using those lovely universal electricity volts (and more than a little gunpowder), it cer…

Stars Above, Earth Below

Now Playing: Stellaris This week saw me revisiting Stellaris, which just released a major overhaul which primarily made it so you have to path through stars in a certain order, allowing for better fortification.  Aside from that, though, how much has the game played since I last played it?
Honestly, maybe it is the fact that the only major game-changing DLC I have is the Utopia expansion, but I feel Stellaris not changed enough; Stellaris remains an excellent storyteller, but only lackluster 4X game.  Some standout gameplay impacts I noticed:
The new emphasis on starbases, their building and upgrading, is a major game changer.  You now have a whole extra source of food and energy that can be generated by them, and an upgraded starbase with defense platforms is basically a doomstack that thwarts invasion through that chokepoint node.Warp travel is so slow that it takes years for my fleets to get anywhere.  Perhaps, once I unlock the warp gates, things will speed up a bit.  As a result…