GM:S 1.4 [SOLVED] Outlined text

Discussion in 'Programming' started by marasovec, Jan 10, 2019.

  1. marasovec

    marasovec Member

    Sep 15, 2016
    I made a script to draw a text with outline
    /// draw_text_outline(x, y, string, text color, outline color)
    var xx = argument0;
    var yy = argument1;
    var s = argument2;
    var c1 = argument3;
    var c2 = argument4;
    draw_text(xx+1, yy+1, s);
    draw_text(xx-1, yy+1, s);
    draw_text(xx+1, yy-1, s);
    draw_text(xx-1, yy-1, s);
    draw_text(xx, yy, s);
    But running this script like 8 times causes a huge FPS drop from avg 1500 to avg 900

    V V V

    /// DRAW STATS
    if global.selected != noone
    var sf = global.selected;
    var posx = 50;
    var posy = 50;
    draw_rectangle(posx, posy, 300, 250, 0);
    draw_rectangle(posx-1, posy-1, 300+1, 250+1, 1);
    var lx = 80;
    var ly = 3;
    var n = 150;
    draw_text_outline(posx+10, posy+15, "Food", c_orange, c_black);
    draw_text_outline(posx+10, posy+30, "Water", c_aqua, c_black);
    draw_text_outline(posx+10, posy+45, "Joy", make_colour_rgb(255, 153, 51), c_black);
    draw_text_outline(posx+10, posy+60, "Energy", c_yellow, c_black);
    draw_text_outline(posx+10, posy+75, "Poop", make_colour_rgb(204, 153, 0), c_black);
    draw_text_outline(posx+10, posy+90, "Fear", c_ltgray, c_black);
    draw_text_outline(posx+10, posy+105, "Health", c_lime, c_black);
    draw_rectangle(posx+lx, posy+ly+20, posy+lx+(*n, posy+ly+25, false);
    draw_rectangle(posx+lx, posy+ly+35, posy+lx+(sf.water/100)*n, posy+ly+40, false);
    draw_rectangle(posx+lx, posy+ly+50, posy+lx+(*n, posy+ly+55, false);
    draw_rectangle(posx+lx, posy+ly+65, posy+lx+(*n, posy+ly+70, false);
    draw_rectangle(posx+lx, posy+ly+80, posy+lx+(sf.poop/100)*n, posy+ly+85, false);
    draw_rectangle(posx+lx, posy+ly+95, posy+lx+(sf.fear/100)*n, posy+ly+100, false);
    draw_rectangle(posx+lx, posy+ly+110, posy+lx+(sf.hp/100)*n, posy+ly+115, false);
    draw_rectangle(posx+lx, posy+ly+20, posy+lx+n, posy+ly+25, true);
    draw_rectangle(posx+lx, posy+ly+35, posy+lx+n, posy+ly+40, true);
    draw_rectangle(posx+lx, posy+ly+50, posy+lx+n, posy+ly+55, true);
    draw_rectangle(posx+lx, posy+ly+65, posy+lx+n, posy+ly+70, true);
    draw_rectangle(posx+lx, posy+ly+80, posy+lx+n, posy+ly+85, true);
    draw_rectangle(posx+lx, posy+ly+95, posy+lx+n, posy+ly+100, true);
    draw_rectangle(posx+lx, posy+ly+110, posy+lx+n, posy+ly+115, true);

    Does anyone found a better script to draw a text with outline?
  2. Tsa05

    Tsa05 Member

    Jun 21, 2016
    How often does your text update?

    You *could* do a thing where you draw the text, with an outline, to a surface, then just draw the surface when needed. If your text changes every step, though, than it would be even slower.
    marasovec likes this.
  3. marasovec

    marasovec Member

    Sep 15, 2016
    @Tsa05 Right now the text updates every step. The text changes only its position so it's a really good idea to draw that to a surface. Or maybe just sprites would be enough because I'm not much familiar with surfaces
  4. Tsa05

    Tsa05 Member

    Jun 21, 2016
    Ah, well, if you know how to draw, you know how to surface :D

    Check this out:

    Create Event
    myTextSurface = -1;
    Draw Event
         // Make a surface big enough for the text
         var outline = 1; // Outline width
         var w = string_width( myText ) + 2*outline;
         var h = string_height( myText ) + 2* outline;
         myTextSurface = surface_create(w, h);
         surface_set_target( myTextSurface);
         draw_clear_alpha(c_white, 0);
         draw_text_outline(x+outline, y+outline, myText, text color, outline color)
    draw_surface(myTextSurface, x-outline, y-outline);
    Looks like a bunch of code, but it's easy, I swear. The surface is basically a picture of your text, like a sprite.
    You start it at -1, so it definitely doesn't exist.
    Then, in your draw event, you say "if it doesn't exist, make it"
    Then draw it.

    To make a surface, you figure out the size you need. I figure that you need it to be the width and height of your text, plus 2x the size of your outline. (A 1px outline is one pixel on each side). So, compute the size, make the surface.

    Normally, all drawing code draws to GameMaker's default surface (the "application surface"), so you aim at the surface you just made.
    Then you do all drawing as usual.
    Then, you reset the target surface--which resumes drawing on the application surface.

    After that little departure, the game goes on to draw the surface contents. During the next drawing step, the surface already exists, so all of the drawing logic and computation is skipped and the image is simply drawn.

    Best of all, there's draw_surface_ext(), which works just like sprite drawing--you can scale and stretch and rotate and blend colors with your surface.

    The reason that the code is in the Draw event is this little wrinkle: GameMaker frees surfaces when it needs to for a variety of conditions. On mobile apps, surfaces often get cleared when the app is cached in the background. Surfaces get cleared when you switch between fullscreen mode and windowed mode, etc. So, having the code to re-create the surface right there ensures that anytime the surface *should* have been drawn but suddenly ceased to exist, it gets re-made.
    marasovec likes this.
  5. Relic

    Relic Member

    Jun 27, 2017
  6. TheouAegis

    TheouAegis Member

    Jul 3, 2016
    Or make two sprite fonts, one that's the outline and one that's the interior. Then it's just two draw_text() calls instead of 4.
  7. marasovec

    marasovec Member

    Sep 15, 2016
    @Tsa05 It worked. I'm on avg 1400 FPS now and I finally undestand those surfaces. Thanks!
    @Relic The shader looks great but I'm still on GMS 1.4
    @TheouAegis I already tried that but it didn't fit
    Tsa05 likes this.

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice