GMLscripts.com

Discuss and collaborate on GML scripts
Invert

You are not logged in.

#1 2020-02-22 02:17:06

lostdarkwolf
Member
Registered: 2015-11-19
Posts: 31

"pie move" wander system

This is a set of scripts i call the "pie move" wander system. It uses "scan rays" aligned like pie slices or tire spokes. It scans for a suitable and desirable direction, then travels there. repeating this process as quickly as possible. Scanning is automatically done only when the instance is stationary, as per intentional limitations. if the instance scans outside the station, it must try to get back. The station location can be unbound, enabling unrestricted wandering.

The "pie move" wander system consists of five scripts, but only the top four are required.
The fifth script is to visualize the data so you can see what the script is doing.

Example of use: (also in init script)
Create event:
  pie_move_init(48)
Step event:
  var var_wander_speed; var_wander_speed=3;
  pie_move_update(4,140,2)
  pie_move_point(xstart,ystart,100,var_wander_speed)
  mp_potential_step(loc_ret_x,loc_ret_y,var_wander_speed,false);
Draw event: (optional, for visualization only)
  pie_move_draw(xstart,ystart,100)

EDIT 2/22/20: Bugfix in pie_move_init.
EDIT 4/6/20: added pie_move_reset and mp_grid_add_solids

Only needed if you want to use pathfinding

Expand///mp_grid_add_solids(id, x, y, grid_width, grid_height, cell_width, cell_height);
// 
// Checks for collision in an area, and sets an mp_grid accordingly
// Collisions are checked with the calling instance's sprite mask.
//
// id            id of mp_grid, real
// x             x position of the mp_grid, real
// y             y position of the mp_grid, real
// grid_width    width of the grid in cells, real
// grid_height   height of the grid in cells, real
// grid_width    width of a single cell, real
// grid_height   height of a single cell, real
//
///gmlscripts.com/license

var var_id, var_iix, var_iiy, var_x, var_y, var_grid_width, var_grid_height, var_cell_width, var_cell_height, var_solid_revert;
var_id=argument[0];
var_x=argument[1];
var_y=argument[2];
var_grid_width=argument[3];
var_grid_height=argument[4];
var_cell_width=16;
if argument_count>5 var_cell_width=argument[5];
var_cell_height=16;
if argument_count>6 var_cell_height=argument[6];

var_iiy=0;
while var_iiy<var_grid_height {
 var_iix=0;
 while var_iix<var_grid_width {
  if not place_free(var_x+(var_iix*var_cell_width),var_y+(var_iiy*var_cell_height)) {
   mp_grid_add_cell(var_id,var_iix,var_iiy);
   //show_message('cell added at '+string(var_iix)+', '+string(var_iiy))
  }
  var_iix+=1;
 }
 var_iiy+=1;
}

Only needed of you want to use pathfinding

Expand///pie_move_reset()
// * arguments are optinal
// 
// resets the pie_move system
// call this when restarting an idle pie_move system
// 
// used for a wander system called "pie move"
// 
///gmlscripts.com/license

loc_startup_timer=0;
loc_pie_offset=0;
loc_ret_x=x;
loc_ret_y=y;

REQUIRED

Expand///distance_to_solid(maxdist,direction,not_me,precision*,x*,y*)
//
// returns distance until solid from x and y
// 
// maxdist     maximum distance
// direction   direction to check
// not_me      set to true to exclude local instance
// precision   distance precision for checking
// x           x location to scan from
// y           y location to scan from
//
///gmlscripts.com/license

var Amaxdist=argument[0];
var Adirection=argument[1];
var Anot_me=1;
if argument_count>2 Anot_me=argument[2];
var Aprec=1;
if argument_count>3 Aprec=argument[3];
var Ax=x;
if argument_count>5 Ax=argument[5];
var Ay=y;
if argument_count>6 Ay=argument[6];
var seen_solid=false;

var solid_revert; solid_revert=solid;
if Anot_me solid=0;
var ii_len=0;
while (ii_len<Amaxdist and seen_solid=false) {
 if not place_free(Ax+lengthdir_x(ii_len,Adirection),Ay+lengthdir_y(ii_len,Adirection)) {
  seen_solid=true;
 }
 ii_len+=Aprec;
}
ii_len-=Aprec;

