Lots of enemies with lots of code

N

NoFontNL

Guest
In the game I am working on, there are a lot of enemies, they all run their horizontal speed and vertical speed code. This however, lags the game, even when deactivating the enemies outside of the view. I ran the debugger and saw that place_meeting was causing the most trouble. Is there a solution to decrease the lag?

Thanks in advance.
 
R

robproctor83

Guest
Well, you will need to be more specific. How many enemies are you talking? I'm not sure how many is too many, but I would suspect you could get away with at least a couple dozen, if not a hundred or so, place meetings each step without a tremendous amount of lag, but that all depends on the device your running it on. Also, are you certain that you have enemies outside the view disabled? Are you certain your not accidentally calling place_meeting many times per enemy per step? Or maybe there is another reason the game is lagging? Have you tried removing place_meeting to make sure that it is in fact causing the lag? And how much lag, just a bit or a lot? What device are you testing on? What are you doing with the collision? Are you looping at all after the collision? Are you looping through collisions? There are so many possibilities why you could be experiencing lag it's difficult to say. Place meeting is about as basic as it gets with gamemaker collisions apart from writing your own simple bounding box code, which I doubt would be any faster. Not to be rude, but I would almost be assured the issue is in some way that you have implemented the code, unless you are really running the function many hundreds of times per step.

*edit: also, are you running precise collisions? If so, what resolution is your sprites? The more pixels the more processing, so if your running precise collisions on high resolution art then yes it will be slow.

*edit 2: Okay, I was curious to see what is possible with place_meeting, and with my tests it shows that I can have over 2,000 place_meetings running all at the same time, even all colliding at the same time, and my FPS only drops to about two thousand (instead of 5,000). This is with square collisions mind you.

*edit 3: Okay, just tested again with 32x32 precise collisions (circles) and that really didn't seem to reduce the FPS by that much to my surprise. I was still getting over a thousand FPS.
 
Last edited by a moderator:
N

NoFontNL

Guest
Woah, that's a lot of questions.

Are you certain that you have enemies outside the view disabled?
Yes, I've drawn the amount of objects on the screen and it decreases when I offscreen the enemies.

Are you certain your not accidentally calling place_meeting many times per enemy per step? Or maybe there is another reason the game is lagging?
This is the code I'm using.
Code:
var hspd_final=hspd+hspd_carry;
        hspd_carry=0;
        if(place_meeting(x+hspd_final,y,par_solid)){
            yplus=4;
            while(place_meeting(x+hspd_final,y-yplus,obSlope)&&yplus<abs(1.25*max(hspd_final))) yplus++;
            if(place_meeting(x+hspd_final,y-yplus,par_solid)){
                while(!place_meeting(x+sign(hspd_final),y,par_solid)){
                    x+=sign(hspd_final);
                }
               hspd=0;
               hspd_final=0
            } else {
                y-=yplus;
            }
        }
        x+=hspd_final;
       
         // Slopes (going down)
        if !place_meeting(x,y,par_solid) && vspd >= 0 && place_meeting(x,y+4+abs(1.5*hspd_final),par_solid)
        {
            while(!place_meeting(x,y+1,par_solid)) 
            {
                y += 1;
            }
            while(place_meeting(x,y,par_solid)) y--;
        }
Have you tried removing place_meeting to make sure that it is in fact causing the lag?
I have ran the profiler in the debugger and it said that the enemy object was taking in the most memory.

And how much lag, just a bit or a lot?
Without the enemies the FPS counter shows 50 to 60 fps. With the enemies the counter shows a value around 30 to 40 fps.

What device are you testing on?
Windows

What are you doing with the collision?
Checking if the enemy is going to collide with a solid object, then if so, move it as close to the solid object as possible and then reset the values.

Are you looping at all after the collision? Are you looping through collisions?
Yes.

There are so many possibilities why you could be experiencing lag it's difficult to say.
Yes, there indeed are many possibilities. But after running the profiler I have found the thing that is causing the most lag of all.

However, this is the profiler. If we do the math right it calls scHspd() 6187 times in 46 steps.
There are 135 enemies on the screen. 30889 times place_meeting seems incredibly much at first, but we run place_meeting 30889 / 6187 = 5 times per step per scHspd() call. And we call scHspd() 135 times per step, because there are 135 enemies on the screen. You might expect from reading the code I put above, that I call it more than 5 times per step, but some place_meetings only are triggered when an if statement returns true.



I hope this gave you enough understanding of the situation and more importantly, I hope this gave you enough information to help me out.
 

Yal

🐧 *penguin noises*
GMC Elder
You could speed up the collision checking a lot if you use position_meeting instead, it only checks a single pixel instead of looping over the entire sprite. (You might need to check more than one place, e.g. all the corners of the sprite, to avoid having the enemy sprite clip into walls, because only checking one pixel means that the hitbox becomes one pixel instead of the entire sprite)
 
N

NoFontNL

Guest
You could speed up the collision checking a lot if you use position_meeting instead, it only checks a single pixel instead of looping over the entire sprite. (You might need to check more than one place, e.g. all the corners of the sprite, to avoid having the enemy sprite clip into walls, because only checking one pixel means that the hitbox becomes one pixel instead of the entire sprite)
Thanks for your response. In my mind I thought this was the solution (checking just 4 pixels, instead of a sprite of 64x64 pixels), but this only shaved off 4 fps.Still, it's progress.
 
N

NoFontNL

Guest
I don't know if it would be viable for your game, but you could look into using tile collisions.
I think it is not viable, my game is a level editor / player, in which I use objects and their variables to save the levels.
 
R

robproctor83

Guest
I still think something else is going on. If your saying that your game runs from 50 to 60 fps without enemies then there is already a problem. Your game should run much faster than that. If your expecting to only lose 10 or so fps with that many enemies it's just not possible. What is really going on here though? Do you have vsync on? Is that why the FPS shows as 60 without enemies? You need to turn of vsync for a moment while you resolve this. Take off vsync and remove enemies and see how much fps you have. If your still only getting roughly 50 to 60 fps then either your on a terribly slow device or there is another bigger issue.

Also, did you see my edits to the previous post? What kind of collisions are you using? Try setting it to rectangle to see if it vastly improves. Also, you should be aware that your saying that your only losing 10 to 30 fps from the checks which is expected, and in the grand scheme of things isn't really much all things considering. If I were you, I would be more concerned with why the game is only running 50 to 60 fps and see why it's not much faster already.

PS, when your profiling you probably want to stay with average values unless you plan to calculate over time like that... But average just makes things a lot clearer for quick debugging.
 
N

NoFontNL

Guest
I still think something else is going on. If your saying that your game runs from 50 to 60 fps without enemies then there is already a problem. Your game should run much faster than that. If your expecting to only lose 10 or so fps with that many enemies it's just not possible. What is really going on here though? Do you have vsync on? Is that why the FPS shows as 60 without enemies? You need to turn of vsync for a moment while you resolve this. Take off vsync and remove enemies and see how much fps you have. If your still only getting roughly 50 to 60 fps then either your on a terribly slow device or there is another bigger issue.

Also, did you see my edits to the previous post? What kind of collisions are you using? Try setting it to rectangle to see if it vastly improves. Also, you should be aware that your saying that your only losing 10 to 30 fps from the checks which is expected, and in the grand scheme of things isn't really much all things considering. If I were you, I would be more concerned with why the game is only running 50 to 60 fps and see why it's not much faster already.

PS, when your profiling you probably want to stay with average values unless you plan to calculate over time like that... But average just makes things a lot clearer for quick debugging.
If you're really saying the problem originates elsewhere, how can I find the orgin of the lag? Also, I'm not using precise collisions.
 
R

robproctor83

Guest
Well it could still be place meeting but it's not totally clear. You need to see what the game is really running at and it should be more than 60 without enemies unless that is just a very small aspect of the game, but just for comparison my game has about a dozen enemies at a time and it eats up a couple hundred fps. So unless I am misunderstanding your game should run faster without enemies. Make sure you disable vsync or just turn on the debug overlay and see what the fps is.

Also disable precise and see if that helps. Also are you certain you need precise? I would only ever use that for special circumstances and not typically enemies, ammo, player, etc unless it really needed that for some reason.

Other things to consider: what resolution is your art at? High res art eats a lot of fps, the smaller the art the better. How many surfaces do you have? Look in debugger to make sure.
 
N

NoFontNL

Guest
Well it could still be place meeting but it's not totally clear. You need to see what the game is really running at and it should be more than 60 without enemies unless that is just a very small aspect of the game, but just for comparison my game has about a dozen enemies at a time and it eats up a couple hundred fps. So unless I am misunderstanding your game should run faster without enemies. Make sure you disable vsync or just turn on the debug overlay and see what the fps is.

Also disable precise and see if that helps. Also are you certain you need precise? I would only ever use that for special circumstances and not typically enemies, ammo, player, etc unless it really needed that for some reason.

Other things to consider: what resolution is your art at? High res art eats a lot of fps, the smaller the art the better. How many surfaces do you have? Look in debugger to make sure.
Firstly, I've said I am NOT using precise collisions.
Aside from that, I don't think the art nor the surfaces have anything to do with the lag, since when I don't run scHspd() or scVspd() in the enemy's step, while the enemies are on screen, the game runs at a steady 50 - 60 fps like as if there were no enemies at all.

I hope any of you can help me on this matter, while giving solid advice, so that we can move forward towards a fitting solution.
 
R

robproctor83

