How do YOU optimize your game?

Discussion in 'Programming' started by Luke Peña, Oct 8, 2017.

  1. Luke Peña

    Luke Peña Member

    Joined:
    Jul 6, 2016
    Posts:
    104
    So right now, I'm actually sitting down to read through the entire Game Maker manual. In one of the early parts about debugging I think, it mentions that changing global draw settings - like font, color, etc - will slow the game down. This would mean that using a functions like draw_set_colour to change the draw color of a vertex is SLOWER than just using draw_vertex_colour, right?

    The biggest drains according to the debug tools is (obviously) the draw event, bumping my game down to about 105 fps, which is less overhead than I'm comfortable with. I can usually figure out how to cut out excess in my logic code. But the actual drawing of the game has always been problematic for me.

    TLDR: There must be all sorts of hidden ways to optimize the game. So my question is what things do all of you do to optimize your game's performance? (Especially visually!)
     
  2. Anomaly

    Anomaly Member

    Joined:
    Aug 23, 2017
    Posts:
    244
    If been reading a lot about using vector graphics instead of the usual raster type pixel based graphics for sprites.
     
  3. Hyomoto

    Hyomoto Member

    Joined:
    Jul 7, 2016
    Posts:
    1,073
    Well, optimization is a funny thing because you can probably get away with not doing a lot of it. Then there are times where it's vital. In my case I knew the performance on the world map was quite poor, but I got good results on my various test computers. However, it turns out that older iGPU's absolutely fell apart trying to render it. So, my solution was to cache the entire map and only redraw it on demand. As a nice side effect this means that all maps run at generally the same speed and it opens up a lot of overhead.

    Granted I think once you've been doing anything for a while you start putting together optimizations unconsciously. My big habits are to cache things that don't change often or use a var whenever a calculated value will be used more than once. How much this saves I don't know, but I feel like it keeps things running as smooth as I can.
     
  4. Matt Hawkins

    Matt Hawkins Member

    Joined:
    Jan 29, 2017
    Posts:
    213
    If you run your game in debug mode you can see which objects might need optimizing
    [​IMG]
     
  5. True Valhalla

    True Valhalla Full-Time Developer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    318
    Limiting excessive color/alpha fades is the main optimization that I focus on, as well as limiting texture page swaps. Drawing fonts is also performance intensive, in my experience, so I'll occasionally opt to format text as a sprite when it makes sense.
     
  6. Smiechu

    Smiechu Member

    Joined:
    Jul 14, 2017
    Posts:
    626
    Most important seams to be preparing all the logic, calculations and loops in the step (or even better step end) event...

    Regarding your concern about color/alpha switching. I also worry about that, but the debugger is not pointing those functions as critical... Problematic by the debugger seam to be the draw_text, and in my case draw_sprite_part_ext...

    The draw_text function is nothing else as looped draw_sprite function, if you look at the texture pages you can see that all fonts are converted into sprites...
    So if you have a 20 character text to draw then it's equivalent to 20 draw_sprite function executions...
     
  7. True Valhalla

    True Valhalla Full-Time Developer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    318
    At least with the HTML5 export, these can easily be the source of massive performance issues.

    Correct. Then perhaps add some questionable "text shadow" code and you have a recipe for disaster.
     
    Last edited: Oct 9, 2017
  8. @Juju has some great advice found here:



    And a big thanks to @ShaunJS for sharing these videos with everyone!!!
     
    BG Games and Juju like this.
  9. Luke Peña

    Luke Peña Member

    Joined:
    Jul 6, 2016
    Posts:
    104
    Thanks to your suggestions and a little bit of awareness, I've quickly achieved an average FPS of 175, compared with earlier at 105. Which is awesome! And this is only by tweaking the major objects. Thanks guys!

    About the draw_text thing. Is there a way to get around this massive drain? I tried to make a Paper Mario style textbox system with the ability to apply jitter and different effects to the individual letters. This meant each letter had to be a separate draw_text event. Sooo 200 characters = draw_text*200. You can imagine how that went.

    What would you guys suggest for a work around in THAT kind of situation?
     
  10. Smiechu

    Smiechu Member

    Joined:
    Jul 14, 2017
    Posts:
    626
    Only thing that comes in mind is to work with surfaces... Draw the whole text first on a surface, transform it and add effects... and than draw only this surface every frame...
     
  11. YellowAfterlife

    YellowAfterlife ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ Forum Staff Moderator

    Joined:
    Apr 21, 2016
    Posts:
    2,404
    Vertex buffers are very well fit for this particular purpose.
     
  12. Juju

    Juju Member

    Joined:
    Jun 20, 2016
    Posts:
    412
    I'd suggest talking to me about a text engine I've been developing =D

    Yeah, pretty much this, plus a shader.
     
  13. Hyomoto

    Hyomoto Member

    Joined:
    Jul 7, 2016
    Posts:
    1,073
    This may be true but are there any numbers that prove its actually equivalent? I'd be surprised if it's not optimized in any way.

    My experience with this in the past is that a loop is more expensive than the draw calls themselves which is where I would expect draw_text to win.
     
  14. Electros

    Electros Member

    Joined:
    Jul 19, 2016
    Posts:
    319
    During development, I pop the instance count and FPS into the corner of the screen:

    Code:
    //Debugging values
    draw_set_halign(fa_left);
    draw_set_font(fnt_Main_Debug);
    draw_text(20, 20, "Instance count: " + string(instance_number(all)));
    draw_text(20, 40, "FPS: " + string(fps_real));
    
    If I see any big unexpected drops in FPS, or ever growing instance counts, it can suggest a duff change or some things not being destroyed that should be!
     
    Noba likes this.
  15. Smiechu

    Smiechu Member

    Joined:
    Jul 14, 2017
    Posts:
    626
    It's only my rough estimation, I didn't say that it's 100% the same.
    Loops are often "revolved" by the compilers, if there is no excesive logic inside, so i wouldn't say that loops self are a performance problem. Problem is the amount of iterated operations they generate with very small amount of code...
     
  16. Hyomoto

    Hyomoto Member

    Joined:
    Jul 7, 2016
    Posts:
    1,073
    My tests are hardly comprehensive, but in GM:S I was working on a tile engine and I found that the biggest problem was actually the iteration through a list to actually draw the items themselves as opposed to the draw calls. Basically I removed all logic and just had the draw calls. Still expensive. Removed all the draw calls and while it did make a difference, it showed the loop doing nothing was almost as expensive as having it draw the tiles to the screen. Which honestly surprised me. The only way to optimize was to actually reduce the size of the loops or how frequently they were called. In this case we are talking iterating over a few thousand tiles, but it was interesting to see that looping a few thousand times was more expensive than drawing a few thousand times. For it's part I think GM's draw calls are reasonably well optimized.

    Then again, as I said, this is just based on my experience which is really why I was asking if there was any numbers to go with that. I'm always interested to hear about optimizations and 'best behaviors'.
     
  17. NightFrost

    NightFrost Member

    Joined:
    Jun 24, 2016
    Posts:
    1,955
    I once had the grand idea of reducing draw load by not drawing instances that were not in view... using a rectangle_in_rectangle check. The result was: nope. Doing the check for all of them and just drawing a few was actually slower than not checking anything and drawing everything. Draw calls, it seems, use relatively little time (breaking draw batches of course is a different matter).
     
  18. Smiechu

    Smiechu Member

    Joined:
    Jul 14, 2017
    Posts:
    626
    If you have only draw functions in the draw event then this is true... becouse GM draw engine checks if it will draw in the range of active view... if not he skips the execution of draw functions...
    But, if from any reason you have some heavy logic or any sort of other operations i.e. iteration through array... then switching drawing (skipping execution of whole draw event) should give a good effects...

    All the things here are very, very individual... there is no one universal good recepie...
    I also found out lately that sprite_create_from_surface is a very heavy function and a simple surface_copy is way faster if you can use surface instead of sprite...
     
  19. dphsw

    dphsw Member

    Joined:
    Oct 19, 2016
    Posts:
    82
    My guiding principles are:

    1. Avoid GML code in favour of built-in functions, even where it seems counterintuitive.

    Since GameMaker itself isn't actually written in GML (I'm not sure what it actually is written in, I'm guessing C++) it's own functions will run far faster than anything you can write. If you need to sum up a 2D array of numbers routinely, make sure they're in a ds_grid so that you can use ds_grid_get_sum to add them all up. Your code and the native GameMaker function will of course both do the same thing - run a loop over it that adds each value to a total - but the native function will run many times faster, just because it isn't written in GML. (For this reason, it's not at all surprising that, as Hyomoto said, a loop doing nothing was as expensive as some draw calls - the loop doing nothing was written in GML, whereas the draw calls were native functions. If it were in C++, this wouldn't have been the case.)

    2. Avoid writing functions in GML.

    Something I've noticed GML is particularly bad at is calling one of its own functions. (By 'one of it's own functions', I mean a function written in GML, not one of the GameMaker functions.) I once had a game in which I had a function to check for level collision at a pixel specified by the argument. I found that most of the runtime was being used by this function - even when I commented out all of the code. Once I took the code, and just copied and pasted it to everywhere in the program where that function was required, the game ran several times faster. Again, not something that would happen in C++ - in most languages it's considered good practice to keep your code readable by making everything out of fairly small functions, and if something is too complicated to be done in a dozen lines or so, it should be broken up into several other functions. But in GML, use as few functions as possible while still keeping code understandable, and sometimes it may even be necessary to sacrifice code readability and maintainability for the massive speedup it can give to eliminate frequently-used functions.
     
  20. JackTurbo

    JackTurbo Member

    Joined:
    Oct 19, 2016
    Posts:
    824
    Mines pretty simple, once every couple of weeks I spend some time with the profiler.

    If anything is using more step time than I think it ought to I'll take a look and work out why.
     
    The Sentient likes this.
  21. RangerX

    RangerX Member

    Joined:
    Jun 20, 2016
    Posts:
    2,595
    In addition to all the good stuff said in this thread, I also pay attention and organise the code in a way that something that doesn't NEED to read every step is indeed read only went absolutely necessary.
    This is done by carefully crafting your step events or any event that are occuring every step and using sensible conditions + short circuit evaluation turned on.

    Also, when you're using "short circuit evaluations", in your conditions you should always put the functions last. This way, the engine might not even need to execute the function at all.
     
    Last edited: Oct 10, 2017
    SnotWaffle Studios likes this.
  22. Luke Peña

    Luke Peña Member

    Joined:
    Jul 6, 2016
    Posts:
    104
    I had something like that were I created a function that checked what block my objects was above and this ran every step. I realized that since each block was 4 pixels wide, I was running this 3 times more often than I needed to. Plus instead of looking for an object below, those blocks were already stored in an array and created below the map in order. So I could know which block I was above by simply checking the array where the selection was x/blockWidth. This saved me a BUNCH of processing power.
     
  23. sitebender

    sitebender Member

    Joined:
    Sep 13, 2016
    Posts:
    827
    What drives me nuts is how I'll still get 200 - 1,000+ real_fps and yet the game will somehow dip to 59 fps. I've made quite a lot of debuggers to track the lowest and highest real_fps per second so I know I'm not missing a frame where it possibly dips to 59 fps.

    As for optimization...
    - not everything needs to go each and every frame.
    - Check for memory leaks, so if you're done using a sprite you made via code or a particle effect or a surface... destroy it properly.
    - Check for for / while / repeat loops that go on far too long.
    - Somehow creating a lot of instances at once seems to burden the game as does activating and deactivating a lot of things at once.
    - Don't update a surface if you don't have to. That goes for maps, lighting and so on. Once every 2 or 3 frames might be the maximum you'll need beyond the game screen.
     
  24. Smiechu

    Smiechu Member

    Joined:
    Jul 14, 2017
    Posts:
    626
    This was already said here. You can do magic (hyper optimization) in the step events, but the devil always hides in the draw event...
     
  25. sitebender

    sitebender Member

    Joined:
    Sep 13, 2016
    Posts:
    827
    I suppose I should optimize my post by removing it.
     
    RangerX likes this.
  26. Smiechu

    Smiechu Member

    Joined:
    Jul 14, 2017
    Posts:
    626
    Hey! Chill! :) It's a misunderstanding... I was referring to your problems with FPS. If the FPS drops down while FPS real is high, than you need to focus on optimizing the draw events... that I had in mind. Sorry, English is not my native language.

    The second part of your post is OK and I'm 100% agreeing with it!
     
  27. grixm

    grixm Member

    Joined:
    Jun 20, 2016
    Posts:
    49
    This isn't always the case. I've found several functions in GM that perform much worse than raw GML. For example color_get_red(color) vs (color & $FF)
     
  28. The Sentient

    The Sentient Member

    Joined:
    Sep 20, 2017
    Posts:
    163
    I use the 'keep it simple' rule.

    Break down the task at hand. What is the simplest way to achieve it? (and I don't mean laziest, i.e. Use an inbuilt collision function and mark everything solid).
     

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