solid=solid_revert;

return ii_len;

REQUIRED

Expand///pie_move_init(raw_slice_count, goal_reach_distance, ray_distance, x, y)
// all arguments are optional
//
// initializes a wander system
// should be executed only once
//
// raw_slice_count   total spoke-styled scan rays, real (integer)
// ray_distance      maximum scan ray distance, real
// x                 x position of wandering instance
// y                 y position of wandering instance
//
// used for a wander system called "pie move"
// raw_slice_count should be a multiple of "sub_slice_count"
// - "sub_slice_count" is an argument specified in the script "pie_move_update"
// see below for an example of use of the "pie-move" wander system.
//
///gmlscripts.com/license

/* example of "pie-move" use:
Create event:
  pie_move_init(48)
Step event:
  var var_wander_speed; var_wander_speed=3;
  pie_move_update(4,140,2)
  pie_move_point(xstart,ystart,100,var_wander_speed)
  mp_potential_step(loc_ret_x,loc_ret_y,var_wander_speed,false);
Draw event: (optional, for visualization only)
  pie_move_draw(xstart,ystart,100)
*/

var var_y, var_x, var_ii;

loc_stop_timer=-1;
loc_raw_slice_count=90
if argument_count>0 loc_raw_slice_count=argument[0]
loc_goal_reach_distance=9
if argument_count>1 loc_goal_reach_distance=argument[1]
loc_ray_distance=120;
if argument_count>2 loc_ray_distance=argument[2]
var_x=x
if argument_count>3 var_x=argument[3]
var_y=y
if argument_count>4 var_y=argument[4]
loc_startup_timer=-1;
loc_pie_offset=0;
var_ii=0;
repeat loc_raw_slice_count {
 loc_pie_data[var_ii]=0;
 var_ii+=1;
}
loc_ret_x=var_x;
loc_ret_y=var_y;
loc_dir=direction;
loc_interesting_direction_threshold=17

REQUIRED

Expand///pie_move_update(precision, ray_distance*, sub_slice_count*, x*, y*)
// * arguments are optinal
// 
// updates scan rays ONLY.
// should be used in a step event.
// 
// precision         precision to use for rays, real
// sub_slice_count   number of rays to scan per step, real (integer)
// ray_distance      maximum scan ray distance, real
// x                 x position of wandering instance, real
// y                 y position of wandering instance, real
// 
// used for a wander system called "pie move"
// sub_slice_count must devide into "raw_slice_count" without remainder
// - "raw_slice_count" is an argument in the script "pie_move_init"
// see script "pie_move_update" for an example of use
// 
///gmlscripts.com/license

var var_x, var_y, var_slice_space, var_raw_slice_size;

loc_sub_slice_count=6;
if argument_count>2 loc_sub_slice_count=argument[2];

if argument_count>1 loc_ray_distance=argument[1];
var_x=x;
if argument_count>3 var_x=argument[3];
var_y=y;
if argument_count>4 var_y=argument[4];
var var_slice_space;
var_slice_space=loc_raw_slice_count/loc_sub_slice_count;
var_raw_slice_size=360/loc_raw_slice_count;

if loc_startup_timer<360 loc_startup_timer+=1;

if point_distance(loc_ret_x,loc_ret_y,var_x,var_y)=0 {
 // sub slice update onto raw slices
 var var_slice_ii, var_subslice_index; var_slice_ii=0
 repeat loc_sub_slice_count {
  var_subslice_index=(var_slice_ii*var_slice_space)+loc_pie_offset;
  loc_pie_data[var_subslice_index]=distance_to_solid(loc_ray_distance,var_subslice_index*var_raw_slice_size,true,argument[0]);
  var_slice_ii+=1;
 }
  
 // update sub slice pie offset location
 loc_pie_offset=(loc_pie_offset+1) mod var_slice_space;
}

REQUIRED

