Klazen's Fangame Development Tutorial

Hey Guys! Welcome to version 2.0 of my "Getting Started with Fangame Development" tutorial! A lot has changed in the two years since I posted the first version, so I figured it was time to go ahead and update the material. Just like last time, this won't be a comprehensive tutorial, but it should cover the basics of everything you need to know. I hope this guide is as useful going forward as the previous version was. Thanks for reading!

Before You Start

This tutorial contains images. However, to keep it from getting cluttered, I have all the images hidden by default. If there's an image available, there will be a Show Image button to display the image for you. I also use HTML5 annotations on the images to point out important things. Just hover your cursor over the image and you'll see little red boxes pop up, hover over one of the boxes to read the text. Try it on the image of the kid below!

A picture of the kid, ready for adventure!

I have also marked each section with a difficulty icon, so you can know at a glance how much experience I expect you to have when you're reading it:

Beginner Section

A beginner section. The only requirement for these blocks is that you have read all the previous beginner blocks, as they build upon eachother. If I have code, it's thoroughly explained, and I describe every step I take while navigating Game Maker.

Intermediate Section

An intermediate section. Once you've had a little experience working in Game Maker, you're probably ready for these. You should understand how to use all the resource editors, so that you can do basic sprite or room editing. You'll get more code, so you should be comfortable enough to be able to read through code and make changes, but not necessarily enough to write your own code.

Advanced Section

An advanced section. In these, I assume you know how to do most of the common tasks in Game Maker, and you can read an instruction like "create a custom triggerable object and link it with its trigger" and know what to do. A working knowledge of GML is also expected.

This tutorial is still a work in progress, so if you notice any issues or have any feedback, please let me know! If you need to reach me, you can find me on the I Wanna Community Forums, where we're also happy to answer any specific questions you have on IWBTG fangame making.

Environment Setup

Here we'll talk about how to get you set up and ready to start.

Development Software

Beginner Section

The very first thing you need to do before you can make fangames is... you guessed it! Get a program that you can use to make fangames! 99% of the games in our community are made with a variant of the Game Maker software, by YoYoGames. Typically, a premade "engine" project is used to lay out all the basics in the game, like physics and graphics. Everyone used to use Game Maker 8.0/8.1 due to lack of a good engine for Game Maker Studio, but after some research and development by a few members of our community, we've actually got a good studio engine now! Due to this, as well as due to YoYoGames officially decommissioning GM8, I now recommend that you use Game Maker Studio 1.

"But I've heard that the free version of Game Maker is terrible! I don't want to pay $99 for it!"

Don't worry, the free version of Game Maker Studio 1 is more than adequate for your needs. The only limitations you'll notice are the required "Game Maker Studio" splash screen on game startup, and the inability to change the window title. Literally everything else you could want to use is available!

Get Game Maker Studio Free Version (Click the "Version 1.4.9999" link at the top)

Getting an Engine

Beginner Section

In the previous version of the tutorial, I had a list of popular engines here. However, since I only recommend using Game Maker Studio 1 now, I'm going to make the choice easier for you! The engine you should use for fangame development in GMStudio 1 is the I Wanna Be The Studio Engine YoYoYo Edition. I'll be using version 1.31 of this engine in the tutorial, so if you've chosen to use a different engine, or you insist on using GM8, then some names, methods and steps may be different. When you download the engine, please read the included readme. You may not understand everything in the readme now, if not come back and read it after the tutorial. There is a lot of important information in there you should know about, including how to disable debug mode. If you do not follow the instructions in the readme before you release your game, you will leave in god mode and give your players the ability to do anything they want.

If you'd like to take a look at the other engines, check out our Engines Forum. Once you're more advanced, you might find some other stuff in there that interests you (RegalPrime even made a Unity engine!)

Get the I Wanna Be The Studio Engine YoYoYo Edition

What's different from GM8

Intermediate Section

If you're new you can skip this section, but I'm leaving it here just for reference.

Many of us were familiar with GM8.1, and were reluctant to move to GMStudio. For the most part it's the same, there's not too many differences between them. Studio brings lots of performance enhancements and new features too! I've been asked a few times what the differences between 8.1 and studio are, and so I've compiled a little list of the major things that might affect a fangame developer. (Feel free to leave a comment if you know of more)

Variable Initialization

In Game Maker 8 / 8.1, variable initialization was optional thanks to an option called "Treat Uninitialized Variables as Zero". This meant that any variable you checked and didn't set beforehand would just be zero. In Game Maker: Studio this option is no longer provided due to their newer, optimized runtime environment. This is not limiting in any way, but just takes some getting used to. You must now remember to initialize all your variables, usually in a create event, or at game start for global variables. For instances, you need to make sure that at least one exists before accessing it, with the instance_exists function. As a side effect, this helps prevent bugs that commonly occurred before, like player-targetted attacks aiming towards the top-left of the screen, true/false variables starting out as false and causing unexpected code flow, or triggers automatically firing / not firing at all when no trg value was set.

Event Order

The event order GM8 vs GM8.1 vs Studio is different in some regards. The only guarantee given to event order by YoYoGames in GMStudio is outlined in the lists below. Note that each event is run for every object in your game before moving on to the next event, and from our research, which object runs first seems to be determined by its order in the Objects folder in your project. This may not be true on non-Windows targets as I haven't tried yet.

Initialization Events:

Step Events:

Draw Events:

For more information, check the documentation.

Audio System

The audio system in GMStudio has been completely overhauled. You'll find that you need to use different functions to play sounds, but the basic concept is the same. Never use any function starting with sound_ - instead, you will use functions starting with audio_. For example, instead of sound_play(sndBlockChange) you will use audio_play_sound(sndBlockChange,0,0). For looping music, instead of sound_loop(sndTrack01) you would use audio_play_sound(sndTrack01,0,1).

Detailed information is available in the GMS Audio documentation.

File System

This one is very different from GM8. Studio has begun enforcing a "Sandboxed" approach, intended to keep programs from affecting the rest of your computer. This will feel like a big limitation, but is done with good intentions. What you need to know as a developer is that you will not have access to the folder your game's executable is in. Instead, you can only access a special folder in your computer's AppData folder. You can find this folder by opening an Explorer window and putting %localappdata% in the url bar, and hitting enter, and then looking for your game's name. Your save files will be saved here.

For more information on the subject of file system limits, read the documentation

Other Links

Here's a couple more links that go over the differences between 8 and Studio if you want to learn more:

Learning the Basics - A Walkthrough

Beginner Section

Ok, now that we've gotten the technical stuff out of the way, let's get back to the basics. This section of the guide has been written as a walkthrough, each part building on the last, so you should read the entire section from start to finish. You can always come back any time if you need a refresher on any one piece!

Starting Game Maker

Beginner Section

Once you've downloaded and installed Game Maker and the YoYoYo Engine, you should start by opening the engine. Extract the YoYoYo Engine zip archive somewhere (a folder on your desktop is fine for now), and then open the GMZ inside (it should have a green-on-black icon if you've installed Game Maker). It will take a minute to set up the project for the first time, and then when it's done, you'll be greeted with a screen like the following. Note that your colors might be a little different from mine since I'm using a skin!

Game Maker, after opening the engine

As a beginner, the very first thing you should do is run the sample game included with the engine. Run the game by pressing the green arrow on the toolbar at the top of the screen, or by pressing F5. It will start in traditional fangame fashion, and you can test it out for yourself. Why is it so important to play the sample game, you ask? Well, it's because we'll be modifying it, and I want you to know what everything is like before our modifications so you can see the effects.

Once you've had enough fun with the sample, press "Esc" to quit and be dumped back at the GM window.

At first, the GM interface can be daunting, but it's all divided up into easy-to-grasp sections, which you can see on the left of the window. Let's walk through these sections and see what's going on. There's only a few major categories you should focus on for now: Sprites, Objects, Backgrounds, Sounds, and Rooms. I'll go over the other categories as well later in the tutorial, but you can skip them if you're just looking to get started.

