Thanks for the series, these are real great videos and easy are to understand. I was previously trying to implement steering behaviours from the same resources you cited using arrays, as I was new to GMS and didn't understand the documentation too much, but your struct approach is much cleaner and straightforward
You could have each ship have a list of "relevant" and "possible" ships. The relevant ships are ones within radius to perform force, if they fall outside of the radius, they get moved to the possible list. Those in the possible list only have to be checked every 5 steps or so to test if they have come in range, they get moved to the relevant list....if they fall outside of the possible range, they are taken completely out of the list. Lastly, you have a thread worker that has a master list of all ships, it will shuffle this list and one at a time go through each ship and simply change an internal flag on that ship to "check_all." When the list is complete, it reshuffles and does it again. The number of ships it tags is FPS dependent....if the FPS starts to drop by a certain %, it decreases the amount per step that it will flag (with a minimum of 1), if FPS is maintained, it increases this number slowly until it dips within optimal range. The "check_all" flag is tested within the ship on the step event....if it's "true", it simply does a loop through EVERY ship in the world to determine range and repopulate the "relevant" and "possible" lists. Done....you now can have thousands.
I have kind of a weird idea that might work here. What if instead of having all the calculations apply to the objects, have them run on the GPU as a shader - create a texture that is the size of the screen (can be scaled down), and assign say red values to being the x speed vector and green to being the y speed vector. Then break the surface down into a buffer and read the values each time you update the speed. That way you can just blur the texture if you want the ships to move similarly, or paint in a color if you want them to turn in a specific direction, and it would make virtually no difference to add more of them since you're working in O(n).
Let's assume for a minute that you are not considering ships in a radius, and rather have a set of defined ships you want to stay in a rough formation, akin to a fleet. Since you know all the ships you will be running the calculations for the behaviors for and some of these behaviors can also use similar calculations, you can do some overhead calculations to create ready to use data for every ship rather than calculating this same data for every ship for every behavior. Before running the behaviors for any ship of the flock, you could calculate the average position and velocity of every ship in the flock, then you could reuse those calculations for cohesion and alignment. Of course you'd have the current ship's data integrated into that data as well, but I don't think I'd consider that much of an issue. I think there could also be a way you might use average position to decide separation, maybe by scaling it against a normal considering distance to the separation
I know you mentioned it at the end, but quadtree seems like the goto for optimizing things like this. Sebastian Lague used it for something I while back, but I can't recall what he was optimizing.
One small change I would make is instead of using choose to randomize a behavior, to have each behavior run in a sequence, unless there’s a reason for it being randomized that I’m not seeing
You definitely could do that. Craig Reynolds' original paper used randomness and so I did as well, but both work as far as speed goes. I think the reason he used randomness is that it probably provides a slightly more natural look to the movement and more variations in movement between ships/boids, but that's only a guess.
Hi, thanks for your videos they are very useful, would it be possible to see a video on how to disable everything that is not framed by the camera so as to have a performance boost?
Deactivated objects wouldn't slow anything down as they would be deactivated, but there's a cost to activating and deactivating, and, of course, being deactivated they won't move or do anything either.
@@SamSpadeGameDev I probably expressed myself badly, I'd like to see a tutorial to understand how to deactivate entities that are outside the view and when they are within a certain distance they are reactivated to avoid pop-ups, I think that for very large video games there is are performance risks if everything remains active even when not within the view, thank you 🙏🏻
I think so? A short version would be to either force some sort of forward movement, scaled perhaps based upon the current direction of the steering force or limit the vector's relative angle (e.g. if the steering force would be greater than 45 degrees off center, limit it to 45 degrees). I don't have a function for the second, but my guess is there's some math out there to do it somewhere.
Thanks for the series, these are real great videos and easy are to understand.
I was previously trying to implement steering behaviours from the same resources you cited using arrays, as I was new to GMS and didn't understand the documentation too much, but your struct approach is much cleaner and straightforward
You could have each ship have a list of "relevant" and "possible" ships. The relevant ships are ones within radius to perform force, if they fall outside of the radius, they get moved to the possible list. Those in the possible list only have to be checked every 5 steps or so to test if they have come in range, they get moved to the relevant list....if they fall outside of the possible range, they are taken completely out of the list.
Lastly, you have a thread worker that has a master list of all ships, it will shuffle this list and one at a time go through each ship and simply change an internal flag on that ship to "check_all." When the list is complete, it reshuffles and does it again. The number of ships it tags is FPS dependent....if the FPS starts to drop by a certain %, it decreases the amount per step that it will flag (with a minimum of 1), if FPS is maintained, it increases this number slowly until it dips within optimal range.
The "check_all" flag is tested within the ship on the step event....if it's "true", it simply does a loop through EVERY ship in the world to determine range and repopulate the "relevant" and "possible" lists.
Done....you now can have thousands.
Great video!
I have kind of a weird idea that might work here. What if instead of having all the calculations apply to the objects, have them run on the GPU as a shader - create a texture that is the size of the screen (can be scaled down), and assign say red values to being the x speed vector and green to being the y speed vector. Then break the surface down into a buffer and read the values each time you update the speed. That way you can just blur the texture if you want the ships to move similarly, or paint in a color if you want them to turn in a specific direction, and it would make virtually no difference to add more of them since you're working in O(n).
Let's assume for a minute that you are not considering ships in a radius, and rather have a set of defined ships you want to stay in a rough formation, akin to a fleet. Since you know all the ships you will be running the calculations for the behaviors for and some of these behaviors can also use similar calculations, you can do some overhead calculations to create ready to use data for every ship rather than calculating this same data for every ship for every behavior. Before running the behaviors for any ship of the flock, you could calculate the average position and velocity of every ship in the flock, then you could reuse those calculations for cohesion and alignment. Of course you'd have the current ship's data integrated into that data as well, but I don't think I'd consider that much of an issue. I think there could also be a way you might use average position to decide separation, maybe by scaling it against a normal considering distance to the separation
I know you mentioned it at the end, but quadtree seems like the goto for optimizing things like this. Sebastian Lague used it for something I while back, but I can't recall what he was optimizing.
One small change I would make is instead of using choose to randomize a behavior, to have each behavior run in a sequence, unless there’s a reason for it being randomized that I’m not seeing
You definitely could do that. Craig Reynolds' original paper used randomness and so I did as well, but both work as far as speed goes. I think the reason he used randomness is that it probably provides a slightly more natural look to the movement and more variations in movement between ships/boids, but that's only a guess.
Hi, thanks for your videos they are very useful, would it be possible to see a video on how to disable everything that is not framed by the camera so as to have a performance boost?
Deactivated objects wouldn't slow anything down as they would be deactivated, but there's a cost to activating and deactivating, and, of course, being deactivated they won't move or do anything either.
@@SamSpadeGameDev I probably expressed myself badly, I'd like to see a tutorial to understand how to deactivate entities that are outside the view and when they are within a certain distance they are reactivated to avoid pop-ups, I think that for very large video games there is are performance risks if everything remains active even when not within the view, thank you 🙏🏻
This is awesome, did you ever get my email on slowing down the ships rotation speed so they dont just "flip" 180 degrees in a split second?
Use normal vectors instead of a target vectors.
I think so? A short version would be to either force some sort of forward movement, scaled perhaps based upon the current direction of the steering force or limit the vector's relative angle (e.g. if the steering force would be greater than 45 degrees off center, limit it to 45 degrees). I don't have a function for the second, but my guess is there's some math out there to do it somewhere.
@@SamSpadeGameDev forum.yoyogames.com/index.php?threads/steering-behaviours-the-ai-system-everyone-needs-for-their-game.23370/post-393745
Normal Vectors should be more efficient. As you are only switching signs and positions of the numbers of the vector.
Quad tree is actually not the fastest. A spatial hash grid is faster and arguably simpler to implement.