Dev Log Entry 7: Am I reverse engineer now?

This is a dev log about creating a game called Newtius in GameMaker Studio 2 (Indie edition). Starting with entry one might make this easier to follow.

I mentioned in entry 6 I would cover how to host the GMS2 generated HTML5 versions of games in my next post but this has been postponed.

As always, the Official newtius project page on itch.io is up, featuring the last playable version.


I was going to keep working on Newtius a while and fumbling my way from one incremental step to the next. Actually did do that to some degree. I ended up with an infinitely spawning new enemy that eventually crashes the game and makes my PC fans ramp up to 11. I can only imagine what would happen if I just set it run. Probably nothing good.

I was going to experiment on my own for a while because seemed like a good path to further learning: without too much assistance.

After feeling a little frustrated with the results of last night I decided instead to go back to the old “Space Rocks” tutorial.

Okay let me back up a second. I believe the YoYo (GMS2 developers) tutorial for “Space Rocks” – a clone of Asteroids – was the first tutorial I ever tried to follow with GMS2.

What you have to keep in mind is that there are two developer mode options in GMS2: the “Drag-n-Drop” mode (where you literally drag and drop blocks and fill in values) and the “GML mode” for writing in an actual programming language. Called GML.

For Space Rocks I followed the DnD edition of tutorial, but there’s also a GML version of the tutorial in both written and in YouTube video form.

What I didn’t know at the time is that a) the written and video versions of these tutorials are written/created by two entirely different authors and b) the written version gets updates while the video versions apparently do not. Which means that Space Rocks tutorial from 2016 isn’t nearly that helpful any longer (the language and UI of GMS2 has changed as you would expect).

What I was only somewhat aware of is that there is follow-up YouTube playlist for adding on to and enhancing that first version of Space Rocks called Space Mods. But only in YouTube form.

So my plan, such as it is, is to open my GML edition Space Rocks project in one GMS2 window then open a fresh/blank GML project is a second GMS2 window and one step at a time write my own version of that DND Space Rocks in GML form. And if I learn some things that I can apply to Newtius then so much the better. And if there’s time document what I learn and how I implement it along with way in this post. We’ll see.

(Later)

The above plan didn’t quite go as I would have hoped. I did learn something I didn’t know though.

First of all – this part I did know – if you choose a DND project you can’t convert the whole project to that of a GML project but you can convert individual blocks to the language which is a one-way conversion. If you haven’t used GMS2 it’s hard to explain.

Anyway, the thing I didn’t know about was the “live preview” window that could be popped out from a DND block. This is effectively a conversion from DND to equivalent GML code but it’s read only. Which is fine actually because I was just reading it anyway.

It makes sense logically there would be a no-commitment form of GML preview for DND projects because when the compiler throws an error it still gives you a line/column number of the issue which the DND mode doesn’t have, making such information rather worthless. Too bad the compiler output window couldn’t just say use live preview to find the error. Too much to ask, I guess.

So this is what I did with my original Space Rocks DND project: I opened it in one GMS2 window, then create a new GML project – creatively called meteor invasion (I misspelled “invasion” but lets not get bogged down in details) – and proceeded to go object by object and room-by-room re-creating the project in GML.

When I had my version of the GML space rocks project and tried running I was glad and somewhat surprised it actually worked. Except for the asteroids. Asteroids weren’t spawning for some reason.

Okay I actually cheated at some point: the generated GML code was using “bitwise operators“. I didn’t understand those 20 years ago in C programming class and I don’t understand them any better now.

Anyway, here is the example of the code:

// GMS2 generating draw code for me with bitwise operators
// the variable names were actually generated, I came up with
// iBitWiseStore on my own
draw_set_colour($FF00FFFF & $ffffff);
var iBitWiseStore=($FF00FFFF >> 24);
draw_set_alpha(iBitWiseStore / $ff);
			
// Draw Transformed Value
draw_text_transformed(250, 100, string("SPACE ROCKS") + "", 3, 3, 0);
				
// Set Draw Colour
draw_set_colour($FFFFFFFF & $ffffff);
var l35CBC932_0=($FFFFFFFF >> 24);
draw_set_alpha(l35CBC932_0 / $ff);

Yes, it’s code like
var l35CBC932_0=($FFFFFFFF >> 24);
specifically that I’m referring to. And what’s the deal with that variable name, anyway?

So executive learning decision made.

Just follow the GML one

Given the bitwise operations going on in the code, I am instead now going to go through the written version of the Space Rocks GML edition code and try and make it match and as best I can so I can move on to the Space Mods follow up. Hopefully this written version will have a minimal amount of binary operators.

(Later)

I made it to the end of the GML Space Rocks tutorial and adopted it to my generic custom project, Meteor Invasion. It’s entirely functional with sound effects, music, an explosion effect and a title, win and game over screen.

I did learn a few things about about properly spawning a specific number of objects as well as spawning them outside of a radius of the player character.

More details

I don’t think I’m going to go into detail on all the code in every object. Just a few things studying this code I think clarified for me.