Sprites

Beginner Section

"Sprite" is just fancy game developer lingo for an animated image. You'll use sprites for anything that isn't part of the background, or that may move in-game (think cherries, spikes, the player, bosses, etc). If you open the Sprites folder, you'll see a bunch of subfolders, which the engine developer made for you (you can make your own by right-clicking and choosing "Create Group"; same for making a new Sprite). Open up the killers folder, and double-click the sprSpikeUp Sprite to open the Sprite Properties window.

The Sprite Properties Window

The Sprite Properties window allows you to modify the sprite. Click Edit Sprite to get the Sprite Editor window. Hover over all the buttons on the toolbar to figure out what they do. We'll be making an animated spike to get accustomed to the editor, so select image 0 (the spike image), and then click the copy button (the two sheets of paper) and the paste button (clipboard with paper) to create a second image frame (yes, ctrl-c/ctrl-v works). Go ahead and check the "Show Preview" box on the left too. The image you see is animated, but it doesn't look special yet because both frames of animation are the same. Let's change one to see what it does.

The Sprite Editor Window

Select image 1, and then click the pencil button on the toolbar to open the Image Editor. You can use the Transform menu to shift, rotate and strecth the sprite, and the Image menu provides you with some neat manupulation styles, and of course you have your tools on the left and colors on the right. This isn't an image editing tutorial, so I won't go into detail, but go ahead and make something of the spike. Do whatever you want, I'll wait for you. Once you're done playing with the image editor, click the green checkmark button at the top left to save the image.

The Image Editor Window

Back at the sprite editor, you should see a rapidly-flashing animation of your new spike on the left. Change the "Speed" from 30 to something lower for a less epilepsy-inducing animation (like it says, this speed is only for the preview, we'll correct this in-game later). Press F5 to start the game, and go find a spike. You'll see it flashing like crazy. Be proud! You've just made your first animated spike, and are well on your way to crafting your own HD Spikes! We'll fix the crazy flashing in the next section, Objects.

A preview of our new spike

Already have some images you want to put in your game? Try File->Add From File. Got a single image with multiple frames of animation that you want to split and add all at once? Try File->Create From Strip. Anything else you'll have to Google for help; that's beyond the scope of our tutorial.

Objects

Beginner Section

Objects are the actual "things" in your game. They use sprites as their images, and their behaviour is determined by code you write (don't freak out just yet!). We just edited the sprite of the upwards spike, so let's open that object to fix the animation flashing. Open the Objects folder, then the killers folder, and finally double-click the objSpikeUp object. You'll get the Object Properties window, much like you got the Sprite Properties window when you double-clicked the spike sprite (see, it makes sense!).

The Object Properties Window

On the left, you'll see a bunch of parameters for the object:

The real meat of the object editor is in the Event/Action lists. This allows you to specify behaviour for the object. It's a cause & effect system: when an "event" happens, it performs a set of "actions". On the far right, you can see all the actions you can perform. It'll take a while, but you'll learn them if you keep trying. All of these are known as "Drag and Drop" actions, or "DnD" (helps to know this when you're Googling for help). For more advanced control, you'll need to actually write code. We'll fix the spike animation using both DnD and code, so you can see both in action.

But first, I want to make a small note about terminology. When talking about objects, you'll often hear the word "instance" used. You may not know what that means, or at least not what it means in programming lingo, but it's real simple. Think of an "Object" as a blueprint, or set of instructions, from which you can create any amount of "Instances". GM gives you a way to add code to each individual instance, called Instance Creation Code. For example, if you have a moving platform as the object, in the instance creation code you can specify the direction and speed for that particular platform. We'll revisit this topic later in the Rooms section.

DnD Actions

Back to fixing our spike. First, we need to specify an event. We want to specify an "animation speed" for every instance of the objSpikeUp object. How can we do this? Why not have the game do it every time it creates an instance? Add a Create event with Add Event->Create. Now, select the Create event. The Actions list on the right now lists all the actions that happen at instance creation (none yet!). Click the "main1" tab on the right, and drag the "Change Sprite" action (the red Pacman) into the Actions list. In the action properties window, select the sprSpikeUp sprite from earlier, leave subimage as 0 (remember image 0/image 1 from the sprite editor? This field specifies which image we start at), and for speed type this exactly: 1/room_speed

Adding a Create Event

The Change Sprite DnD Action

Technical information warning! room_speed is one of GM's built-in variables. Its value is the number of "ticks", or updates, that the game performs per second. You should never need to change this, but in the Yuuutu engine, it's 50. The "speed" is added to a counter behind-the-scenes every second, and the value of this counter determines which image of the sprite is to be drawn. This means that every "tick", 1/50 is added to the image counter, and since 50 "ticks" happen per second, the counter increases by 1 every second. If the counter goes past the number of images in the sprite, it just goes back to 0 and keeps going. So we get animation at one frame per second!

That's all you have to do to fix the animation! Go start the game again, and look at the spikes. Every second, they'll switch back and forth between the images you made in the sprite editor. If it's too slow for you, try raising the speed (2/room_speed would be 2 frames per second, 3/room_speed is 3, etc.) Also try adding more animation frames to make it look cooler!

Script Actions

Ok, that was the drag-and-drop tutorial. But for anything interesting, you'll need to delve into the code... so you might as well learn now! Code is added to actions just like the other DnD actions; go to the "Control" tab in the Object Properties window, and drag the "Execute Code" action (the piece of paper) into the Actions list. Brace yourself, because it will immediately open the Execute Code script editor. Luckily, all we are trying to do here is fix the image speed, so it'll take just one line of code. And... here... it... is:

image_speed = 1/room_speed;

Equivalent Code for the DnD Action Above

Not bad, huh? Notice how the words image_speed and room_speed are both red? That means GM recognizes them as special variables, like I mentioned before. There will be a red highlight to the left of the text if you messed it up, so make sure you copied it exactly! Hit the green checkmark to save the script, and then, back at the Object Properties window, click the old DnD action in the list, and press the "Del" key to delete it. Now, there's only code controlling your object; let's go see how it does. Oh, what's that you say, it worked great? Good. Well, that's all I have to tell you about scripting, but you can go read the GML (Game Maker Language) Reference to learn more about GML, the functions and variables you can use, and what you can do with it.

Backgrounds

Beginner Section

You don't wanna be the guy (heh puns again) that uses bland, pastel backgrounds in your game. So let's put something nice in here instead. On the left of the GM window, open the Backgrounds folder. One caveat before we go any further: GM considers background images and tilesets (a tileset is an image that has a bunch of smaller images in it that you use to build scenery) both as backgrounds, so you'll find them both in here.

Anyway, this is really simple, so go find an image that you like (any image will do, just get one already!). The typical room size in fangames is 800x608, so don't get an image bigger than that! (smaller is fine... for now, I guess) In GM, right-click the backgrounds folder, and create a new background. Name it whatever you like, and then click Load Background to open your image. Remember this for later, we'll make good use of it ;)

The Background Properties Window

Tilesets are a little more complicated, but easy once you know what you're doing. Typically, tiles in fangames are 32x32 or 16x16 big. Here's an example of a tileset (Google "super mario bros tileset" if the link is ded): http://www.spriters-resource.com/snes/supermariobros/sheet/6211/ You can see that this person has taken the individual blocks from SMB1 and divided them up, and put them in an image for you to use. You can import this image into GM to create your own scenery with! Just create a new Background (we'll call it tileSMB1), and then Open Background like before, and open this image. This time, however, check the "Use as tile set" checkbox. You'll see a grid overlaid on the image, denoting where the tiles will be divided at. It's not correct, so we'll fix it. You can see that these tiles are 16x16, so set the tile width/tile height as 16. Looking at the top-left tile, there is no space between it and the edge of the image, so the horizontal/vertical offset can be left as zero. In between each tile there is a 2 pixel wide gap, so set the horizontal/vertical separation to 2 each. Now, you'll see a nice black box surrounding each tile, which means you're set! We'll test this out later in the tutorial.

