Steering Behaviours: The AI system everyone needs for their game.

Discussion in 'Tutorials' started by amusudan, Mar 27, 2017.

  1. amusudan

    amusudan Lousiest of Potatoes

    Joined:
    Jun 20, 2016
    Posts:
    183
    GM Version: Game Maker: Studio
    Target Platform: ALL
    Download: Clicky
    Links: Original Post, and follow-up of the original post (Please do check them out). And also this very helpful gallery with an explaination of each behaviour.

    Summary:
    This is a re-post of two reddit posts made a while back by PixelatedPope and devlkore, and the file (See "Download" above) contains all you need to add steering behaviours to your GM:S game!

    Tutorial (Directly copied (almost) from the "follow-up" post):
    I needed steering behaviours for my game, but there was nothing prebuilt, so I followed the breadcrumbs. Thanks to PixelatedPope, The Mojo Collective (TMC), http://tutsplus.com/authors/fernando-bevilacqua and Craig Reynolds ( http://www.red3d.com/cwr/steer/ ).

    So what are these steering behaviours? Think swarms, think basic pathing, following and avoiding.
    I've tried to make the project as simple to understand how to use as possible. There are a bunch of scripts that handle the steering behaviours, they all begin with "sb_..." and they are dependant on the scripts in the Vector folder and a few need the 2 scripts from GMLscripts.com (included).

    There are a few objects (obj_drone...) set up already to show you how to use the scripts. The scripts themselves have some comments, but if you really want to understand what's going on, check out the tutorial by PixelatedPope and this series of tutorials (this is exactly what I did).

    If you run the project as is (or standalone exe), you can see a bunch of steering behaviours running in various combinations to get an idea of what you can do with these, though the potential is far greater.

    There is likely a bunch of optimisation to be done, but I wanted to get my head round the concepts involved before tightening it up fully. Most of the behaviours seem to have a pretty low CPU overhead EXCEPT the ones used for flocking (alignment, cohesion and separation) and to a lesser extent obstacle avoidance.​

    List of behaviours:
    sb_seek - Basic "go to here" behaviour (WILL constantly overshoot the destination).
    sb_seek_arrive - Same as above except it will slow down and stop at the destination.
    sb_flee - Opposite of seek, will move away from the specified point.
    sb_pursuit - specify an object (must have position and velocity variables) and it will try to intercept it based on it's velocity. Look inside the script to change how T (time) is calculated from dynamic to fixed if desired.
    sb_evade - Opposite of pursuit.
    sb_wander - Will constantly change direction, amount and angle offset can be configured.
    sb_path_loop - Will follow a path and start again from the beginning. Works on closed or unclosed paths.
    sb_path_tofro - Follows a path then turns around when it reaches the end/beginning.
    sb_obstacle_avoidance - Specify an object to avoid and a distance to "see", tries to avoid the object.
    sb_alignment - Flocking. Tries to align its velocity to the average velocity of its neighbours.
    sb_cohesion - Flocking. Tries to move to the centre of mass of its neighbours.
    sb_separation - Flocking. Tries to move away from the centre of mass of it's neighbours.
     
  2. ph101

    ph101 Member

    Joined:
    Jun 20, 2016
    Posts:
    415
    Yeah this does indeed look awesome. I'm mid project so not sure I can use this, but it looks very cool, very interesting, plus appreciate the heads up to @Pixelated_Pope tutorial which also looks excellent - thanks!
     
    Last edited: Apr 7, 2017
  3. Pixelated_Pope

    Pixelated_Pope Member

    Joined:
    Jun 20, 2016
    Posts:
    783
    I should really finish that series at some point... This is a great summary, though. Such a cool concept, I use it wherever possible.
     
    Bentley, Zodya Studios and ph101 like this.
  4. devlkore

    devlkore Guest

    I signed up to post here and notify y'all that the OP isn't actually the latest version. At the time @amusudan messaged me on reddit, my latest version thread was removed by auto mod for some reason. I've since had the thread restored, but I can't post links here until I have 5 posts.

    I'll do some more posting after work and then just make a new thread with the latest version. If you are hungry for it RIGHT NOW, search "steering grid finally" on r/gamemaker and it'll be the only result.
     
  5. amusudan

    amusudan Lousiest of Potatoes

    Joined:
    Jun 20, 2016
    Posts:
    183
    Welcome to the forums :).
     
  6. king javo

    king javo Member

    Joined:
    Apr 1, 2017
    Posts:
    73
    This is really awesome! I'm looking through your project now and not 100% sure yet how to `test` each behavior out. I'll probably figure it out, but if you happen to want to point me in the right direction, I'd really appreciate it! :)

    EDIT: Figured it out.. haha.
     
    Last edited: Nov 1, 2017
  7. v_roma

    v_roma Member

    Joined:
    Mar 31, 2018
    Posts:
    2
    Hello,

    Hoping to revive this thread to ask about something I've been trying to resolve. I have been playing with steering behaviors and have gotten all the behaviors to work. However, I was wondering if anyone has figured out a work around for the "jitteriness" (i.e., the very fast rotation from side to side) that the drones display. I've tried a number of things but the only way I've managed to get rid of this was by slowing down the image_angle rotation but I need to slow it down so much that this doesn't look good either.

    EDIT: For those that come across this post looking for a solution to this problem as well, the code below works reasonably well. The number multiplied at the end can be adjusted for more/less "jitters".

    Code:
    image_angle -= angle_difference(image_angle, vect_direction(velocity))*max_force/2;
     
    Last edited: Apr 13, 2018
    amusudan likes this.
  8. amusudan

    amusudan Lousiest of Potatoes

    Joined:
    Jun 20, 2016
    Posts:
    183
    Have you tried using the lerp function?
     
  9. v_roma

    v_roma Member

    Joined:
    Mar 31, 2018
    Posts:
    2
    I did. However, at least the way I was trying it, you run into issues when trying to interpolate directions around zero degrees (i.e., facing right) because the value of two directions that straddle zero degrees can be very different even though the directions are not.

    I'm ok in my code above, though. It essentially does what I need it to. I'm looking into alternatives to steering behaviors, though, as there are other reasons I'm not totally happy with. I recently read about context behaviors and it sounds like it could be an interesting alternative.
     
    amusudan likes this.
  10. king javo

    king javo Member

    Joined:
    Apr 1, 2017
    Posts:
    73
    Did you ever get anywhere with Context Behaviors? I'm reading up on it and because I'm dealing with the same issues with Steering Behaviors and need a better solution?
     
  11. Aajowa

    Aajowa Member

    Joined:
    Sep 9, 2018
    Posts:
    6
    Thanks Amusudan! Not just for that, but because I followed the link in the link and discovered reddit has a gml thing, so...double thanks? Haha!
     
    amusudan likes this.
  12. IgniFerroque

    IgniFerroque Member

    Joined:
    Aug 28, 2017
    Posts:
    24
    Sorry for the necro, but as i am currently also solving this problem and want to give some insights. The jittery behaviour of the solution comes from the used vectors for the adition.
    To visualize it for an extreme Example i have uploaded an image.
    The red vector is added every frame, and for that extreme example that means that the desired/target vectors are equaling -velocity vector (minus velocity vector). Thus resulting in an velocity vector of [0;0] at some point.
    Thats a replication of the most efficient use of power for zero-g environments, but it doesnt look "gamey" enough for space shooters which want a "jet fighter style".
    current.png




    A better solution is the second image
    using a normal vector to "steer" the velocity vector till it points into the target vector thus resulting in a real circular motion (look here: https://en.wikipedia.org/wiki/Centripetal_force and here: https://en.wikipedia.org/wiki/Circular_motion )
    better.png


    I would not use any lerps bc the used vectors in the addition are already close to a lerping of the values.
     
    amusudan likes this.
  13. IgniFerroque

    IgniFerroque Member

    Joined:
    Aug 28, 2017
    Posts:
    24
    Just a quick example for the step event for a seek behaviour which overshoots and circles around.

    Code:
    steering = scr_vect2(0,0);
    
    // needs a starting velocity vector and objects velocity vetor shall not reach [0,0] at any time
    normal_right =   scr_vect2_truncate(scr_vect2(-velocity[2],velocity[1]),max_rot_force);
    normal_left =   scr_vect2_truncate(scr_vect2(velocity[2],-velocity[1]),max_rot_force);
    
    
    target_coordinate = scr_vect2(target_x,target_y);
    target_vector =  scr_vect2_norm(scr_vect2_subtract(target_coordinate,position));
    target_angle = point_direction(x,y,target_x,target_y);
    
    velocity_norm = scr_vect2_norm(velocity);
    velocity_angle = point_direction(0,0,velocity_norm[1],velocity_norm[2]);
    
    angle_dif = angle_difference(velocity_angle,target_angle);
    
       if (angle_dif > 0){
           steering = scr_vect2_add(velocity,normal_right);
       }
       if (angle_dif < 0){
           steering = scr_vect2_add(velocity,normal_left);
       }
    
    
    
    
    steering = scr_vect2_truncate(steering,max_force);
    velocity = scr_vect2_truncate(scr_vect2_add(velocity,steering),max_speed);
    position = scr_vect2_add(position,velocity);
    
    x = position[1];
    y = position[2];
    image_angle = point_direction(0,0,velocity[1],velocity[2]);
    
    
    
    
     
  14. ajrdesign

    ajrdesign Member

    Joined:
    Jun 29, 2019
    Posts:
    7
    Can you expand on this a bit? This seems like something I'm very interested in understanding as I really want my objects behavior to be more of a slow rotation rather than spinning instantly when they overshoot their target but there's a lot of scripts in there that I don't recognize from the OP's batch of scripts so I don't really know how to implement this to try it out.
     
    amusudan likes this.
  15. IgniFerroque

    IgniFerroque Member

    Joined:
    Aug 28, 2017
    Posts:
    24
    the scripts are a renamed and i have rewritten them for 2 dimensional vectors, but should work the same as the other downloads (asmusudan's download and pixelated pope's youtube vid)
    simply use these with the same name after the "vect2_"



    better commented/cleaned up version (the first code I uploaded had many additional AI values)
    the object needs a starting velocity and new value max_rot_force to work correctly

    Code:
    //steering reset to 0;0 like in original
    steering = scr_vect2(0,0);
    
    // normal_right/left are the normal vectors of the current direction of movement, that means they are orthogonal to the current movement direction
    normal_right =   scr_vect2_truncate(scr_vect2(-velocity[2],velocity[1]),max_rot_force);
    normal_left =   scr_vect2_truncate(scr_vect2(velocity[2],-velocity[1]),max_rot_force);
    
    // save target as vector
    target_coordinate = scr_vect2(target_x,target_y);
    
    // like in sb_seek, subtract the target coordinates from own position to get the vector directing from your object to the target
    target_vector = scr_vect2_subtract(target_coordinate,position));
    
    //angle the object needs to point to the target
    target_angle = point_direction(x,y,target_x,target_y);
    
    //current angle of movement
    velocity_angle = point_direction(0,0,velocity[1],velocity[2]);
    
    //calculate the difference
    angle_dif = angle_difference(velocity_angle,target_angle);
    
    
    // "turn left"/"turn right" according to angle_difference
       if (angle_dif > 0){
          steering = scr_vect2_add(velocity,normal_right);
       }
       if (angle_dif < 0){
          steering = scr_vect2_add(velocity,normal_left);
       }
    
    
    
    
    
    //exact the same stuff like in the tutorial
    steering = scr_vect2_truncate(steering,max_force);
    velocity = scr_vect2_truncate(scr_vect2_add(velocity,steering),max_speed);
    position = scr_vect2_add(position,velocity);
    
    x = position[1];
    y = position[2];
    image_angle = point_direction(0,0,velocity[1],velocity[2]);
    
     
    amusudan and ajrdesign like 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