Guest
Sorry I misread your text. But still just to clarify you should be using basic rectangle collisions (not rotated), at least for testing. Additionally, if your on a version of GM earlier than 1.4 you might find use in something like this:

https://marketplace.yoyogames.com/assets/244/tmc-sgs-fast-collision-system

With that said, I am still concerned with your comment about 50 to 60 fps... If your getting under 60 fps already then that essentially means no matter what you do it will cause lag because you don't have any frames to spare, none. Where are you getting the fps number exactly? Maybe when you say 50 to 60 you mean it's a constant 60 but periodically dips to 50? You need to figure out if you vsync enabled either in the windows setting or through code (display_reset) and also look at the real fps, either with fps_real or the show_debug_overlay(true) command.

Like I am saying, if your game is truly already maxed out at 60 fps then no matter what you do it will cause noticeable lag, especially if your on a 60 fps monitor (which most are). So, if that is truly the case, then your options are extremely limited. My suggestion, and maybe someone else can chime in, would be to either add delta time to your game so that when it dips below 60 it's not as noticeable, or to target 30 fps instead and add motion blur to disguise the micro stutter. Either way it's a lot of work, and not something I would really suggest if at all possible, especially depending on how far along in the project you are.
 
R

robproctor83

Guest
Something else I thought about is that you may want to give Motion Planning a shot instead of relying on collisions. It's not cheap, so I don't know it will be few enough FPS to really help, but Motion Planning is typically a better system for enemy movement in general.

https://docs2.yoyogames.com/
 
N

NoFontNL

Guest
I can't find vsync in the global game settings. I'm using GMS1.4.
However, is there any way to simplify my code, to get rid of some place_meeting occurrences?
 

Yal

🐧 *penguin noises*
GMC Elder
It should be labelled "use synchronization to avoid tearing" (if it's checked, it means vsync is on).
 
N

NoFontNL

Guest
Ah, I didn't notice that. Then yes, I'm using precise collisions.
Is that also the cause of the lag? (vsync was already off, if you wonder)
 

TheouAegis

Member
Yes, precise collision checking is very, very slow. There is no simple algorithm to compare bounding boxes when you use precise collision checking, the game loops through every pixel. I mean, I haven't tested it because I never use it but I would assume the smaller the sprites, the faster the function.
 

Neptune

Member
Whewy that Shaun Spaulding code brings back some memories (nightmares).
From my experience (that code you have up there being the first code i ever wrote), I would either:

A) Make damn sure you understand how it works.
B) Try to code your own version, trying various collision functions -- even if it takes you much more lines.
C) Skip slopes if you're very new to coding.

If you're making some sort of side-scrolley/platformer, that code is pretty much core to your game, and should be something you fully understand -- otherwise it will cause you nothing but headache.
Again, its just my experience/opinion.
Either way, Im sure you'll work it out, goodluck!
 
N

NoFontNL

Guest
Yes, precise collision checking is very, very slow. There is no simple algorithm to compare bounding boxes when you use precise collision checking, the game loops through every pixel. I mean, I haven't tested it because I never use it but I would assume the smaller the sprites, the faster the function.
I'm using upscaled sprites, is there a way to have smaller masks for slopes and upscale the masks to only check 16x16 pixels instead of 64x64?
 

TheouAegis

Member
Reducing scale for everyone temporarily should improve the speed. If it's just ground, you'd be better off generating a height map for each ground sprite. Then use instance_position() at a specific point to find a ground object at that position and compare that point to the height map for that ground's sprite. You find the height index by subtracting the x of the point you used in instance_position() subtracted by the ground's bbox_left. I'd use the center-bottom point of the player to determine actual height to put yhe player at, then a point under each foot to determine what sprite or image_angle to use.

The point is, you still have a lot of collision checks each step just for the player alone. Multiply that by the number of pixels in the ground sprite. If setting the player sprite to a rectangle tells GM to only treat the ground as precise, then that should only be up to 4a checks (where a is the area of the ground sprite). If GM has to treat both instances as precise, that is ab checks (where b is the area of the player sprite). Multiply that by every collision event, place_meeting(),and instance_place() in the player and/or ground. With the height map method, it's up to 4 checks - one for if there is any collision, and up to 3 for the center and feet checks.
 

Sabnock

Member
there are a lot of while statements in your code that could be holding things up?
 
Last edited:
What are you getting for real_fps (or is it fps_real ) both with and without enemies.

As others have already mentioned, if your real_fps is already low due to your editor already eating up a lot of frames, it doesnt give you much wriggle room for enemies etc...

I had to make sure I disabled as much editor code as possible when switching to play mode in my editor.

What exact version number of 1.4 are you using?

I remember at some point they added fast collision system and there was a check box somewhere in the options to enable/disable it. Just wondering if its enabled for you. Later versions of gms1.4 had it enabled by default I think.
 
Top