Tileset Creation: TODO: image here

Having a hard time finding backgrounds/tilesets for your game? Try here: http://www.spriters-resource.com/ Has a TON of sprites/backgrounds/tilesets for all sorts of games

Sounds

Beginner Section

Sounds? Are we changing what sound the kid makes when he jumps? Well, no, you could do that I guess, but what we're really doing is getting rid of that awful guy rock. Yep, don't go any further until you've got a song of your own to use here. It can be hard to find music that you want, so here's a few good resources to get started:

Ok, now you've got a song, let's put it in the game! Open the Sounds folder in the GM window, right-click the music folder, and choose Create Sound (It doesn't matter that it's in the music folder, this is just to help you keep track of where things are). Name the sound whatever. I recommend you prefix it with mus so it's easier to find later; for instance, use musYoshisIsland as the name for a Yoshi's Island song. You'll see this done in other areas of the game too; obj for Objects, spr for Sprites, snd for sound effects, etc.

The Sound Properties Window

When you import your music, make sure it is in mp3 format! Game Maker requires that music be in this format, and will convert it to an OGG when you compile. For sound effects however, only use the WAV format. Make sure your sound effects are set as Uncompressed - Not Streamed and your music is set as Compressed - Streamed, this will make sure your music doesn't hog any memory, and that your sound effects are quick and well synced. If you want your music to be stereo, change that in the "Target Options" at the bottom.

The below paragraphs explain how to actually play sounds and music in your game. It requires a little understanding of code, so you might want to come back here later after you've finished the tutorial.

When you want to add your music to your rooms, you'll need to edit a script that the engine uses to get the correct music for each room. Open the Scripts > world folder, and then double-click the scrGetMusic script. Here, you'll see some code describing which rooms get which music. You can add new sections yourself, just don't forget the break; statement at the end of each section. Read the green comments for an explanation of how everything works.

To play sound effects, you'll need to use the audio_play_sound(soundid,0,false) function in your code. Change soundid to the name of your sound. If you want your sound to loop, change the false to true, but don't forget to stop the loop at some point!

Rooms

Beginner Section

Enough screwing around. The heart of every fangame is the level designs. Everything else is just icing; without good platforming, what do you have, right? Well, young student, now you know enough to advance. Let us learn how to make levels!

On the left of the GM window, open the Rooms folder. The init folder here contains the boilerplate rooms needed to get you into your fangame, so don't mess with those for now. Instead, let's open up the sample folder, and double-click the room named rStage01. This opens the Room Properties window, the heart of the designer. This room is actually 2 rooms in one, so drag out the window so you can get a wider view of everything. If you want to scroll around the room, you can do it by dragging with your middle mouse button, or by clicking on the minimap at the bottom left. Now, let's explore what's going on. Take a look at the left section of the window and you'll see 6 tabs. Each one is covered in a section below.

Objects Tab

Select objects here (from the Objects folder) to place in your room (like the spike from earlier!). Left-click places, right-click deletes. Read the notes at the bottom of the objects tab, right there on the screen for your convenience if you ever forget. (See above image for object tab explanation)

Room Properties Window, with the Objects tab selected.

Settings Tab

General room settings, like the name (used to reference this room from within the game; the player will never see this). All you need to worry about is the name and the width/height, the other settings are advanced things you don't have to mess with until you need them. Always set the room size as 800x608 if possible, but if you need to make a bigger room, make the width a multiple of 800 (800,1608,etc.) and the height a multiple of 608 (608,1216,etc.). This ensures that it follows traditional fangame standards.

Room Properties Settings Tab

Tiles Tab

select which tileset to use to place your scenery in the game. If you click the text box at the bottom of the grey space on the tiles tab and select bAllTiles, you'll see the generic guy game blocks there in front of you. Select your tileset from earlier and try clicking on the different tiles to select one, and then somewhere on the level to place them. Right-click in the level to clear tiles.

Room Properties Tiles Tab

Backgrounds Tab

Set the background to be displayed in the room. There's 8 background slots available for you to use, but in general, you'll only need to use Background 0. Besides being able to choose the background image, you can choose a color to paint behind the background, stretch/tile the background, and make the background scroll behind the level. Foregrounds are great if you have a haze or a cloud layer you want to overlay on the screen. Try it out with the background you made!

Room Properties Backgrounds Tab

Views Tab

This determines what the player sees in your room. ALWAYS make sure to set the view correctly in any new room you make. It's very easy to forget to do this, so I recommend copying the rTemplate room instead of creating a new one when you're making a new room. If you forget to set the view, your players can get strange graphical bugs, like the window jumping around on their screen. Just Enable the use of Views, select View 0, check Visible when room starts, and make sure the coordinates are 0,0,800,608 as in the image below.

Room Properties Views Tab

View in room specifies what section of the room to display: X is the left side of the rectangle, Y the top, W the width, and H the height. You can see this view encompasses the left half of the room, but it is moved to where the player currently is automatically thanks to the objCamera object, which you should also place in any room larger than 800x608 if you're not making the view follow the player. Go to the View Following section in the FAQ at the end of the tutorial for more information on that!

Port on Screen specifies where in the game window that rectangle is put. X is the left of the window, Y the top, and W/H are same as before. So, this takes the view and sticks it into a 800x608 window for the user's viewing pleasure. To learn more about what you can do with the view, check the View Following and Screen Shaking sections in the FAQ at the end of this tutorial!

Physics Tab

We don't use Game Maker's physics engine in fangames, so I'm not going to cover this functionality. You can look it up online if you're interested.

Other Tips

One more piece of advice about room editing: You'll notice at the top of the window there are two boxes: Snap X and Snap Y. These control the sizes of the squares on the grid displayed on the window below. When placing an object/tile, if you click anywhere inside a grid square, the object is placed at the upper-left grid intersection on that square. Common values for these snaps are 32, 16, and 8; one "block" in fangames is 32 pixels high, so those are 1 block, 1/2 block, and 1/4 block sizes respectively.

So try placing some objects around in your room! Use a different tileset, get rid of those **** brown blocks, and more! It's all yours now! Make sure to get comfortable with the above concepts before you move on, as I assume your level of knowledge is a bit higher than "absolute noob" in the next sections.

Other Game Maker Resource Categories

Intermediate Section

These sections will give a brief overview of the other categories available in Game Maker Studio. You can skip this for now, as you've now got enough information to do some game making. But if you're curious, read on!

Scripts

Intermediate Section

If you've done some coding in game maker, it's likely you've used some built-in functions, like instance_create. Scripts are just Game Maker's way of letting you create your own functions! For instance, if you want to create an apple-splosion with 30 apples, all moving at speed 8, starting from the current object's position, you might write the code like so:

count=30;
curDir=0;
spd=8;
xcenter=x;
ycenter=y;
for (i=0; i<count; i++) {
    a=instance_create(xcenter,ycenter,objCherry);
    a.direction=curDir;
    a.speed=spd;
    curDir+=count;
}

Pretty straightforward, but that would be annoying to copy around every time you need it right? What if we could just write one line every time we wanted to make an applesplosion? Using scripts, we could replace that entire block with this:

applesplosion(x,y,30,8);

Now that's what I'm talking about! To do that, create a new Script, and name it applesplosion. In the script editor, put the following code:

///applesplosion(x,y,count,speed)
var count=argument2;
var curDir=0;
var spd=argument3;
var xcenter=argument0;
var ycenter=argument1;
for (i=0; i<count; i++) {
    var cherry=instance_create(x,y,objCherry);
    cherry.direction=curDir;
    cherry.speed=spd;
    curDir+=360/count;
}

And now you can use that applesplosion function anywhere in code! The triple-slash line at the top of the script is a special comment that GMStudio displays to you when you're typing the function, so you don't have to memorize the arguments. It's not required, but it's very nice to have! You can see it in action at the bottom of the objCherryEnemyText_objBullet_1 Action Editor Window in the image below.

