GameMaker sprite_create_from_surface vs pre-made sprite

Flaick

Member
Hi guys. I'm developing a game in which there are lot of sub-menus opening on certain action. I've made a tileset for that window menu.

My question is:

1. is better to use sprite_create_from_surface()? And using sprite_delete() when no need anymore...
or
2. Pre-made the window's menu sprites into IDE? But my texture pages will raise a lot.

Those sprites are about 800x600 each.

Must sint question:
In generally do you use a IDE pre-made sprite or draw it at runtime for a window sub-menu?
Is a problema having lot of texture pages?
 

NightFrost

Member
Are you talking about menu container / border drawing? I use a single sprite and a specialized box script. The basic idea is to have a miniature sprite version of the box that divides into logical parts like this:
Code:
123
456
789
My script receives the width and height of the box and the thickness of the border (which I measured when I drew the border sprite). The function uses draw_sprite_part_ext calls, using sprite regions 1, 3, 7, and 9 to draw the box corners, stretches parts 2, 4, 6, and 8 to draw the straight edges, and stretches region 5 to draw the entire inner part of the box. This is called "9-slice" and you should be able to find pretty exhaustive guides one google away.
 

CloseRange

Member
chances are it won't matter in the end. Many texture pages means a bigger download size when sending your game but a few extra for an indie game won't even be noticeable.
Many texture swaps could be an issue but if it's for a menu system and not during gameplay again it won't have much of an effect.
If you want to push that tiny bit of performance, or want to make good habits if you ever go AAA, or just so you can learn, the best way is :
make a surface. Use 9 slice as @NightFrost said but on the surface, and just redraw that surface.
Delete it when not needed.
9 slice means you have a smaller file size and using surfaces means you don't have to do a bunch of 9slice calculations every frame.
 

Flaick

Member
Thx to all. Yes i use a kind of 9-slice (sorry i didn't know the name). But actually i create the drawn sprite from surface, while i presume i can simply draw directly the surface. So if i understand correctly the best solution is: have a 9-slice, draw it on a surface into Create event, then draw surface into Draw event.
 

NightFrost

Member
You can't rely on Create event to do that. Surfaces (and whatever they're called in other programming languages) are volatile, meaning they can get deleted when some other operation requires the use of graphics card's memory. Might not happen quickly if your game is the only program running on the system, but the bottom line is you can't tell. You just define a variable to save the surface in Create event (Box_Surface = -1 or whatever). In Draw event, you check if surface exists. If it doesn't, you create the surface and draw the content onto it. Then you draw the surface to display.

Separate your code intelligently. Create a 9-slice script that just does that, draws a box. Then call it from script(s) that create the text / menu / etc content. That's how I've made my textbox scripts. Fornatting script takes a string and returns an array where it has been formatted to fit into a box. Draw script checks for surface and if necessary creates and targets surface, calls 9-slice to draw the box, draws the text, resets target. Lastly it draws surface to display. Surface will also be destroyed when the box closes.
 

Flaick

Member
Oh! Didn't know that! I've fixed my code based on your suggestion:

Create:
Code:
menu_width       = 200;
menu_height      = 200;
menu_surface     = -1;
Draw:
Code:
if surface_exists(menu_surface) {
    draw_surface(menu_surface,x,y);
}else {
    menu_surface = tileset_menu_create_surface(menu_width,menu_height);
}
Destroy:
Code:
if surface_exists(menu_surface) surface_free(menu_surface);
While "tileset_menu_create_surface" is:
Code:
///@param width
///@param height
var _w = argument0;
var _h = argument1;
var surf = surface_create(_w,_h);
surface_set_target(surf);
draw_clear_alpha(c_white, 0);
tileset_draw_menu(_w,_h,0,0);
surface_reset_target();
return surf;
1. Is an error declaring?
Code:
menu_surface = undefined;
2. Instead of this approach, if i using sprite_create_from_surface() i won't encounter the problema you said? Cause the sprite is created and always present?

P.S: tileset_draw_menu() is my 9-slice function.
 

NightFrost

Member
1. Is an error declaring?
Code:
menu_surface = undefined;
Shouldn't be, surface_exists looks for valid a surface and since undefined isn't, it should just return false.

2. Instead of this approach, if i using sprite_create_from_surface() i won't encounter the problema you said? Cause the sprite is created and always present?
Yes, a sprite created from surface will last until game closes. However each sprite created in such manner generates a new texture page containing that sprite only, so it will cause texture swaps. And of course eats as much memory as if you had drawn the sprite yourself and added it to game resources. And now instead of checking surfaces, you have to keep track of which sprites you no longer need and destroy them, so I'd only use them if the sprites never change.

Also, its not clear from your code fragments if you draw menu text to surfaces as well. When it comes down to it each letter is its own draw operation, so drawing several sentences worth is likely going to take more time than the box draw. Anyhow you shouldn't worry too much about it if you have codebase that works, it tilts towards premature optimization which shouldn't be a priority. Micro-optimize only when it becomes necessary.
 

Flaick

Member
Thx NightFrost. So i'll go with this final solution. My text is drawn same in Draw event, after the surface.
 
Last edited:

Nocturne

Friendly Tyrant
Forum Staff
Admin
Clean up event is generally better, as it gets called on room end as well as on destroy. If the menu or whatever is still visible when the room ends, then destroy won't clean up the surface memory as it's not called. ;)

Also note... just read through the topic... There is no "correct" way to do these things! In my current WIP I have full sprites from the IDE, nine-slice containers, sprites I load and multiple backgrounds that I load then create sprites from. :) Each one I have chosen for a specific reason (looks, ease of use, etc...) and so don't be afraid to just use whatever is best for the needs at the time. There really isn't a "correct" way to these things.
 

Flaick

Member
Thx Nocturne. I was just only afraid about performance, but i think my game (in progress) is too simple to worry about.
 
Top