Expand///pie_move_point(station_x, station_y, travel_distance, speed, x*, y*)
// * arguments are optional
//
// reacts to "scan ray" data and will "point" to the chosen "interesting direction"
// instance is allowed to walk outside station, but must walk toward station after leaving it
// should be used in a step event
// 
// station_x         x location of station to wander around
// station_y         y location of station to wander around
// travel_distance   station's unrestricted movement distance
// speed             speed by which to wander
// x                 x position of wandering instance
// y                 y position of wandering instance
// 
// if station_x is set to undefined, wandering will be unbound, and station_y will be ignored
// see script "pie_move_update" for an example of use
// customization notes below (marked "Custom:")
// 
///gmlscripts.com/license

var var_sx, var_sy, var_speed, var_go_distance, var_x, var_y, var_exception;

var_sx=argument[0];
var_sy=argument[1];
var_go_distance=argument[2];
var_speed=argument[3];
var_x=x;
if argument_count>4 var_x=argument[4];
var_y=y;
if argument_count>5 var_y=argument[5];

var var_station_direction, var_chosen_direction_raw_index, var_station_distance_exceeded,
var_goal_distance;

var_station_direction=point_direction(var_x,var_y,var_sx,var_sy);

if var_sx!=undefined var_station_distance_exceeded=point_distance(var_x,var_y,var_sx,var_sy)>var_go_distance
else var_station_distance_exceeded=false;

var_goal_distance=point_distance(loc_ret_x,loc_ret_y,var_x,var_y);


if var_goal_distance>=loc_goal_reach_distance {
 loc_startup_timer=-1;
}
else {
 loc_ret_x=x;
 loc_ret_y=y;
}

if loc_startup_timer>=loc_raw_slice_count/loc_sub_slice_count 
and var_goal_distance<loc_goal_reach_distance {
  var var_raw_slice_size, var_ii;
  var_raw_slice_size=360/loc_raw_slice_count;
  var_ii=0;
  var var_align_direction_min_diff, var_align_direction, var_align_direction_diff;
  if var_station_distance_exceeded var_align_direction=var_station_direction;
  else {
   // Custom: chance of trying to maintain approximate direction
   // |----------|
   if irandom(4)=0 var_align_direction=irandom(359);
   // Custom: feild of random direction offset for approximation
   //                                |-------------|
   else var_align_direction=direction-30+irandom(60);
  }
  var_align_direction_min_diff=1000;
  repeat loc_raw_slice_count {
   var var_last_slice; var_last_slice=var_ii-1;
   if var_last_slice<0 var_last_slice+=loc_raw_slice_count;
   var var_last_slice2; var_last_slice2=var_ii-2;
   if var_last_slice2<0 var_last_slice2+=loc_raw_slice_count;
   var var_next_slice; var_next_slice=var_ii+1;
   if var_next_slice>=loc_raw_slice_count var_next_slice-=loc_raw_slice_count;
   var var_next_slice2; var_next_slice2=var_ii+2;
   if var_next_slice2>=loc_raw_slice_count var_next_slice2-=loc_raw_slice_count;
   // dont walk away from the station for an "interesting direction"
   if var_station_distance_exceeded var_exception=abs(angle_difference(var_ii*var_raw_slice_size,var_align_direction+180))>75;
   else var_exception=true;
   // Custom: 30 is the far neighbor "interesting direction" threshold
   if (loc_pie_data[var_last_slice2]<=loc_pie_data[var_ii]-(loc_interesting_direction_threshold*2) 
   or loc_pie_data[var_next_slice2]<=loc_pie_data[var_ii]-(loc_interesting_direction_threshold*2)) 
   // Custom: 17 is the close neighbor "interesting direction" threshold
   if (loc_pie_data[var_last_slice]<=loc_pie_data[var_ii]-loc_interesting_direction_threshold  
   or loc_pie_data[var_next_slice]<=loc_pie_data[var_ii]-loc_interesting_direction_threshold) 
   // Custom: 40 is the minimum acceptable scan ray distance.
   and loc_pie_data[var_ii]>40 
   and var_exception {
    var_align_direction_diff=abs(angle_difference(var_align_direction,var_ii*var_raw_slice_size));
    if var_align_direction_min_diff>var_align_direction_diff {
     var_align_direction_min_diff=var_align_direction_diff;
     var_chosen_direction_raw_index=var_ii;
    }
   }
   var_ii+=1
  }
  if var_align_direction_min_diff=1000 {
   if var_station_distance_exceeded direction=floor(var_station_direction/var_raw_slice_size)*var_raw_slice_size;
   else direction=irandom(loc_raw_slice_count-1)*var_raw_slice_size;
   var_chosen_direction_raw_index=direction/var_raw_slice_size
  }
  else direction=var_chosen_direction_raw_index*var_raw_slice_size;
  var var_max_dist, var_chosen_length;
  var_max_dist=loc_pie_data[var_chosen_direction_raw_index];
  // Custom: 0.6 is a multiple of a scan-ray's distance for the chosen direction
  // Custom: 16 is padding to avoid having the wander target go into a solid
  // they both specify walk distance randomization paramiters
  var_chosen_length=irandom_range(var_max_dist*0.6,var_max_dist-16)
  loc_ret_x=var_x+lengthdir_x(var_chosen_length,direction);
  loc_ret_y=var_y+lengthdir_y(var_chosen_length,direction);
}

