If you're looking at this, that either means that you want to learn how to use surfaces because it sounds interesting, or you just got linked here on accident or something.
A surface in gamemaker is basically a drawing canvas. Just like the game screen, you can draw things on this surface. The difference between surfaces and the game surface is that you can manipulate surfaces in a wide variety of ways while not affecting the game screen. Surfaces are insanely useful in terms of graphics, as they are used for the most complex things like proper lighting engines, screen effects, and even get used in some fangames! (Remember Signore's purple warp?)So now we know what a surface is, but obviously we're not just here to hear just that. That'd be dumb as crap, so now I'll talk you through the steps of making a surface, drawing to the surface, and manipulating it! Awesome, right? Let's do this.
What we're going to do is make an object which makes each fourth of the screen wave around while also having different colors drawn to each fourth.
Step 1: Making an object for the surface.Super simple. We'll make an object so that we can define the surface and do all those cool things with it. The recommended qualities for the object are:
Title: oSurfaceWaveScreen
Sprite: No Sprite (We're not gonna be involving a sprite with the surface.)
Visible=1 (We've gotta make the effect visible, right?)
Solid=0
Depth=-100 (The surface will appear over most of the objects on the screen by doing this.)
Persistent=0
Parent: No Parent
Mask: Same As Sprite / No Mask
Step 2: Defining the events and actions.Create Event:surf=surface_create(800,608);
//End Of CodeWhat this does is define the variable "surf" as a newly created surface with a width of 800 and a height of 608.
Room End and Destroy Events:surface_free(surf);
//End Of CodeWhat this does is it frees the "surf" surface from the RAM so that we don't end up having another "surf" surface floating around uselessly whenever the game restarts or the room ends.
Step Event:if !surface_exists(surf){
surf=surface_create(800,608);
}
surface_set_target(surf);
visible=0;
with(GAMEOVER)visible=0;
screen_redraw();
with(GAMEOVER)visible=1;
visible=1;
surface_reset_target();
//End Of CodeAlright, so now this'll probably seem odd and confusing, so I'll walk you through it.
The reason for this part:
if !surface_exists(surf){
surf=surface_create(800,608);
}
Is because surfaces are stored in RAM. Normally they'll stay there, but there's always an odd chance that they'll leak out of the memory. In order to make sure that we're always drawing on a surface that exists, we use this code to assure that the "surf" surface exists.
The function surface_set_target() is what sets the surface you'll draw on. If we don't want to draw on the game surface and instead on the "surf" surface, we use this code to make that change.
Now onto the next lines in the code.
visible=0;
with(GAMEOVER)visible=0;
screen_redraw();
with(GAMEOVER)visible=1;
visible=1;
This is confusing for a variety of reasons, but I'll make sure you understand it at its fullest. Basically, it makes the surface invisible, makes the GAMEOVER object invisible, and then redraws the screen. Why this is amazing is because what we're doing isn't actually drawing it on the game surface. We're redrawing the whole entire screen...On the "surf" surface! Since we've copied the screen, we can make the GAMEOVER object visible again and make the surface visible again. That's the reason for this code.
The surface_reset_target() function works almost exactly like the surface_set_target code, but all it does is switches the drawing surface back to the game surface.
Draw Event:draw_set_color(c_black);
draw_rectangle(0,0,800,608,0);
if surface_exists(surf){
r+=2;
for (i=0;i<4;i+=1){
switch i{
case 0:
col=make_color_rgb(255,255,0);
break;
case 1:
col=make_color_rgb(0,255,255);
break;
case 2:
col=make_color_rgb(255,0,255);
break;
case 3:
col=c_white;
break;
}
draw_surface_part_ext(surf,i*200,0,200,608,i*200,32*sin(degtorad(r+(90*i))),1,1,col,1);
}
}
//End Of CodeThis code might look like absolute nonsense to a novice gamemaker coder, but either way I'll make sure you understand it. It's actually not that complex.
draw_set_color(c_black);
draw_rectangle(0,0,800,608,0);
The reason for this is that even though we've got the screen drawn to the surface, we've also got the original screen, unchanged, sitting there behind it. We'll make the original screen blank by putting a gigantic rectangle over it. What we do next is execute the following code whenever the "surf" surface exists:
r+=2;
for (i=0;i<4;i+=1){
switch i{
case 0:
col=make_color_rgb(255,255,0);
break;
case 1:
col=make_color_rgb(0,255,255);
break;
case 2:
col=make_color_rgb(255,0,255);
break;
case 3:
col=c_white;
break;
}
draw_surface_part_ext(surf,i*200,0,200,608,i*200,32*sin(degtorad(r+(90*i))),1,1,col,1);
}
Basically, what we do is increase the variable "r" each frame. We'll use it later.
Aside from that, we start a "for" loop. Basically how it works is it repeats the same code, but each time having "i" be a different value. In that loop, the switch statement checks the variable "i" from the for loop and uses it to set the variable "col" depending on what value "i" is. After that, we draw a part of the "surf" surface. As you should remember, we drew the entire screen onto the "surf" surface, so now we can have our fun with it. Basically, since the "for" loop will repeat 4 times, we draw a different part of the surface 4 times. This is where it gets really tricky to explain.
The arguments for the draw_surface_ext() function are: ID, Left, Top, Length, Height, X, Y, Horizontal Repetition, Vertical Repetition, Color, Alpha.
We're obviously drawing from the "surf" surface.
The left of the part is dependent on "i". Since "i" ranges from 0 to 3, we'll have one part's left be 0, one be 200, and up to 600.
The top of the part is 0. This is so we always draw the correct part of the surface.
The length of every part is 200, because that's exactly 1/4 of the room width.
The height of every part is 608 so we draw the correct part.
The X is also dependent on "i". We won't change this.
The Y position is 32*sin(degtorad(r+(90*i))). This may sound odd, but there's a good reason for this. To make each part wavy, we use the sine function which plots points in a perfect wavy pattern. the degtorad() function simply converts degrees into radians, which is the sine function's way of working. We use the "r" variable as the base degrees, but we also add "i*90" degrees to it. This is how we make the parts wavy.
No extra horizontal or vertical repetition of the part is needed; We're only drawing the part once.
The color is dependent on the "col" variable defined by the switch statement above. Basically, we'll draw one part yellow, one part cyan, one part magenta, and one part white. Gamemaker blends the colors and does amazing things with them.
The alpha is 1, because we need to make it fully visible.
After that, the function is called, the for loop ends, and the code closes.
We'll see what we just created in a gif form! Although, I'd suggest you put it in gamemaker yourself too to see how it affects the screen.
This is what the end result should be similar to:Don't mind the tiles or apples. I was bored when making that.
This concludes the tutorial. This is only getting a certain screen effect, though. You'll have to do a whole bunch of experimentation when you want a fancy screen effect of your own. Now that you know the basics of making a surface, I hope you enjoyed the tutorial!