As I mentioned when I attempted to add a new enemy with goal of only four or five enemy objects and stop this ended terribly. I couldn’t figure out how to only make a specific number and have it stop, thus the infinite enemy objects (the version I’m referring to isn’t online right now due to it’s affect on computers).

I’ve been almost entirely familiar on a conceptual level of the controller object for a while: it’s basically an object with a bunch of functions attached to it, set to fire off when the game starts (or as programmed to do). It doesn’t necessarily have a sprite associated with it but it’s added to the main “game room” so it “exists” in the world. I should mention here using this controller object makes dropping in actual asteroid objects into the game room unnecessary as they’re all spawned at different locations instead.

In case of GML Space Rocks it has both a room start and a create event associated with it. Below is the sample code I’ll start with.

Object: obj_game
event: Room Start

if (room == rm_game) {
	if ( audio_is_playing(msc_song) ) {
	audio_stop_sound(msc_song);
}
	audio_play_sound(msc_song, 2, true);
	repeat(6) {
		// as the tutorial says 
		// "This gives the player the best possible starting circumstances as there will be no asteroids created near them. "
		//https://www.yoyogames.com/en/tutorials/space-rocks-gml
	    var xx = choose(irandom_range(0, room_width * 0.3), irandom_range(room_width * 0.7, room_width));
	    var yy = choose(irandom_range(0, room_height * 0.3), irandom_range(room_height * 0.7, room_height));
	    instance_create_layer(xx, yy, "Instances", obj_asteroid);
	    }
	alarm[0] = 60;
}

This code does a few things at “room start”

  • sets an xx and yy variable to define the area it’s okay to spawn in asteroids
  • uses that instance_create_layer to spawn in those asteroids but only in the areas of the screen outside where the player ship is going to be
  • it does this 6 times
  • it sets alarm[0] to a value of 60

Well this leads to an more obvious question: what happens in the alarm 0 event? I mean that’s the first question I would ask upon seeing this code.

Object: obj_game
event: Alarm 0

/**
To set the alarm we have used the room_speed global variable. This variable holds the 
number of steps the room will perform in a second (the game speed), which is what we set 
right at the start of this tutorial: 60FPS. So, by setting the alarm to 4 * room_speed we 
are setting it to trigger again in 4 seconds.
**/
alarm[0] = 4 * room_speed;
if (choose(0,1) == 0) {
		var xx = choose(0, room_width);
		var yy = irandom_range(0, room_height);
	}
	else {
		var xx = irandom_range(0, room_width);
		var yy = choose(0, room_height);
}
instance_create_layer(xx, yy, "instances", obj_asteroid);

I copy/pasted a description of the GMS2 include global variable called room_speed as I thought it seemed like a good description. I wish I could syntax highlight that. Basically all it’s saying is that room_speed stores what we set the the frames-per-second to in the project, in this case 60 frames per second. So by setting alarm[0] to four times the frames per second we get sixty times four or four seconds.

Using that var key word for the variables makes those temporary variables that “expire” at each run. These aren’t going to conflict with the xx and yy in the room start event in other words. Not sure why it necessary to double up on the names like that. It’s not that readable and at best can only lead to confusion for anybody trying to read the code.

I’m on kind of a roll here but I’m going to take a slight detour: I actually skipped over some code in that alarm 0 event and I think it’s important so I should stop and include it separately.

Object: obj_game
event: Alarm 0

/***
There is one problem with this event, however... Because the object "obj_game" is 
persistent and the alarm is always reset, we would end up with asteroids in rooms 
other than the game room, since the alarm will be running even after the player has won 
or lost. To avoid this, add this code at the start of the code block, before the code given 
above
***/
if (room != rm_game) {
	exit;
}

I again had pasted in the conclusion from the tutorial page. As the explanation says it just has to test and make sure it’s the main/game room and if not then exit. Seems kind of important.

With that minor detail out of the way, back to my main goal: Create four and only four enemies in Newtius and not cause an infinite memory leak.

Back to the alarm 0 code: it uses a choose to get some random x and y coordinates to put in that asteroid. Actually it uses a randomized then random x/y coordinates. Kind of interesting how that’s written. I find it both clear and something of a shorthand at the same time.

I think what’s happening is that basically on the “room starts” event some – six to be specific – initial asteroids are created at random locations that aren’t any where near the player ship. This is done inside a repeat 6 times loop which also creates variables xx and yy for x and y coordinates for use in the instance_create_layer call. After that a new random asteroid at a random location spawns every four seconds. Indeed: if I don’t shoot anything in the game the window just fills up with more and more asteroids.

Actually I’m not sure why that alarm[0] = 60; line is in the repeat the loop. Is it necessary to set that alarm value in every all 6 loops? I’m probably missing something obvious.

Upon re-re-re-re-reading the code, the alarm 0 equal 60 code is not in the repeat 6 loop, so it’s not setting that value to 60 six times. I just mis-read where the braces were, I guess.

The other interesting thing about this game object is the draw event. This is the one with all the bitwise shift operators. In this manually coded edition it’s a bit simpler and a thousand percent more readable.

I’ll just put in the one case here for demonstrative purposes.

Object: obj_game
Event: draw