The Applesplosion script in use

You may be wondering what those "argument" words mean. In programming, an argument is something you give to a function. For our script, we have four arguments, the x, y, count and speed arguments. GMStudio lets access up to 16 arguments, argument0 through argument15. You can also return a value from your function. In the code above, you see instance_create returning a value; in fact, it returns the instance ID of the object it created, allowing you to edit it's variables. You can return a value with the return keyword, but for our example, it's not really useful.

Think of a function as a black box, with holes you put stuff into, and a hole that something comes out of. This box can also do other things than give something out, which we call a side effect. Our function has two inputs, no outputs, and a side effect of creating an applesplosion. Every function can be thought of like this, you don't have to worry about what it does on the inside. As long as you know its inputs, outputs and side-effects, you understand the function!

One more point I should bring up is that of Scope. In programming, scope determines what variables you have access to at any one time. When you're writing code for an object, you are in the scope of that object, and so you have access it all its variables, like x, y, image_speed, and so on. When you call a script from an object, you are in the scope of that calling instance. (Fun fact: the with keyword allows you to switch the current scope to something else!) That means that you have access to all that instance's variables, and can use them accordingly. Also, any variables you set here are available in the calling instance. This is why I put var in the script, as the var keyword limits the scope of the variable to the current code block. This way, if the calling instance had a "count" variable it was using, we won't overwrite it when we call our script. This is also why you shouldn't use the var keyword when declaring variables for your object, because otherwise the variable goes out of scope when the current event completes execution. It's a little complex, but it's a powerful concept you should be aware of.

Time Lines

Intermediate Section

Timelines are a common way of executing a list of actions at a specified speed. This can be great for things like cutscenes, where you have the player start walking at the start, stop walking after one second, start an earthquare after 2 seconds, etc. However, because of the way Game Maker structures timelines, I actually recommend you don't use them - maintenance just becomes a headache.

What should you use instead of timelines? If you've just got a couple of actions, why not put them in alarm events in your object? If you're making an avoidance and are going to need hundreds of actions, then the most common and easiest solution is to put it all in a step event, and keep track of the steps yourself. For instance, the scenario above would be implemented in the cutscene player object's step event like this:

timer+=1

if (timer==1) hspeed=3
else if (timer==50) hspeed=0
else if (timer==100) shakeScreen=true

Looks pretty simple doesn't it? the timer will count how many steps have elapsed since it started (remember there are room_speed steps per second, which is 50 in common fangame engines). You can use a similar method to count beats in a song to make timing in avoidances easily. Instead of adding one per step, add the number of [beats per step] which can be calculated given the BPM of the song.

If you still want to use a timeline, then I'll give you a couple of tips. A timeline doesn't run until you start it:

timeline_index=tmlMyTimeline;
timeline_running=true;

The timeline's scope is the scope of the instance that started it. If you don't know what scope is, go check out the Scripts section of this tutorial. For more information on timelines, check the documentation.

Shaders

Advanced Section

Shaders are, in my opinion, the most powerful new addition to GMStudio. They are also certainly the most complicated. Shaders introduce an entirely different programming language, known as HLSL (or GLSL if you use OpenGL shaders). This code is compiled separately and run on your GPU, as opposed to most code you're used to which runs on the CPU.

So what makes learning a completely new language worth it? The reason is pretty simple actually; let me give you a quick example. Let's say you want to draw everything inverted - so black becomes white, blue becomes yellow, etc. With shaders this is actually very simple! In fact, let's just take a look at it, and I'll explain what it does. Below is the Fragment Shader for our invert shader. To follow along, create a new Shader, and open the Fragment tab and paste this code. The Vertex Shader code can be left as it is for now.

//Fragment Shader
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    vec4 c = texture2D(gm_BaseTexture,v_vTexcoord); //get the color that the current pixel is supposed to be
    gl_FragColor = vec4(1.0-c.rgb,c.a); //invert the RGB values; keep alpha the same
}

You don't even have to look at the code, just read the comments. "Get the color the pixel is supposed to be, and invert the RGB values". Two steps to invert, very straightforward! Before, we'd have to keep track of a surface and learn blend modes and such, all very complicated just to get this simple concept implemented.

Here, I'm drawing half the screen with the shader off and half with it on, so you can see it in action. The code below is in an object's Draw GUI event, which occurs after all draw events.

shader_set(shdInvert)
//Draw the left half of the application surface to the screen
//Draw GUI coordinates are relative to the screen
draw_surface_part(application_surface,0,0,400,608,0,0);
shader_reset();

Half the screen drawn with an invert shader

So how exactly is that shader working? As I said before, a shader is a program that runs on your GPU. The cool part is that the fragment shader is run for every single pixel in parallel. Your GPU was built for this kind of thing; your CPU would have to calculate each pixel one by one. For an 800x608 image, that's 480,000 pixels that have to be calculated. And this was just a small example, you can do tons of other cool things with shaders, like dynamic lighting, cell shading, standing waves, and more, but I'll leave how to do those as an exercise for the reader.

If you want to learn more about Shaders as they relate to Game Maker, LAWatson has written a small tutorial here.

Paths

Intermediate Section

Paths are a simple way to control the position of an object over time. As an example, say you want a spike to pop in and out of the ground over and over. Now, you could put the following code in the spike:

if (y<=ystart) {
    y=ystart;
    vspeed=1;
} else if (y>=ystart+32) {
    y=ystart+32;
    vspeed=-1;
}

Or, you could create a path for it:

Path Properties Window, Showing Example Spike Path

And use only the following code:

path_start(pth32down,1,path_action_restart,false)

This will give you the same effect! Paths can also be much more complicated than just a short line back and forth, so if you want to move something along a track, a path is probably what you're looking for. For more on paths, check out the documentation.

Fonts

Intermediate Section

Fonts are, well, fonts. If you're drawing text ingame, you can use fonts to give it your own flair! It works like any other text-editing program in that you can select your font, size, and characteristics. To change fonts, use the draw_set_font function. For more information on drawing text, check the documentation

One extra bit I'd like to cover is the bottom half of the Font Properties window. In Game Maker, fonts are actually stored as images internally. This allows you to use any font on your computer and not worry about if the player has that font. However, because of this, you can only use the character set you specify here. Looking in the YoYoYo Engine, I can see that only code points 32-127 are defined in the fonts, which covers all the standard English letters, numerals, and punctuation, and should be fine for most fangames. However, this excludes extended characters like ß, å, ç, é, ö, and Japanese characters like あ. If this affects you, my recommendation is to use the following character range: 32-255,12288-12543. This covers basic ASCII, extended ASCII, and basic Japanese (excluding Kanji). If you need more characters, you can look them up in the Unicode table. A word of warning, don't use any more than you need because each character takes up some graphics memory (and if you select a huge range Game Maker will freeze up while rasterizing all the graphics for you!).

Font Properties Window

Frequently Asked Questions & Advanced Topics

Intermediate Section

The below sections describe specific scenarios regarding common tasks that aren't so obvious for newcomers (and sometimes for veterans too!). If you've got a question you'd like to see added here, please contact me!

Room Changers (Warps)

Beginner Section

