Tech

Surfaces and Transitions - Part 1

Hello everyone! The following awesome guest article was written for us by David Strachan, if you found this useful he has lots of other great animated tutorials, guides and articles for GameMaker over at his website. There is a full source download available linked just below, which will also give you a sneak preview of part two! Enjoy! - Shaun

When Shaun Spalding approached me to write a guest blog article I knew I wanted to do something at an intermediate level to help those who already have the basics down and understand how GML works.

So for this guide I’m going to showcase surfaces in GameMaker as it is one of the many features I feel doesn’t get the attention it should. For the last few months I have been obsessed with surfaces and how they can be used for masking, lighting, outlines, shadows, and countless other powerful graphical features.

We will be learning how to create 3 different room transitions starting off easy and each one just getting a tiny bit more complex. In this part we will cover just the first. Now I’m sure you are already thinking “There are already loads of guides on screen transition what makes these special?” Well unlike most, these screen transitions are able to show both rooms at once.

Let’s look at the three transitions we are going to make:

Not only do these transitions appear to show two rooms at the same time, but in the final transition the second room looks like it has been broken up into chunks. However this is just an illusion and is actually just many images that have been put together to look like this.

If you haven’t used surfaces before they are basically an empty canvas you can draw onto in the same way you draw any sprite onto the screen and anything you draw there is saved, these surfaces can then themselves be drawn onto the screen with everything you have added onto them.

In this article I will show you how to capture images of the current state of the screen and the basic method we will be using to trigger the transition and keep track of how far along the transition is. We will do this with a sliding transition:

An Overview of the Project

The project consists of two rooms and 8 objects:

3 of these objects are the buttons that create the transition

1 is a master parent button

1 is a back button

so we can ignore all of those. The 3 objects we are interested in are:

obj_transitionslide

obj_transitionquarters

obj_transitionbars

When these objects are created a transition will start.

In this part we're just going to be looking at the first one, obj_transitionslide!

obj_transitionslide

This simple, yet stylish transition can be adapted for users on mobile devices that want to be able to flick the screen across to change the room and have the room move 1 to 1 with the player’s finger.

CREATE:

currentframe = 0
maxframes = 45
persistent = true; // when changing room keep this object alive
// copy the old room so we can display it on the second room
sur_oldroom = surface_create(room_width,room_height);
surface_copy(sur_oldroom,0,0,application_surface)
// We have recorded what the old room looks like so we can instantly go to the next room.
room_goto(room_second)

currentframe and maxframes – Used to record how long the transition lasts and how far through it we are. If you want to make any of these transitions last longer just make maxframes a larger number.

persistent – This tells GameMaker that when we change the room we do not want this object to be destroyed.

surface_create() – We use surface_create() to make a variable to store the surface.

surface_copy() – This is used to duplicate a surface. The clever bit here is it duplicates application_surface which already contains an image of how the screen currently looks.

Together surface_create(), surface_copy() and application_surface basically take a screenshot of the game.

Side note: Depending on your game you might want to use maxframes=room_speed*1.5 this would allow you to detach the length of the transition from the room speed and use a more absolute timing system. Also you will have to remember not to move anything or start any animations on the next room until the transition has finished.

STEP

currentframe++
if (currentframe > maxframes) {
instance_destroy() // The transition has finished so destroy it
}
// We are now on the second room so record that room.
if (currentframe == 2) {
sur_newroom = surface_create(room_width,room_height);
surface_copy(sur_newroom,0,0,application_surface)
}

The step event does two things; If the transition has finished it destroys the object, and on the second frame it records what the new room looks like just like we recorded the first room. At this point, we have stored in sur_oldroom an image of the old room and in sur_newroom an image of the new room.

DRAW GUI

if (currentframe > 1) {
// convert the number of frames that have passed into a number between 0 and the room width
var slideamount = EaseOutQuad(currentframe,0,room_width,maxframes)
if (surface_exists(sur_oldroom)) {
draw_surface(sur_oldroom,-slideamount,0)
}
if (surface_exists(sur_newroom)) {
draw_surface(sur_newroom,room_width-slideamount,0)
}
}
/// I do this to hide the flicker where the next room pops up for 1 frame
if (currentframe == 1) {
if (surface_exists(sur_oldroom)) {
draw_surface(sur_oldroom,0,0)
}
}

We use EaseOutQuad() (see below, you don't have to use this script.) to create a number between 0 and room_width that gets bigger the more frames that have passed, we then draw the two surfaces next to each other and offset them by this number to make it look like they are both sliding simultaneously.

All of that code is pretty intuitive apart from that little chunk at the end. The reason we want to flash up an image of the old room for one frame is because if we didn’t there would be a flicker when changing room. This happens because we would normally need to display the new room for one frame so we could take an image of it, however recording the application_surface in the step event allows us to record what the room should look like and then overwrite this by drawing in the draw_gui event. *shrugs* I don’t know why, it just works.

DESTROY

surface_free(sur_newroom)
surface_free(sur_oldroom)

So last thing to do is tidy up when we are done with the transition.

Scripts for Easing and Tweening

I think I better mention the 3 tabbed scripts I have also used. These include some very basic maths that allows you to do some very clever things. Basically these scripts help you to draw graph curves. It does this by providing an input range and an output range, it will then transform where a point on the input range would fall between the output range. It actually goes further than that because that would be a linear conversion, these also converts points that do not have even gaps between them. You don’t have to use them but that’s what makes the images look like they smoothly glide along and slide to a halt.

So that’s the first transition!

From this you should have learnt how to record an image of the whole screen and move this information into another room.

You will have noticed that every time I drew the surface to the screen I first tested to made sure it existed. This is very important because surfaces are volatile and can be removed from the memory without notice.