case rm_start:
/*
	Note that we use the "@" to prefix the string we are wanting to draw, and we have the string split over multiple lines. Using "@" like this tells GameMaker Studio 2 that you are defining a string literal, which means that the string will be drawn with line breaks and other special characters, without the need for escape characters
*/
	    draw_set_halign(fa_center);
		var c = c_yellow;
		draw_text_transformed_colour(room_width / 2, 100, "SPACE ROCKS", 3, 3, 0, c, c, c, c, 1);
		draw_text(room_width / 2, 200, 
		// @ is essentially the GML version of the "pre" tag in HTML
@"Score 1,000 points to win!

UP: move
LEFT/RIGHT: change direction
SPACE: shoot
>>PRESS ENTER TO START<<");		
	    draw_set_halign(fa_left);
    break;

This code is much more readable. Not sure why using a variable called ‘c’ for every color was necessary (in the other case statements) but this is at least is readable.

This is only interesting as far as using the ‘@’ symbol as something of an equivalent to the “preformatted” tag used in HTML: just put everything in verbatim, including spaces and line breaks. Other than that it use that fa_center at the top to center all the text and then fa_left to “reset” the next formatting back to default. Seems unnecessary to me but since it’s the recommended convention I should probably get in the habit of doing so.

Probably in accurate sum-up

I’ve decided to attempt to sum up the way this seems to work in a semi-coherent outline then use another post for attempt to apply this to Newitus. Just bear with me.

I’m looking at my left over code in Newtius and I now realize from my adoption of the arena shooter demo game.

That game used a similar but not necessiarly identical method to the GML Space Rocks game demo: it used an “object spawner” object an alarm to create a continuous flow of enemies.

Space rocks on the other hand has the “game object” that has many more events and a lot more code involved. I’m going to go with the Space rocks version.

So let me try and follow this process in kind of stream of consciousness sort of format here.

"obj_game"
Starting the "room start" event 
first check if the room is the game room and if it is check if the music is play already. If the music playing stop it (this is to prevent over lapping music tracks from one game start to another)

then start up the music

first thing then:
repeat 6 times:
generate two random number integers: 
for width, variable xx is between 0 and room width  times 0.3 and room width times 0.7 and room width
for height, variable yy is between 0 and room height times 0.3 and room height times 0.7 and room height
with the xx and yy variable established, create an instance of an asteroid object...
and do this six times

outside the repeat loop, set alarm 0 to 60.

Ok I’m fairly sure I know what’s going on there. I might have to do a side project called “fun with alarms” to really comprehend how they work. But mostly I know what’s going on here. And this alarm[0] = 60 line actually “calls” the alarm 0 event, kicking off the whole infinite loop to continually spawn new asteroids. Now that I think about it there should probably be an upper limit set to that.

The next logical question to me upon seeing the above code would be “well what’s in the alarm 0 event?”. So lets see.

"obj_game"
Starting the "alarm 0" event 
first check for value of "room" - see if it's equal to the game room or not. If it's not just "exit". I think this is so there aren't any asteroids floating about on the title screen.

Next is the alarm 0 set, of "4 times room speed". Room speed is a GMS2 provided global variable that is essential the frames per second setting for the game. The game is set to 60 frames per second, which make this statement four times 60 which is 240 or "4 seconds". So the timing of this game is linked directly to the frames per second setting. For a game like this I assume hardly anything can go wrong with doing it that way.

Next is something of a shorthand: using an if statement then embedding a "choose" statement inside it. Seems like it'd be more readable as two separate statements. The choose is either 0 or 1.

If the choose comes out equal to 0, set variable xx some where between 0 and room width and variable yy an integer random value between 0 and room height.

Conversely if the choose was a 1 well it's just xx that gets the random integer treatment.

These are separate xx and yy variables to the prior ones from room start. Which I guess is what it's kind of confusing to me. 

lastly it's the same instance create statement with the xx and yy and spawning an asteroid.

So an attempted summary: I’m using this “controller” object to spawn some 6 initial asteroids when the room loads, once per second.

After that the timer will spawn a new asteroid once every seconds some place in the room, along the edges.

I’m not sure if this is going to help that much for whatever I have in mind for Newtius.

My goal for the next post is just to spawn five instances of one enemy type, and that’s it. Just stop there. No memory leaks, the infinite spawning. Just stop.

Actually that initial repeat six loop might be perfect for that. Just have to add a “Destroy self” line once the enemy objects are outside the room. That code already exists for bullets in the space rocks demo.

I guess as a proof-of-concept I could use the same method (so to speak) with the room start event. It would just be doing that room check and immediately setting a value to an alarm. And in the alarm event itself setting a value to the same alarm then using the set instance call to spawn a ship. No…that wouldn’t work. I’d be back at the same problem of infinite enemies with no end. I don’t know I’ll have to further try to noodle this through.

I also need to add that explosion/debris effect to enemies and the player ship. But one step at a time.


The latest version/progress of Newtius can always be found at my GitHub repo:
https://github.com/tildesarecool/newtius

One thought on “Dev Log Entry 7: Am I reverse engineer now?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s