Why aren't all fangames just one big room? Well it just so happens I've got a story for this one. When I made my first fangame, I had a 3200x1200 room (that's 4 rooms wide by 2 rooms tall if you're not feeling like math). I also came up with this cool glowy animated spike effect that turns out required a little too much processing power... so much so that the person who was testing the game for me only got about 20FPS! So how do you stop that from happening to you? By keeping every 800x608 screen of your fangame as a separate room where possible. (There are other alternatives to this, such as deactivating all instances outside of your view, but that's outside the scope of this tutorial).

So you've got two rooms and need to let the player walk between them. There are two standard ways of doing this: have a warp portal to take you to the next room, or allow the player to walk off the edge of the screen onto the next room. Which one you choose is up to you, it's just a matter of preference, but in my opinion allowing the player to walk off the screen to the next one really helps with the feel of continuity in your game, and lets the player feel like they are in a much larger world than they are.

No matter which method you choose, the YoYoYo Engine has you covered. It comes with a variety of warping objects in the Objects > warps folder:

objWarpNext and objWarpAutosaveNext are straightforward to use once you understand how objWarp works, so I'll just cover the two main objects - objWarp and objOutsideRoomChanger.

objWarp

To use objWarp, first, just place it in your room. However, don't test yet, because it's not going to work until you do a little configuration. objWarp has three parameters you need to set in instance creation code:

The roomTo parameter is required (we have to have a room to warp to, right?) but warpX and warpY are optional. If you leave them out, you MUST place a objPlayerStart object in the next room, as that is where the player will start from after warping. Also note that objWarpNext and objWarpAutosaveNext DO NOT have warpX and warpY parameters; you can only use them with a objPlayerStart object.

Warp Usage with objPlayerStart in Next Room

objOutsideRoomChanger

objOutsideRoomChanger is a little more complex, but nothing you can't handle! To use it, place and stretch it so that it overlaps the edge of the room you want to wrap on. Don't just place it along the inside or outside edge of the room, but actually cover it (check the image below if you're unsure of what that means). Then, open up its instance creation code and set the following parameters:

For a screenwrap effect, you must set roomTo and smoothTransition. Also, be warned that the source and destination rooms must be the same size because the roomchanger can't tell how big the destination room is going to be, and so it uses the source room sizes (just another good reason to keep all your rooms 800x608).

Proper Placement and Code for Smooth Transition

Triggers

Beginner Section

It's happened to all of us. You're jumping happily down a hallway, about to reach the next save point. Nothing stands between you and it but a single spike on the ground. "Is that the best you can do?" you think to yourself, jumping over the spike, when suddenly, BAM! The spike jumps off the ground and shows you who's boss.

The word "trigger" means "to cause something to happen". In the scenario above, a spike flew up when you reached a certain point. The effect was a spike moving, and the cause was you touching the trigger object.

In the YoYoYo Engine, there is a premade trigger object ready for you to use in the triggers folder called objFreeTrigger. The objFreeTrigger object is a semi-transparent purple square that you can place in your room to decide where the kid must touch before something happens. However, you won't see it in game, because the Visible checkbox in the object properties has been unchecked.

In order to use an objFreeTrigger, you must link it with the object it controls. Doing this is very simple, using a special variable called trg. In the image below, you can see the trigger and controlled spike's instance creation codes, showing that both have been assigned trg=1 by the developer.

A Trigger Linked to the Object It Controls

Now, what about the other code in the spike's instance creation code? Well, in order to keep the trigger object as flexible as possible, it actually only does one thing: announce when the player has touched it. The "triggerable" objects check every frame to see if an announcement was made for their trg value, and if so, it's up to them to do whatever they want to do. For the spike in our example, it takes the v value from the creation code and stores it in its vspeed, effectively making it fly upwards. You can see this in the step event of objKillerTrigger, which is the parent object of objSpikeTriggerUp, the orange spike in the room from above. Let's take a look at the code, because I want you to be able to make triggerable objects of your own, and not be limited just to the basic spikes and cherries in the engine.

//if we haven't been triggered yet, and an announcement was made for our trg value,
if (!triggered && global.trigger[trg]) 
{
    //if the designer put a value for v or h in the instance creation code
    if (v != 0 || h != 0) 
    {
        //set the speed to those values
        vspeed = v; 
        hspeed = h;
    }
    //otherwise, if the desginer set the spd value
    else if (spd != 0)
    {
        //set the speed based on these
        direction = dir;
        speed = spd;
    }
    
    //finally, mark that we have been triggered now so it doesn't happen again
    triggered = true; 
}

It might look like a lot of code at first, but I translated the code to English and put it in comments so you can at least read through and understand what it does. If you're not yet comfortable with coding, you can use just the basic triggerable objects in the engine to get familiar with the trigger concept. But if you think you can handle the code, then I'm going to give you the basic outline for a triggerable object's step event:

//if we haven't been triggered yet, and an announcement was made for our trg value,
if (!triggered && global.trigger[trg]) 
{
    //Anything you want here!

    //finally, mark that we have been triggered now so it doesn't happen again
    triggered = true; 
}

That's it! Inside that if statement you can do anything, whether you want to make an applesplosion, spawn a boss, start a cutscene, download more ram, whatever, and it will start happening as soon as the kid touches the trigger linked to this object.

A Custom Triggerable Object

Our Applesplosion Trigger in a Room

Our Applesplosion Trigger in Action!

Object spawning

Beginner Section

Adding objects in the room editor is great and all, but if you want a dynamic game, there's got to be a way to create objects through code right? For example, the kid's bullets aren't placed in the room editor, but rather are created every time you press the shoot button. Let's go see how that's done, so we can do it ourselves!

You might think we should go open the player object to check his shooting code, and you would be half right. However, in the YoYoYo Engine (and in fact, every engine I've seen so far) the shooting code is separated out in a script. If you don't understand scripts, you can check the Scripts section of this tutorial, but it's not required - we're just looking for now. Open the Scripts folder, then the player folder, and you'll see scrPlayerShoot. Here's the code from that script:

if (instance_number(objBullet) < 4)
{
    instance_create(x,y,objBullet);
    audio_play_sound(sndShoot,0,false);
}

In English, that's read like this: "If there are less than 4 bullets, create a bullet at position (x,y), and play the shoot sound effect." Hey! Look at that! To create an instance of an object, we use the instance_create(x,y,object) function. This function takes three values:

Not too complicated right? You tell it where to spawn and what to spawn there, and Game Maker takes care of the rest.

View following

Beginner Section

In the Rooms section of the tutorial, we discussed the possibility of rooms larger than 800x608, the standard IWBTG fangame window size. However, what happens when your player leaves the current view boundaries? If you did nothing, then the view would remain in place and the kid would be outside the window, unable to be seen. The standard solution for this problem is to use a Camera object, and the YoYoYo Engine provides you with two options to get you started.

objCamera

The basic camera is the objCamera object, in the world folder. This object will intelligently detect where in the room the kid is, and move the view over the 800x608 chunk he is inside. To use this object, just drop it anywhere in your room!

A Demonstration of objCamera

objSmoothCamera

Another object provided in the engine which will allow for a more smooth scroll is the objSmoothCamera object. This one doesn't lock the view to an 800x608 chunk, rather, it tries to keep the player in the center of the screen (unless the player is along the edge of the room, otherwise you'd be able to see outside the room!). You can use the objSmoothCamera object almost just like the objCamera object above, but there is one more step you need to remember to do: set the Object Following parameter of the room's view to this object (Check the image below).

Setting up objSmoothCamera, with View Following Configuration

It also allows you to configure the scroll speed with instance creation code, through the use of a variable called snapDiv. A value of 1 means that the camera will follow the player exactly, and higher values cause it to move more slowly. The default is 4, play around with it and see what works best for you!

A Demonstration of objSmoothCamera

Aside from using a camera object, you can come up with your own methods of moving the view, both by setting the Object Following parameter to a different object of your choice and by directly manipulating the view yourself with code. In the Screen Shaking section of the tutorial, I will show you how to use this to your advantage to make the room appear to be shaking.

Screen Shaking

Intermediate Section

Screen shaking can add a great visual element to your game, but it can also ruin your game if you go overboard on it. Subtlety is key here, a quick jolt when something falls on the floor or some vibration during a cutscene where the room is crumbling really help pull your players into the scene. There are many ways to do screen shaking, usually involving the view's position. Imagine the view of your room as a camera, if you shake the camera's position around a bit it's going to look like the room is shaking, even if nothing is moving. Here, I'll show you how I achieve a simple-to-use, flexible screen shake. We'll do this by making our own camera object, objCameraShake.

We're going to base our new camera off of objCamera, so copy the objCamera object (right click & duplicate). Open its Create event, and add the following code at the beginning of the action:

shake_mag = 0;
shake_mag_acc = 0;

Then, open the User Defined 0 event and replace all of the code with this code:

///snap view to the section of the room that the player's in

//calculate the shake magnitude here
if (shake_mag > 0) {
    shake_mag-=shake_mag_acc;
    if (shake_mag<0) {
        shake_mag=0;
    }
}

if(instance_exists(objPlayer))
{
    var xFollow = objPlayer.x;
    var yFollow = objPlayer.y;
    
    if (!leaveRoom)
    {
        xFollow = clamp(xFollow,0,room_width-1); 
        yFollow = clamp(yFollow,0,room_height-1);   
    }
    
	//apply the shake here
    view_xview[0] = floor(xFollow/view_wview[0])*view_wview[0] + irandom_range(-shake_mag,shake_mag);
    view_yview[0] = floor(yFollow/view_hview[0])*view_hview[0] + irandom_range(-shake_mag,shake_mag);
}

Let's quickly examing this code to see what's new. We've introduced two new values, shake_mag and shake_mag_acc. shake_mag represents the max number of pixels that the view will move from its actual position. shake_mag_acc gives us the ability to have a shake start off strong and fade back to normal as fast as we set it to. A value of zero means that it won't ease up at all and will continue shaking until we stop it. These values are maintained at the beginning of the User Defined 0 event.

At the end of the event, we are using irandom_range to add a random value to the view's current position. We use irandom_range because we want a whole number, to avoid strange graphical glitches if the view isn't aligned with the pixels. So in this event, we're calculating the current shake magnitude, and then shifting the view randomly. Since we do this once every frame, the screen's gonna look nice and shaky!

So this is all well and good, but how can we use this? First off, you need to place the objCameraShake in your room. Since we copied the orignal objCamera, this will act like normal for now. In order to start the shake, we need to set shake_mag. You could do this in the create event, but then your room is just going to start shaking when you walk in and never stop, which might be cool for a second but will quickly get annoying. Instead, you should have the other objects in your game tell the camera to start shaking, which we now have the ability to do!

As an example, lets make a custom trigger that causes the screen to shake for a second, and smoothly return to normal. Create a custom triggerable object, and place the code below inside it. If you're not sure how to make a custom triggerable object, check the Triggers section of this tutorial where I explain how.

with (objCameraShake) {
    shake_mag=5;
    shake_mag_acc=5/room_speed;
}

Here, we get a hold of the camera object, and tell it to have an initial magnitude of 5 pixels, and to fade back to no shake over a period of one second. If you wanted a stronger shake, you would change the 5 above to something higher, like 10. If you wanted it to last longer, make shake_mag_acc smaller; fading it over 2 seconds would be 5/(room_speed*2). Feel free to play with the values until you find the perfect effect!

And that, in a nutshell, is a basic and easy way to achieve a screen shake. Using the method I described in the trigger above, you could just as easily have an object start a shake when it hits the floor, or start an earthquake and then have it stop by setting shake_mag_acc a few seconds later. You could also extend the camera that follows the player, just put the shake control code at the start of the event and add the random range calls to the lines that set the view position. Be creative, the possibilities are up to you!

Error Messages

Advanced Section

When you were first starting out, you might have just made some simple needle or adventure games with minimal to no coding, just to get more comfortable with the process. But perhaps later on you had a cool idea for a gimmick, or really want to make an avoidance fight, or saw some cool graphical effects that you wanted to try to make, and you started coding it. Finally finished, you run your game, go to the room expecting to see something really cool and... you get hit with a big, unfriendly grey error message popup. Or there is no error but... it's just not doing anything. Or it's doing something, but whatever it is, it's not what you expected. Here, we'll figure out how to diagnose issues and come up with solutions. This, in my opinion, is what separates the novices from the professionals - the ability to resolve errors.

So you've got an error message, and you don't understand it. Let's do a little test... if you saw the error in the screenshot below, would you know what to do?

An Example Error

How can we figure out what's wrong? Let's start by breaking down the error message. From the top, we see that there was a FATAL ERROR in action number 1 of Other Event: Room Start for object objWorld. So, let's open that up and take a look! We know to look in objWorld, in the Room Start event, in the first action...

Action 1 of Room Start for objWorld

Hmm, I don't see anything wrong yet. What's the error message say again? global variable gameStarted(100003, -2147483648) not set before reading it. We can safely ignore those numbers, so the message becomes "global variable gameStarted not set before reading it." But I don't see global.gameStarted in this action! Actually, when you look at the bottom of the error message, you'll see a Stack Frame - this is very helpful, because it will show you the trail your code is flowing through. Looking at the bottom of the stack frame, we can see that at line 7 of the Start Room event, scrSetRoomCaption was called. Then, at line 5 of scrSetRoomCaption, that must be where our error lies!

The scrSetRoomCaption Script, Showing the Line in Question

There it is, global.gameStarted. But what's wrong with it? Well, reading the error message again, we can see that it says this variable was "not set before reading it." As I stated earlier in the tutorial, all variables must be initialized before you can use them, and if you don't, this is what is going to happen. So how would you fix this? Well for this example, I purposefully removed a line of code from the game initialization script in order to trigger this error.

The scrInitializeGlobals Script, Showing the Line That Was Removed

The global.gameStarted variable's purpose is to track the game's state - for example, if you're in the menu, you shouldn't be able to press R and restart the menu room, that doesn't make any sense. This sounds like a variable that needs to always be defined, so that's why it's set in scrInitializeGlobals, which is run at the very start of the game in objWorld's Game Start event. If you were facing an error like this, it would be up to you to determine where your variable needs to first be initialized.

The Game Maker Documentation has more information on debugging and error messages here.

Debugging

Advanced Section

At the start of this section, I mentioned a scenario where you're not getting an error message, but the code still isn't working right. I get a lot of questions like this actually, where people say "I tried to do X, but it's not working." The first step you should take when you're in this situation is to sit back and identify why it isn't working: what you expected, and what is happening instead. I've prepared a situation below, let's walk through it.

So you read this tutorial, saw the applesplosion script, and thought "yo, neat, I want to use that in my game!" So you selfishly ripped the code I worked so hard on... I mean borrowed the code for your own game. You wrote the script, and used it just like I outlined in the Scripts section earlier, and your code looks like the screenshot below.

If you want to follow along at home, create the applesplosion script with the code below, and create an objApplesplosionTrigger as shown in the screenshot below. The object should also have a Create event with "triggered=false" in it. Then, place the objApplesplosionTrigger object in your room, and put an objFreeTrigger somewhere, and link them together. The correct way to do this is shown at the end of the Triggers section, in the "A Custom Triggerable Object" image. Remember to use the applesplosion code here, as we've introduced a bug for demonstration purposes.

An Applesplosion Script, But Something is Wrong...?

You made this applesplosion trigger, and placed it in your room, expecting a big ring of cherries to fly out when the player touches it. But when he does, something else happens...

It's Not Working!

Alright, first things first, following my advice from above: what is it supposed to do, and what is it doing. Well, we expected there to be a nice evenly spaced ring of apples, but instead it looks like they're all squished together! In addition, they're all going mostly right, which corresponds to a direction of pretty much zero. Armed with this information, lets look back to the applesplosion script.

///Can you see what's wrong here?

//using the script
applesplosion(x,y,30,8);

//the script
///applesplosion(x,y,count,speed) script with error
var count=argument2;
var curDir=0;
var spd=argument3;
var xcenter=argument0;
var ycenter=argument1;
for (i=0; i<count; i++) {
    var cherry=instance_create(x,y,objCherry);
    cherry.direction=curDir;
    cherry.speed=spd;
    curDir+=count/360;
}

The apples spawned in the correct position, so we can rule out a problem with anything involving x/y. The speed of the cherries seemed about correct, but the directions are definitely wrong. Instead of spreading the cherries evenly along a circle, they're all bunched up! In fact, they're all bunched up near 0, which is what curDir starts out as. At this point, curDir being wrong sounds like a very plausible explanation.

So what does curDir do? It's the direction of each cherry for each loop - it stands for "current direction". If we want to spread 30 cherries along a circle, and the first one is at 0, what direction should the next one go? A circle is 360 degrees, so dividing that by 30 gives 12 degrees per cherry!

Ok, so now we have something we can test. We know that the first two cherries should fire at 0 and 12 degrees. How can we see what the actual values are? There are two great methods for this - Debug Messages and The Debugger itself. I'll show you how to use both methods to solve the problem.

Debug Messages

You might have noticed that black box at the bottom of Game Maker before, where it writes a bunch of technical information. Well you can actually use this to write messages to yourself from the game! We want to see the value of curDir, so let's write some code to show that to us. Add one line to the applesplosion script, inside the for loop:

///applesplosion(x,y,count,speed) script with error
var count=argument2;
var curDir=0;
var spd=argument3;
var xcenter=argument0;
var ycenter=argument1;
for (i=0; i<count; i++) {
    show_debug_message(string(curDir)); //Add this line
    var cherry=instance_create(x,y,objCherry);
    cherry.direction=curDir;
    cherry.speed=spd;
    curDir+=count/360;
}

show_debug_message is a function that takes a string and prints it out to the console window in Game Maker, as it is called. Since curDir is a number, we use the string function, which turns it into a string. When we run it, this is the output we get:

Console Output from show_debug_message

So we expected the first two to be 0 and 12, but they are 0 and 0.08! So now we know curDir is definitely being calculated incorrectly. Looking back at the code, we see curDir gets count/360 added to it every step. count is 30, so this works out to 30/360, or 0.08... oops! What we really wanted there was 360/count.

As a small note, game maker truncates numbers to two decimal places when printing them with string() - 30/360 is really 0.08333 repeating. If you want extra precision, use string_format.

The Debugger

Adding debug messages is a good way to fix quick problems, but sometimes you need more than that. It would be great if we could actually walk through the code, step by step, and see what it's doing with our own eyes. Luckily for us, Game Maker Studio comes with a powerful, modern debugger that allows you to deeply analyze your game while it runs. Normally, when you test your game, you use the green arrow button or the F5 key. To access the debugger, press the red arrow button next to it, or the F6 key. When you do, you'll be greeted by a new window, the GameMaker: Studio Debugger.

GameMaker: Studio Debugger Window

If you're running this along at with me, your debugger window will liekly look different. The debugger allows you to customize the way it looks, choosing from a wide array of displays and positions. To configure what is displayed, you can right click any of the blue title bars, and choose "Split" or "Set Type". Set Type will change what the current panel displays, and split splits it into two horizontally or vertically. For our demonstration, configure your debugger so that you can see the Source and Locals panels like in the screenshot above. Once you do that, open the applesplosion script in the resource browser on the left, and it will display the code in the Source panel.

Now we'll learn about Breakpoints. A breakpoint is like a stop sign - when the program reaches a line with a breakpoint on it, it will pause execution and allow you to analyze the program state at that point. Set a breakpoint on the curDir line by double-clicking the line number to the left of it (line 10 in my screenshot).

A Breakpoint, Denoted by a Red Circle

Now, when the program is about to set curDir, it will freeze and let you debug it. Open up your room and touch the applesplosion trigger, and the debugger will pop up with the curDir line highlighed! On the right, you will also see a list of all the variables currently in scope, as well as their values. Right now, nothing looks out of place, because this is the first run through the loop. curDir is 0 as we expected.

We need to see what it is on the next iteration of the loop. You can do by pressing the green run button at the top left, which will resume execution (until another breakpoint is hit). So click that, and the debugger will run back to this line again.

Debugger, After Two Loops

Over on the right you can see that curDir is now 0.08, not 12 like we expected! Why could that be? count/360 was added to curDir, what value was that? We can see that count is 30, and 30/360 is... 0.08. What we really wanted was 360/count, or 360/30. At this point you can close the game and debugger, but if you wanted to keep testing your game, you could remove the breakpoint and press the green arrow button to resume execution as normal.

GMS backups

Beginner Section

If you used GM8.1 and previoius, you may have noticed a .gb1 file created in the same folder as your project when you saved. This was actually just the project file copied and renamed - if you realized you broke something before you saved again, you could open the gb1 file and get your old project back. I have seen multiple peoples' projects saved after an accidental deletion or corruption this way. Surely GMStudio has something similar, right?

Game Maker Studio handles backups a bit differently. It can be configured to automatically keep backups of your project every time you save, and more than one too, so if you don't realize your mistake until a couple of saves later there's still hope. To check the backup settings, click on Edit in the menu bar at the top, and then Preferences. Alongside a ton of other configuration options, you can see the following:

GMS Preferences Window, showing the backup settings.

Set these to whatever you feel comfortable with. The more backups you save, the more space it will take up on your computer - my backup folder is a few GB large! But, in my opinion, the peace of mind is certainly worth it. Remember that this doesn't replace a good offline backup strategy - keeping a recent, good copy of your project on a usb stick or on dropbox helps protect you from bigger catastrophes, like if your hard drive crashes.

Object Wobble

Beginner Section

Have you ever seen an object hovering in place, bobbing up and down, and wanted to recreate that effect yourself? It's actually very easy to do! We refer to this effect as a "wobble" in the fangame community. Below I'll show you how to do a simple wobble effect, and also an optional advanced technique I've learned.

Simple Wobble

To do it yourself, you just have to add a few lines of code to the object that you want to wobble:

//Create event
wobble_speed = 2*pi/room_speed; //speed of the wobble
wobble_distance = 32; //distance of the wobble
aa=0;

//Step event
aa+=wobble_speed;
y = ystart + wobble_distance*sin(aa);

You don't have to understand how it works, just know that you can change the following two values:

Note that we're doing a vertical wobble here, by setting the y position. If you wanted to obble left and right, change y and ystart to x and xstart in the step event. You could even do both at the same time! Try it out and see if you can come up with any neat effects.

Advanced Wobble

I'd like to go a little deeper into the wobble and show you an advanced technique, but this gets a little mathematical. If you've got what you needed feel free to stop reading!

The above technique works great if you want to spawn an object and then let it wobble forever. But what if you want to stop the wobble at some point, and then smoothly fly away? If we do this now, we'd have to calculate the current speed and set it. But what if we could wobble the speed instead of directly setting the position? It turns out we can, and get a very similar effect!

If you know your trigonometry and calculus, you'll know that speed is the derivative of position. Also, cos is the derivative of sin. Using this knowledge, we can take the derivative of our wobble function, and get a new wobble function that we can apply to the speed parameters of the object. (remember that aa is essentially wobble_speed*t, and when we take the derivative with respect to t we apply the chain rule to get the wobble_speed factor).

//Step event
aa+=wobble_speed;
speed = wobble_speed*wobble_distance*cos(aa);

Let's compare the two objects side by side. In the image below, the blue box on the left is controlled by position, and the red box on the right is controlled by speed:

Two wobbling objects

Hmm, it looks like our speed-controlled object is ahead by a bit in its wobble. I believe this is due to us using a discrete system, as opposed to a continuous one. It turns out that we can actually make up for this effect by shifting our sin parameter back just a bit at the start:

//Create event
wobble_speed = 2*pi/(room_speed*0.5); //speed of the wobble
wobble_distance = 64; //distance of the wobble
aa=0-wobble_speed/2;

After testing this, I've confirmed that the wobbles are identical. It's not a major problem, and I bet no one would ever notice it, but if you need that perfect sync then you can get it like this.

Now that you're controlling your wobble by speed, you can do neat things like wobbling in an arbitrary direction - just apply the wobble to speed and set direction to whichever direction you want! Or, when you're done wobbling, stop applying the function and your object will continue on in whatever direction it was going at the speed it was going when you stopped! Or even change the direction while you're changing the speed to get an... interesting effect like in the image below. And people said I'd never use math again after highschool!

I call it... the inverse clover!

Hit Points (HP)

Intermediate Section

By now you may be well versed in the art of instance_destroy() to destroy things. For instance, maybe you put it in a Collision with Bullet event so that you can destroy things when you shoot them. But that's pretty boring, a good boss needs to take a few hits before it dies! Or maybe you want to break the boundaries, and let the kid take a few hits before he goes out! Both of these ideas are based on the concept of Hit Points, or HP for short. In short, you'll keep a counter of how many hits something can take, and perform the death sequence once that counter hits zero. Here, we'll take a look at how to apply that to enemies, bosses, and the kid himself.

Enemy HP

Intermediate Section

Setting up enemy HP is very simple, because all we will be doing is delaying the actual instance_destroy call. Let's start with our basic Collision with Bullet event:

with (other) instance_destroy(); //destroy the bullet
instance_destroy(); //destroy ourselves

The code above will destroy the object after a single bullet, in effect giving it one HP. In order to have more HP, we need to first set up a counter to hold how much HP we want, and then write the supporting code to utilize that value. In the object's Create event, add the following:

hp = 5; //give our enemy 5 hit points

Of course you can change this to however much HP you want. Then, back in our Collision with Bullet event, replace the code from earlier with this;

with (other) instance_destroy(); //destroy the bullet
hp -= 1; //decrement the HP by 1
if (hp<=0) { //if our HP is less than or equal to zero
    instance_destroy(); //destroy ourselves
}

Pretty simple! Now, when a bullet collides, we only destroy the instance if the HP has run out. I always check if the HP is less than or equal to zero instead of just equal to zero just out of safety. In reality, your enemy should never end up with less than zero HP, but this way you can be sure that he will die.

You might be thinking that the enemy just disappearing here is a pretty boring way to kill it right? What if you want a death animation? Well, instead of calling instance_destroy, you could do something like dead=true, and then check that value in the instance's step event and play an animation if it's true. Or maybe create a fancy explosion or blood splatter while destroying the enemy. Just add your custom behavior inside the if (hp<=0) statement!

Invulnerability Frames (I-Frames)

Intermediate Section

If you're familiar with fangame bosses, you'll probably understand what I mean when I say i-frames. I-frames are a period of invincibility after being damaged, which prevents you from spamming down a boss with a bunch of quick shots. Let's get right to the good stuff and see how we should edit the code from the previous section to allow for i-frames:

//Create Event
iframes=0; //start out without any iframes
//Collision with Bullet event
with (other) instance_destroy(); //destroy the bullet
if (iframes<=0) { //if we aren't in i-frames
    hp -= 1; //decrement the HP by 1
	iframes=30; //give us 30 i-frames
    if (hp<=0) { //if our HP is less than or equal to zero
        instance_destroy(); //destroy ourselves
    }
}

But don't get too excited just yet! As we've got it now, our boss will set its i-frames value to 30 when it collides with a bullet, but the frames never tick down! To fix this, we'll need to add some code to the step event:

//Step Event
if (iframes>0) { //if we have iframes
	iframes-=1; //count down the frames
}

Now, every step we have i-frames, the counter will tick down until we're out of them, at which point the enemy will allow you to shoot it again. At this point, we've got functional i-frames, but we need to let the player know when you can and can't shoot the enemy, right? A quick-and-dirty way of doing this is to make the enemy partially transparent while he has i-frames. Let's edit the step event to do that:

//Step Event
if (iframes>0) { //if we have iframes
	iframes-=1; //count down the frames
	image_alpha=0.5; //make the enemy half-transparent
} else {
	image_alpha=1; //make the enemy fully opaque
}

Boom! We're done. Another common method is to have the enemy blink while in i-frames; you can do this with an alarm event by doing visible=!visible if iframes is greater than zero (but don't forget to stop the alarm and set visible=true again when the iframes are done!) You are of course encouraged to think up other ways you might have a damage indicator, just check if iframes>0 to know when to do it!

Kid HP

Advanced Section

You might have seen an avoidance game like I Wanna Beat the Random Numbers which lets you get hit by multiple projectiles before actually killing you. You might be thinking you can just apply the code from earlier to the kid, right? Well it turns out it's actually a bit more complicated than that. First off, the kid doesn't just instance_destroy itself on contact with a objPlayerKiller object. Looking in the Collision with objPlayerKiller event, we see this:

scrKillPlayer();

Are you thinking what I'm thinking? Yes! You can wrap that up in the code we saw earlier:

hp -= 1;
if (hp<=0) { 
    scrKillPlayer();
}

So now you've set up the hp variable in the create event, and changed the collision event. Ok, so that's prety simple, what's the problem? Well, the objPlayer object is a Persistent object. This is something we haven't really covered in the tutorial anywhere. There are only two persistent objects in the standard engine: objPlayer and objWorld. A persistent object is special, because when you change rooms, persistent objects do not get destroyed. They stay loaded and keep the state they had when you changed rooms. This allows our player to switch rooms without us having to create a new one every time we switch, but comes with some side effects.

So what does our player object being persistent have anything to do with HP? You player's HP is part of its state, which is kept between room transitions. Also, your HP will be reset every time the player object is recreated, which happens when you touch a warp without warpX or warpY set, or you press the restart key (usually R).

As you can see, it's a bit more complicated than a non-persistent object, because non-persistent objects are easier to keep track of. There's no simple answer for how to continue here, it's really up to how you want to handle player HP in your game. Do you want your player to have 1 HP everywhere in your game, except for a boss fight? In his Room Start event, set hp=5 if the current room is the boss room, or hp=1 otherwise. Do you want to have a set amount of HP for the entire game? You'll need to make the hp variable global, and then add it to the save file and don't let the player continue if it's zero (See the Extra content in saves section for more information on that). You'll first have to figure out what you want the player to have HP for, and then come up with a solution on how to work it out.

Playtesting

Beginner Section

Guest Section, written by Kyir

Testing is critical to the production of high-quality fangames. There’s nothing worse than publishing your game, only to be told that a jump is impossible, or a warp is broken, or that some other critical element of your game is malfunctioning. These are all problems that can be solved by playing your own game during development, but what about difficulty balance, finding skips, and ensuring that it is clear what the player should be doing? These are all far more difficult for the developer to discern on their own, since their knowledge of the inner workings of the game and experience with the platforming make them a poor representation of the average player.

Thus, we turn to playtesting, where someone else tests your game for you. Picking someone to playtest for you can be difficult, but here are some things to consider while making your choice.

As a Creator

As a Tester

The situation is not so different for those asked to test a game. You may not have put hours of work into the product, but you are taking on the responsibility of doing what you can to ensure that a quality game is produced. Here are a few factors to keep in mind while doing your testing and writing feedback:

As a creator you should not feel compelled to make ever change your testers recommend, and as testers you have to keep that in mind, but respectfully giving and receiving advice can do nothing but improve the quality of a fangame, no matter what sort it is.

Menu customization (WIP)

Intermediate Section

Coming Soon!

Extra content in saves (WIP)

Intermediate Section

Coming Soon!

Particles (WIP)

Intermediate Section

Coming Soon! Here's a particle system generation tool in the meantime:

Crystalline

Data structures and other code (WIP)

Advanced Section

Coming Soon!

Avoidance basics (WIP)

Advanced Section

Coming Soon! Here's an avoidance planning tool in the meantime:

Erunatyan's Avoidance Tool

View Manipulation (WIP)

Advanced Section

Coming Soon!

Aligns (WIP)

Intermediate Section

Coming Soon!

Extra Resources & More Reading

That covers everything I have to tell you about game making! I may be done, but I hope this is only the beginning for you! If you need some more help, feel free to come ask in our community forums or discord server. I look forward to the games you make!