optional

Expand///pie_move_draw(station_x, station_y, travel_distance)
//
// this script is only intended for visualizing how "pie move" works
// - This script is not synced with any data from the "pie_move_point" script
// this script should be called in a draw event
//
// station_x         x location of station to wander around
// station_y         y location of station to wander around
// travel_distance   station's unrestricted movement distance
// 
// see script "pie_move_update" for an example of use
//
///gmlscripts.com/license

var_sx=argument[0]
var_sy=argument[1]
var_go_distance=argument[2]

draw_set_color(c_fuchsia);
draw_circle(var_sx,var_sy,var_go_distance,1);
draw_circle(var_sx,var_sy,3,1);
var_raw_slice_size=360/loc_raw_slice_count;
var var_ii; var_ii=0;
repeat loc_raw_slice_count {
 var var_last_slice; var_last_slice=var_ii-1;
 if var_last_slice<0 var_last_slice+=loc_raw_slice_count;
 var var_last_slice2; var_last_slice2=var_ii-2;
 if var_last_slice2<0 var_last_slice2+=loc_raw_slice_count;
 var var_next_slice; var_next_slice=var_ii+1;
 if var_next_slice>=loc_raw_slice_count var_next_slice-=loc_raw_slice_count;
 var var_next_slice2; var_next_slice2=var_ii+2;
 if var_next_slice2>=loc_raw_slice_count var_next_slice2-=loc_raw_slice_count;
 
  // 30 is the far neighbor "interesting direction" threshold
  //if (loc_pie_data[var_last_slice2]<=loc_pie_data[var_ii]-30 
  //or loc_pie_data[var_next_slice2]<=loc_pie_data[var_ii]-30) 
  // 17 is the close neighbor "interesting direction" threshold
  if (loc_pie_data[var_last_slice]<=loc_pie_data[var_ii]-17 
  or loc_pie_data[var_next_slice]<=loc_pie_data[var_ii]-17) 
  // 40 is the minimum acceptable scan ray distance.
  and loc_pie_data[var_ii]>40 {
  if loc_startup_timer>(loc_raw_slice_count/loc_sub_slice_count) {
   draw_set_color(c_red)
  }
  else draw_set_color(c_yellow)
 }
 else draw_set_color(c_aqua)
 draw_line(x,y,x+lengthdir_x(loc_pie_data[var_ii],var_ii*var_raw_slice_size),y+lengthdir_y(loc_pie_data[var_ii],var_ii*var_raw_slice_size))
 
 var_ii+=1;
}
draw_set_color(c_lime);
draw_rectangle(loc_ret_x-1,loc_ret_y-1,loc_ret_x+1,loc_ret_y+1,0)

Last edited by lostdarkwolf (2020-04-07 00:13:18)

Offline

Board footer

Powered by FluxBB