Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411423 Posts in 69363 Topics- by 58416 Members - Latest Member: JamesAGreen

April 19, 2024, 03:47:45 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityTownhallForum IssuesArchived subforums (read only)TutorialsSurfaces in Game Maker Tutorial!
Pages: [1] 2 3
Print
Author Topic: Surfaces in Game Maker Tutorial!  (Read 53347 times)
ChevyRay
Guest
« on: July 25, 2009, 07:26:27 AM »

Using Surfaces in Game Maker



Where Chevy explains one of Game Maker's less understood, yet sexy and powerful features.

I wrote a Game Maker tutorial awhile back that explained how to use Game Maker's Surfaces to scale the view without getting blurry results or strange tiling problems. Since then, I've probably gotten an email every week from somebody who has run into issues and errors using the scripts. I've come to realize that this is because a general lack of knowledge on how Surfaces work in Game Maker, and what is actually happening when you use them. So I'm writing this tutorial to clear these things up!

What you will need
You will need the Pro Edition of Game Maker to use the Surface functions used in this example. The Pro Edition is a measly $25/€20/£20, and can be purchased here.

What you should know
This tutorial is probably best for people who have a moderate or firm grasp of GML coding, and are familiar with Game Maker's layout.


1. Surfaces, Explained!


Quote from: Game Maker Manual
In certain situations you might want to paint not directly on the screen but on a canvas that can then later be used to paint things on the screen. Such a canvas is called a surface.

Alright, what happens when you want something to appear on the screen? Simple. We use a draw_ function, as any intermediate GML coder will know. For example, let's say we take this handsome gentleman here (who will be our subject for the day)...



And Make him into a sprite called sprBald, and place the following code in the draw event of any object:

Code: (Draw Event)

draw_sprite(sprBald, 0, 0, 0);


The result will be something like this:



Duh, Chevy. Smiley But what exactly is this draw_sprite function doing? The function takes the bitmap information from sprBald and copies it onto the screen, which is the visible canvas on which all your game's visuals are shown. Just like the Manual explains a Surface as a canvas, the screen is also a canvas!

So when I told draw_sprite to draw the character at position (0, 0), I am actually telling Game Maker to draw the character at that position on the screen canvas. So now, what do these fancy Surface things do?

A Surface is just a different canvas. Meaning instead of drawing the information onto the screen, you can choose to draw it on a specific surface other than the screen. The key difference is that your own Surfaces will be invisible, and not displayed. Why? Because Game Maker is told to only show one Surface, the Screen. Smiley In the next section, I will show you how to make them visible.

So, now we know this -- we can draw things onto a Surface just like we draw things onto the screen! Here are the main things you need to know about drawing on a Surface vs. drawing on the Screen:

  • The Screen is the default Surface that draw_ functions are painted on.

  • The Screen is cleared every step of the game. This is how we get the illusion of moving objects, because they are constantly being cleared and drawn in a new position, and appear to be moving across the screen. This is also why things drawn in a step event will not show up, because the screen is cleared at the end of the step, and all your objects' draw events are called.

  • The Screen surface's size is room_width x room_height

  • Custom Surfaces can be a size of your choosing, and are not restricted to the room size.

Also, it is very important to note the following things about surfaces:

Quote from: Game Maker Manual
  • You should never change the drawing target while you are actually drawing on the screen, that is, never use it in drawing events. This will cause serious problems with the projection and viewport.

  • Surfaces do not work correctly with 3D mode. You can use them while not in 3D mode (by calling d3d_end() before using them, but once you start 3D mode again the surfaces will be destroyed.

  • For reasons of speed, the surface is maintained in videomemory only. As a result, you might lose the surface when e.g. the screen resolution changes or the screensaver pops up.

  • Surfaces will not be saved when saving a game.

And finally...

Not all video cards support Surfaces!

Certain video cards will not display surfaces properly. Some give awful background effects when transparency is supposed to be drawn, and others simply refuse to even create the surfaces. When coding Surfaces into your game it is suggested that you either:

   1. Warn people of the system specs required to run the game, or

   2. Provide alternatives in your game for users that run into such errors, and cannot play the game. For example, you could have an option that allows the user to turn off surfaces. They may not get nice screen scaling, or miss out on some nice special effects, but at least they won't be completely alienated from the game.
Logged
ChevyRay
Guest
« Reply #1 on: July 25, 2009, 07:26:39 AM »


2. Drawing on Surfaces!


Download .GMK Source

Quote from: Game Maker Manual
They are actually rather simple to use. You first create a surface. Next you indicate that further drawing should happen on this surface. From that moment on all drawing functions operate on the surface. Once you are done you reset the drawing target and further drawing happens on the screen again.

In the previous step, I drew our subject, sprBald onto the Screen using draw_sprite. Now, how would one go about drawing Mr. Bald onto a custom surface instead? Here are the steps:

Step 1: Create the Surface

In order to draw on a surface, first it has to exist. Here is how we would create a 240 x 160 surface called my_surface:

Code:

my_surface = surface_create(240, 160);


surface_create is a function that creates a brand new surface. But just like we use the handle sprBald to refer to our character sprite, we need a handle to refer to our new surface. Just like if we were to set variable = 10, we can set the variable my_surface to the value of the new surface.

Now, any time we want to refer to this particular surface, we can use my_surface. Next step!

Step 2: Changing the Drawing Target

When you normally use a drawing function, such as draw_sprite or draw_background, they are drawn onto the Screen. This is because our current target surface is set to the Screen. So knowing that, if we want to now draw onto our new surface instead, all we have to do is change the drawing target to that specific surface! That is done like so:

Code:

surface_set_target(my_surface);


After this function has been called, all draw_ functions will happen on your targeted surface, instead of the Screen. But eventually, you'll need to switch the drawing target back to the Screen; this can be done with the following function:

Code:

surface_reset_target();


Knowing this, we can draw our character onto the Surface just like we did with the Screen before. In the Creation Event of an empty object, I can put the following:

Code: (Creation Event)

surface_set_target(my_surface);
draw_sprite(sprBald, 0, 0, 0);
surface_reset_target();


And it is done! Now, what happens when I put that object in the room?



... nothing. Of course, because what I'm looking at is the Screen, not my_surface! Nothing has been drawn on the Screen yet, which is why the display is empty. But now I've reset the drawing target to the Screen with surface_reset_target(), so now all I have to do is draw the Surface to the screen!

This is done simply by placing this in the object's Draw Event:

Code: (Draw Event)

draw_surface(my_surface, 0, 0);


Now my_surface, and everything that has been drawn onto it, will be drawn onto the Screen! I run the game again, and what do I see?




Download .GMK Source


Next up, we will tackle some more advanced features of Surfaces, and I will show you a couple of tricks.
Logged
ChevyRay
Guest
« Reply #2 on: July 25, 2009, 07:26:56 AM »


3. Exploiting Surfaces!


Now you know how to create a surface, draw stuff onto it, and then how to draw it to the screen. When you think about it, a Surface isn't really different than a background, is it? It's just a bitmap that you can draw onto the screen. The thing about Surfaces, though, is that you can change what is in it at runtime using draw events and the such. So where backgrounds are static and remain the same, Surfaces are dynamic and can be changed anytime you want.


Clearing a Surface


It's very useful to know how to clear a surface. In the previous example, we drew sprBald onto the surface at (0, 0), but say now we want him to instead be at position (50, 50) in the surface. Let's see what happens when we draw him on the surface again. In the Press Space event for the object, I will add the following code:

Code: (Press Space)

surface_set_target(my_surface);
draw_sprite(sprBald, 0, 50, 50);
surface_reset_target();


When I run that and press space, here's what happens.



Why? Because surfaces, unlike the screen, are not automatically cleared each step. So every time I draw on a surface, I draw on top of whatever already exists on that surfaces. If I want to clear a surface, I have to use the following code (which I have placed in the object's Press Enter event.

Code: (Press Enter)

surface_set_target(my_surface);
draw_clear_alpha(0, 0);
surface_reset_target();


You can download the source .gmk: HERE.

This basically clears the whole surface with the color 0 (c_black) at alpha 0 (fully transparent). As a result, the surface is cleared and is now completely transparent again. Normally, it is a good idea to call a draw_clear function on a surface right after you create it, because sometimes surfaces will be created with a bunch of garbage data from your video memory because of the way Game Maker stores them.

You can similarily use draw_clear(c_black) if you want the surface to be fully black, or any other color, instead of transparent.


Shapes & Polygons on Surfaces


Now we know that information drawn onto a Surface will remain there, how can we use that to our advantage? One of the first thing that comes to mind is Polygons. Game Maker, as some of you know, has the ability to draw polygons using some of the advanced drawing functions. For example, the following code would draw a triangle on the screen:

Code:

draw_primitive_begin(pr_linestrip);
draw_vertex(0, 100);
draw_vertex(100, 100);
draw_vertex(50, 0);
draw_vertex(0, 100);
draw_primitive_end();


That's not too bad, Game Maker can handle that. But 6 lines of code to draw a single triangle! If you wanted to draw more advanced shapes, you'd have huge lists of code that had to be re-interpreted every step of the game! Re-drawing all that information every step of the game is a waste, especially if it isn't changing, right?

So the trick is, instead of drawing it to the screen, draw it to a surface! So now, you can just perform this code once:

Code:

surf_triangle = surface_create(100, 100);
surface_set_target(surf_triangle);

draw_primitive_begin(pr_linestrip);
draw_vertex(0, 100);
draw_vertex(100, 100);
draw_vertex(50, 0);
draw_vertex(0, 100);
draw_primitive_end();

surface_reset_target();


And instead of having to calculate this triangle every step, you can just use draw_surface(tri to draw that triangle to the screen because it is stored in the surf_triangle surface! With really advanced polygons, you can really save a lot of processing time for your game.
Logged
ChevyRay
Guest
« Reply #3 on: July 25, 2009, 07:27:38 AM »


4. Scaling the Screen!


Pending.

I'm off to a friend's wedding for now! I'll be back with the rest of this tutorial later folks Smiley and to reply to any questions, comments, crits, etc.

Hope you find it all useful so far! <3
Logged
ChevyRay
Guest
« Reply #4 on: July 25, 2009, 07:28:47 AM »

I'll just reserve this post as well, in case I decide to expand the tutorial more.
Logged
GregWS
Level 10
*****


a module, repeatable in any direction and rotation


View Profile
« Reply #5 on: July 25, 2009, 09:34:35 AM »

Wow; thank you Chevy!  This is brilliant, because it explains it a lot more than that little resolution fix using surfaces thing you'd showed us all awhile back (which was also awesome).  And the polygon trick is great!  Grin
« Last Edit: July 25, 2009, 09:42:51 AM by GregWS » Logged
Mir@k
Level 1
*


Pffffffft


View Profile WWW
« Reply #6 on: July 25, 2009, 11:31:46 AM »

I have a rather stupid question, how could surfaces be useful in games? Like, picture me an scenario. I understand that they are like dynamic backgrounds, but i still don't quie get what they could be applied to, or in what cases.
Logged

GregWS
Level 10
*****


a module, repeatable in any direction and rotation


View Profile
« Reply #7 on: July 25, 2009, 12:34:10 PM »

The most practical one is the section that Chevy hasn't finished.  You can use a surface to scale up a low-resolution game without the awful blur issues that you'd get using GM's built-in scaling system.  Smiley
Logged
ஒழுக்கின்மை (Paul Eres)
Level 10
*****


Also known as रिंकू.


View Profile WWW
« Reply #8 on: July 25, 2009, 12:38:43 PM »

I have a rather stupid question, how could surfaces be useful in games? Like, picture me an scenario. I understand that they are like dynamic backgrounds, but i still don't quie get what they could be applied to, or in what cases.

one simple example: when text is drawn on the screen every step, it's very slow. drawing a lot of text on the screen at once (not bitmapped fonts, just normal truetype fonts) can slow the game down enormously. instead, you can draw the text to a surface, and then draw the surface, which speeds up the game quite a bit.

there are a million uses of them though; it's a pity more video cards don't support them.
Logged

Carnivac
Level 0
***



View Profile
« Reply #9 on: July 26, 2009, 12:45:52 PM »

The most practical one is the section that Chevy hasn't finished.  You can use a surface to scale up a low-resolution game without the awful blur issues that you'd get using GM's built-in scaling system.  Smiley

Yeah I use this a lot not just cos of the sharp clean low res pixels but also I can add arcade like scanlines on top which are the in real resolution rather than the simulated one.  Also rotating sprites works properly in that they keep the blocky pixels rather than the higher res which looks odd.

Unfortunately there are drawbacks...

there are a million uses of them though; it's a pity more video cards don't support them.

Yup.  All the reports I've had back of my stuff not working properly (due to the surfaces) have been by people who've all listed various types of GeForce cards whereas I didn't know this since I use an ATI Radeon which the surfaces work perfectly on.  Maybe GM8 fixes this, I don't know.  Most of the stuff I've heard about the new version seems to focus a lot on the updated image editor which I still likely won't use much other than last minute tweaks.  Why should I when I have the far superior Pro Motion?  I've been waiting for better a better room editor personally...
Logged

___
Vice President of Marketing, Romeo Pie Software
Level 10
*


View Profile
« Reply #10 on: July 26, 2009, 04:25:53 PM »

Quote
You should never change the drawing target while you are actually drawing on the screen, that is, never use it in drawing events. This will cause serious problems with the projection and viewport.

I thought we determined that everything was fine when this happens.

Quote
I've been waiting for better a better room editor personally...

 Beer!
« Last Edit: July 26, 2009, 04:30:44 PM by xerus » Logged
GregWS
Level 10
*****


a module, repeatable in any direction and rotation


View Profile
« Reply #11 on: July 26, 2009, 04:57:45 PM »

All the reports I've had back of my stuff not working properly (due to the surfaces) have been by people who've all listed various types of GeForce cards whereas I didn't know this since I use an ATI Radeon which the surfaces work perfectly on.
Huh, funny you say that, because surfaces work fine for me and I'm using a GeForce card (Go 7400).

I've been waiting for better a better room editor personally...
Yeah, given that I've had to create myself a custom editor for my current project, I can definitely agree with that.  Lips Sealed
Logged
ChevyRay
Guest
« Reply #12 on: July 26, 2009, 07:20:21 PM »

Quote
You should never change the drawing target while you are actually drawing on the screen, that is, never use it in drawing events. This will cause serious problems with the projection and viewport.

I thought we determined that everything was fine when this happens.
Yeah, but I haven't tested this on many different systems or situations, etc. So I don't want to take the blame if somebody does routinely use it and it ends up causing a lot of problems for certain users Tongue

But yeah, it'd be interesting to get some more reports from people to see if it is actually fine to do, because I've had no problem with it so far.

Quote
The most practical one is the section that Chevy hasn't finished.  You can use a surface to scale up a low-resolution game without the awful blur issues that you'd get using GM's built-in scaling system.
I can't really agree. I think that is one of the practical solutions, but not the most practical. Only a niche of games created these days use scaled-up resolution, and I don't even know if all of them even care that the image is blurred or not. Actually, surfaces are far more practical to use in cases where you're dealing with a much larger screen and special effects. Or, as Paul Eres said, if you're using lots of text.

If you're using a sprite-based font, you can get incredible slowdown. Try it out: run a simple game using a normal font and fill the screen with it. Tell your game to run at 1000 FPS and see how high you can get it to go in debug mode. Then, make a sprite-based font and fill the screen with it, then run the program again. I doubt you'll even be able to get it to top 150 - 200 FPS. That's a huge price to pay for something really minute, and if your game is graphically expensive in other ways, such as effects and particles, you're not gonna want to waste those precious FPS (just ask Xerus Wink)

So, by drawing it onto a surface, then drawing that surface onto the screen, you take what normally is drawing several hundred different sprites (which are all their own separate surfaces) onto the screen and change it into drawing one simple surface instead, which will be much easier on your game.

Another practical use, which I can't really explain (but I might reserve for a more advanced tutorial later on) is for special graphical effects involving textures. For example, say you want to have dynamic lighting in your game. By using surfaces and some transparency and blending tricks, you can achieve much more realistic and satisfying (not to mention more runtime-friendly) results using surfaces.
Logged
ஒழுக்கின்மை (Paul Eres)
Level 10
*****


Also known as रिंकू.


View Profile WWW
« Reply #13 on: July 26, 2009, 11:53:15 PM »

the reason you're supposedly not supposed to draw to surface during the draw event is that it slows it down -- it interrupts drawing to the screen to draw to a surface, and when you interrupt a process it'll cause it to be slower than if you do that during another time. that's also the reason you're not supposed to calculate stuff heavily during the draw event, or have very many loops, or do collision checking etc. so it's not that it won't work, it's just that it'll make drawing render slower (and have a slower fps) if you pause it in the middle of the drawing step and do complex things than if you do that in the step event.
Logged

pgil
Guest
« Reply #14 on: July 27, 2009, 05:52:07 AM »

that's also the reason you're not supposed to calculate stuff heavily during the draw event, or have very many loops, or do collision checking etc.
Embarrassed
So I guess putting the logic for the entire game there isn't such a great idea....
Logged
Rostiger
Pixelhead
Level 5
******



View Profile WWW
« Reply #15 on: July 28, 2009, 04:39:02 AM »

Oh sweet, thanks for the tut Chevy! I just started with GM a couple of weeks ago with some learning projects and always wanted to get into surfaces at some point. Perfect timing it is!  Beer!
Logged

Clemens Scott
Co-Founder & Artist of Broken Rules
Pencerkoff
CCCP
Level 4
*


Hello I am Pencerkoff


View Profile
« Reply #16 on: September 09, 2009, 04:37:40 PM »

Hello this is Pencerkoff

Excellent tutorial, though it isn't finished.  That wedding still going on or what?

I want to experiment with collision checking and surfaces, but the only way I can think to do it would be to convert a surface to a sprite, which really defeats the purpose (for me anyway).  Is there any kind of surface collision checking?  I'd really love to make a surface of a game map that stores the obstacle information, then only have to check back on that surface for collisions (assuming all obstacles are stationary and indestructible).

-PENCERKOFF


Logged

ChevyRay
Guest
« Reply #17 on: September 09, 2009, 07:15:33 PM »

Yes, I will get to writing the screen-scaling portion of this. It's sort of the reason the whole tutorial was spawned, I guess Corny Laugh
Logged
___
Vice President of Marketing, Romeo Pie Software
Level 10
*


View Profile
« Reply #18 on: September 09, 2009, 10:49:41 PM »

Hello this is Pencerkoff

Excellent tutorial, though it isn't finished.  That wedding still going on or what?

I want to experiment with collision checking and surfaces, but the only way I can think to do it would be to convert a surface to a sprite, which really defeats the purpose (for me anyway).  Is there any kind of surface collision checking?  I'd really love to make a surface of a game map that stores the obstacle information, then only have to check back on that surface for collisions (assuming all obstacles are stationary and indestructible).

-PENCERKOFF




Like how MMF does collision with backdrop?
Logged
Pencerkoff
CCCP
Level 4
*


Hello I am Pencerkoff


View Profile
« Reply #19 on: September 10, 2009, 07:22:40 AM »

Hello this is Pencerkoff

Like how MMF does collision with backdrop?

If I had tried that in MMF any unit I had interacting with a wall would be wiggling uncontrollably for like 3 seconds before shooting off into space.  No, I want something that works, thank you very much.

I've been toying with the RTS genre for a while now and just can't get the damn thing efficient.  I'm a far better physicist than programmer.

-PENCERKOFF

Logged

Pages: [1] 2 3
Print
Jump to:  

Theme orange-lt created by panic