GMLscripts.com

Discuss and collaborate on GML scripts
Invert

You are not logged in.

#1 2018-06-14 06:30:59

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

no vk platformer physics (BIG UPDATE 3/13/19). Uses GM's variables.

UPDATE 3/13/19:
This post contains the scripts for platformer physics with solids. The post below this one contains a much more versatile set of collision scripts that can combine psudo-solids and local-multiplayer.

Get platformer physics without the use of input. Uses GM's built in variables. The code is set up to react instead of pilot, enabling this code to be used with non-player characters! Movement is quite smooth and refined. smile

UPDATE 3/11/19:
This new script is much better than the old one, with no known flaws.
UPDATE 3/13/19:
separated correction and reaction

///collision_platformer_react(stair_height, gravity)
//
// Provides platformer physics for an instance without using input.
// Integrates GM's native variables into its code. (Including but not limited to direction, speed, and gravity.)
// Requires scripts "direction_fix" and "wiggle".
// 
// stair_height  Maximum height of stairs, real.
// gravity       Default gravity for the current step, real.
// 
// Should be placed in the step event of any platformer instance.
// All arguments are optional.
//
///gmlscripts.com

var CPS_stair_height; CPS_stair_height=13;
if argument_count>0 CPS_stair_height=argument[0];

var CPS_gravity; CPS_gravity=1;
if argument_count>1 CPS_gravity=argument[1];

var var_a=max(CPS_stair_height,abs(hspeed)*2.2);
var var_can_stair=place_free(x+(hspeed),y-var_a);//-abs(speed));

// Check for collision with ground
CPS_on_ground=0;
if (not place_free(x+4,y+1) or not place_free(x-4,y+1)) and not place_free(x,y+1) {
 gravity=0;
 if vspeed>0 vspeed=0
 CPS_on_ground=1;
 move_contact_solid(270,max(speed,2,CPS_stair_height))
}
else gravity=CPS_gravity;
///collision_platformer_correct(stair_height)
//
// Provides platformer physics for an instance without using input.
// Integrates GM's native variables into its code. (Including but not limited to direction, speed, and gravity.)
// Requires scripts "direction_fix" and "wiggle".
// 
// stair_height  Maximum height of stairs, real.
// 
// Should be placed in the step event of any platformer instance.
// All arguments are optional.
//
///gmlscripts.com

var CPS_stair_height; CPS_stair_height=13;
if argument_count>0 CPS_stair_height=argument[0];

var var_a=max(CPS_stair_height,abs(hspeed)*2.2);
var var_can_stair=place_free(x+(hspeed),y-var_a);//-abs(speed));

//go up stairs and slopes
if not place_free(x,y) and var_can_stair {
 y-=var_a;
 move_contact_solid(270,var_a)
}

//get unstuck
var ii; ii=1;
while ii<ceil(var_a*2) and not place_free(x,y) {
 if not place_free(x,y) wiggle(ii,-1); // Dont let the instance get stuck
 ii+=2;
}

// Vertical collisions and bumps (like with a sloped roof)
if not place_free(x,y+vspeed) and vspeed!=0 {
 var var_dir_fix_result=0;
 if vspeed<0 var_dir_fix_result=direction_fix(id,5,47);
 if not place_free(x,y+vspeed) and not var_dir_fix_result {
  move_contact_solid(((sign(vspeed)+1)*90)+90,speed);
  vspeed=0;
 }
}

// Check for collision with wall (you can delete this bit if you don't need it.)
CPS_on_wall=0;
if not place_free(x+sign(hspeed),y) and not var_can_stair and hspeed!=0 {
 CPS_on_wall=1;
 hspeed=0;
}

REQUIRED SCRIPTS:

///direction_fix(inst*, angular_precision*, direction_flux_cap*)
// * all arguments are optional
//
// corrects the direction of the calling instance to not collide with the target instance (or object).
// returns weather successful
//
// inst                  instance to avoid, set to -1 to avoid solids.
// angular_precision     precision for checking for empty spots
// direction_flux_cap    cap for direction change
//
///gmlscripts.com

var ii_inst, SCRprec, SCRlimit;
ii_inst=-1;
if argument_count>0 ii_inst=argument[0];
SCRprec=2;
if argument_count>1 SCRprec=argument[1];
SCRlimit=90;
if argument_count>2 SCRlimit=argument[2];


if ii_inst!=-1 {
 if place_meeting(x+lengthdir_x(speed,direction),y+lengthdir_y(speed,direction),ii_inst) {
  //smooth movement
  for(ii=0; ii<=SCRlimit; ii+=SCRprec;){
   if(!place_meeting(x+lengthdir_x(speed,direction+ii),y+lengthdir_y(speed,direction+ii),ii_inst)) {
    direction+=ii;
    ii=90+1;
    return true;
   }
   if(!place_meeting(x+lengthdir_x(speed,direction-ii),y+lengthdir_y(speed,direction-ii),ii_inst) and
      ii<=90) {
    direction-=ii;
    ii=90+1;
    return true;
   }
  }
 }
 return false;
}
else {
 if !place_free(x+lengthdir_x(speed,direction),y+lengthdir_y(speed,direction)) {
  //smooth movement
  for(ii=0; ii<=SCRlimit; ii+=SCRprec;){
   if(place_free(x+lengthdir_x(speed,direction+ii),y+lengthdir_y(speed,direction+ii))) {
    direction+=ii;
    ii=90+1;
    return true;
   }
   if(place_free(x+lengthdir_x(speed,direction-ii),y+lengthdir_y(speed,direction-ii)) and
      ii<=90) {
    direction-=ii;
    ii=90+1;
    return true;
   }
  }
 }
 return false;
}
///wiggle(max_dist*, inst*)
// * all arguments are optional
//
// tries to wiggle an object free of an instance.
// returns true if successful.
//
// max_dist    ammount in pixels of the position change.
// inst        instance or object to wiggle from, set to -1 to wiggle from solids. (-1 is default)
//
///gmlscripts.com

var ii_distance, ii_inst;
ii_distance=1000000000
if argument_count>0 ii_distance=argument[0];
ii_inst=-1;
if argument_count>1 ii_inst=argument[1];

// overhead view, you are X.
// 7 8 9
// 4 X 6
// 1 2 3
// order is X64283719

if ii_inst!=-1 {
 if !place_meeting(x,y,ii_inst) {return 1;} // X
 if !place_meeting(x+ii_distance,y,ii_inst) {x+=ii_distance; return 1;} // 6
 if !place_meeting(x-ii_distance,y,ii_inst) {x-=ii_distance; return 1;} // 4
 if !place_meeting(x,y+ii_distance,ii_inst) {y+=ii_distance; return 1;} // 2
 if !place_meeting(x,y-ii_distance,ii_inst) {y-=ii_distance; return 1;} // 8
 if !place_meeting(x+ii_distance,y+ii_distance,ii_inst) {y+=ii_distance; x+=ii_distance; return 1;} // 3
 if !place_meeting(x-ii_distance,y-ii_distance,ii_inst) {y-=ii_distance; x-=ii_distance; return 1;} // 7
 if !place_meeting(x-ii_distance,y+ii_distance,ii_inst) {y+=ii_distance; x-=ii_distance; return 1;} // 1
 if !place_meeting(x+ii_distance,y-ii_distance,ii_inst) {y-=ii_distance; x+=ii_distance; return 1;} // 9
}
else {
 if place_free(x,y) {return 1;} // X
 if place_free(x+ii_distance,y) {move_outside_solid(0,ii_distance); return 1;} // 6
 if place_free(x-ii_distance,y) {move_outside_solid(180,ii_distance); return 1;} // 4
 if place_free(x,y+ii_distance) {move_outside_solid(270,ii_distance); return 1;} // 2
 if place_free(x,y-ii_distance) {move_outside_solid(90,ii_distance);; return 1;} // 8
 if place_free(x+ii_distance,y+ii_distance) {move_outside_solid(315,ii_distance); return 1;} // 3
 if place_free(x-ii_distance,y-ii_distance) {move_outside_solid(135,ii_distance); return 1;} // 7
 if place_free(x-ii_distance,y+ii_distance) {move_outside_solid(225,ii_distance); return 1;} // 1
 if place_free(x+ii_distance,y-ii_distance) {move_outside_solid(45,ii_distance); return 1;} // 9
}

Last edited by lostdarkwolf (2019-03-13 22:56:18)

Offline

#2 2019-03-13 22:40:07

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

Re: no vk platformer physics (BIG UPDATE 3/13/19). Uses GM's variables.

Sorry if this is dual-posting, but this is a pretty big update with a whole new set of scripts.
Each instance calling collision_platformer_list functions should have its own object list.
Each object list is a list of objects and/or instances to be considered solid only by the instance calling the script.
The solid flag is ignored.
The ability to specify an object list is useful to be able to combine psudo-solids and local-multiplayer.

Please let me know if you notice any problems or have any questions.

///collision_platformer_list_react(object_list, stair_height, gravity);
//
// Provides platformer physics reactions for an instance without using input.
// Integrates GM's native variables into its code. (Including but not limited to direction, speed, and gravity.)
// Requires scripts "move_contact_list" and "place_meeting_list".
// 
// stair_height   Maximum height of stairs, real.
// gravity        Default gravity for the current step, real.
// object_list    List of specific instances and/or object indexes to treat as solid.
// 
// Should be placed in the step event of any platformer instance.
// All arguments are optional.
//
/// GMLscripts.com/license

var CPS_obj_list;
CPS_obj_list=argument[0];

var CPS_stair_height; CPS_stair_height=13;
if argument_count>1 CPS_stair_height=argument[1];

var CPS_gravity; CPS_gravity=1;
if argument_count>2 CPS_gravity=argument[2];

// Check for collision with ground
//CPS_on_ground=0;
if (place_meeting_list(x+4,y+1,CPS_obj_list) or place_meeting_list(x-4,y+1,CPS_obj_list)) and place_meeting_list(x,y+1,CPS_obj_list) {
 gravity=0;
 if vspeed>0 vspeed=0
 //CPS_on_ground=1;
 move_contact_list(CPS_obj_list,270,max(speed,2,CPS_stair_height))
}
else gravity=CPS_gravity;
///collision_platformer_list_correct(object_list, stair_height);
//
// Provides platformer physics reactions for an instance without using input.
// Integrates GM's native variables into its code. (Including but not limited to direction, speed, and gravity.)
// Requires scripts "place_meeting_list", "wiggle_list", "move_outside_list", "move_contact_list", and "direction_fix_list".
// 
// object_list    List of specific instances and/or object indexes to treat as solid, real (ds_list).
// stair_height   Maximum height of stairs, real.
// 
// Should be placed in the step event of any platformer instance.
// All arguments are optional.
// The object list contains a list of objects and/or instances that should be treated as solid by the instance calling the script.
//
/// GMLscripts.com/license

var CPS_obj_list;
CPS_obj_list=argument[0];

var CPS_stair_height; CPS_stair_height=13;
if argument_count>1 CPS_stair_height=argument[1];

var var_placemeet_current=place_meeting_list(x,y,CPS_obj_list)

// var_a represents 
var var_a=median(CPS_stair_height,abs(hspeed)*2.2,1);
var var_can_stair=var_placemeet_current
                  and (not place_meeting_list(x+(hspeed),y-var_a,CPS_obj_list)
                  or not place_meeting_list(x+(hspeed),y-(var_a*0.8),CPS_obj_list)
                  or not place_meeting_list(x+(hspeed),y-(var_a*0.6),CPS_obj_list)
                  or not place_meeting_list(x+(hspeed),y-(var_a*0.4),CPS_obj_list)
                  or not place_meeting_list(x+(hspeed),y-(var_a*0.2),CPS_obj_list))
                  and hspeed!=0;

var var_stair_up=0;

//go up stairs
move_outside_list(CPS_obj_list,90,var_a);

//get unstuck
var ii; ii=1;
while ii<ceil(var_a*2) and place_meeting_list(x,y,CPS_obj_list) {
 if place_meeting_list(x,y,CPS_obj_list) wiggle_list(CPS_obj_list,ii); // Dont let the instance get stuck
 ii+=2;
}

// Upward vertical collisions and bumps (like with a sloped roof)
if place_meeting_list(x,y+vspeed,CPS_obj_list) and vspeed<0 {
 var var_dir_fix_result=0;
 var var_old_dir=direction
 var_dir_fix_result=direction_fix_list(CPS_obj_list,5,52);
 if abs(angle_difference(90,direction))>=90 {
  direction=var_old_dir;
  var_dir_fix_result=0;
 }
 else {
  // speed loss for hitting an angled roof
  speed=speed*0.9
 }
 if place_meeting_list(x,y+vspeed,CPS_obj_list) and not var_dir_fix_result {
  move_contact_list(CPS_obj_list,((sign(vspeed)+1)*90)+90,speed);
  vspeed=0;
 }
}

//horizontal collisions
if place_meeting_list(x+hspeed,y,CPS_obj_list) 
and place_meeting_list(x+hspeed,y-(CPS_stair_height*0.25),CPS_obj_list) 
and place_meeting_list(x+hspeed,y+(CPS_stair_height*0.25),CPS_obj_list) 
and place_meeting_list(x+hspeed,y-(CPS_stair_height*0.5),CPS_obj_list) 
and place_meeting_list(x+hspeed,y+(CPS_stair_height*0.5),CPS_obj_list) 
and place_meeting_list(x+hspeed,y-(CPS_stair_height*0.75),CPS_obj_list) 
and place_meeting_list(x+hspeed,y+(CPS_stair_height*0.75),CPS_obj_list) 
and place_meeting_list(x+hspeed,y-CPS_stair_height,CPS_obj_list) 
and place_meeting_list(x+hspeed,y+CPS_stair_height,CPS_obj_list) 
and hspeed!=0 {
 hspeed=0;
}

// This part is optional and can be safely erased
// check if on wall (should be done after corrective translations)
if not place_meeting_list(x,y+1,CPS_obj_list) {
 CPS_on_wall=0 // this is a local variable
 if place_meeting_list(x+1,y,CPS_obj_list) CPS_on_wall=1;
 if place_meeting_list(x-1,y,CPS_obj_list) CPS_on_wall=-1;
}

REQUIRED SCRIPTS:

///place_meeting_list(x, y, obj_list)
//
// Checks for a collision with a list of instances and/or objects.
// Does the same thing as place_meeting, but with a list of objects instead of just one.
//
// x          X position to check.
// y          Y position to check.
// obj_list   list of instances and/or objects to check for collision with.
//
/// GMLscripts.com/license

var var_arg_x, var_arg_y, var_arg_ds, var_return, ii;
var_arg_x=argument[0];
var_arg_y=argument[1];
var_arg_ds=argument[2];

//show_message('place_meeting_list called')
var_return=0;
var ii=ds_list_size(var_arg_ds)-1;
while ii>=0 and var_return=0 {
 //show_message('ii is '+string(ii))
 if place_meeting(var_arg_x,var_arg_y,ds_list_find_value(var_arg_ds,ii)) var_return=1;
 ii-=1;
}

return var_return;
///wiggle_list(obj_list, max_dist*)
// * arguments are optional
//
// tries to wiggle an object free of a listed instance.
// returns true if successful.
//
// obj_list    list of instances and/or objects to move out of, real (ds_list)
// max_dist    ammount in pixels of the position change, real
//
///gmlscripts.com

var ii_distance, ii_inst, var_obj_list;
var_obj_list=argument[0];
ii_distance=1000000000;
if argument_count>1 ii_distance=argument[1];
ii_inst=-1;
if argument_count>2 ii_inst=argument[2];

// overhead view, you are X.
// 7 8 9
// 4 X 6
// 1 2 3
// order is X64283719

if !place_meeting_list(x,y,var_obj_list) {return 1;} // X
if !place_meeting_list(x+ii_distance,y,var_obj_list) {x+=ii_distance; return 1;} // 6
if !place_meeting_list(x-ii_distance,y,var_obj_list) {x-=ii_distance; return 1;} // 4
if !place_meeting_list(x,y+ii_distance,var_obj_list) {y+=ii_distance; return 1;} // 2
if !place_meeting_list(x,y-ii_distance,var_obj_list) {y-=ii_distance; return 1;} // 8
if !place_meeting_list(x+ii_distance,y+ii_distance,var_obj_list) {y+=ii_distance; x+=ii_distance; return 1;} // 3
if !place_meeting_list(x-ii_distance,y-ii_distance,var_obj_list) {y-=ii_distance; x-=ii_distance; return 1;} // 7
if !place_meeting_list(x-ii_distance,y+ii_distance,var_obj_list) {y+=ii_distance; x-=ii_distance; return 1;} // 1
if !place_meeting_list(x+ii_distance,y-ii_distance,var_obj_list) {y-=ii_distance; x+=ii_distance; return 1;} // 9
///move_outside_list(obj_list,dir,max_dist,step_size*)
//
// moves the instance running this script a set number of pixels 
//    in the specified direction until it meets a listed instance.
//
// obj_list    a list of instances and/or objects to collide with, real (ds_list with instances and/or objects)
// dir         direction of travel, real
// max_dist    maximum distance of travel, real
// step_size   size of steps to travel, real
//
// Returns successful if collided.
// Useful for having psudo-solids with local multiplayer.
// Ignores the "solid" flag.
//
/// GMLscripts.com/license

var var_arg_obj_list;
var_arg_obj_list=argument[0];
var_arg_dir=argument[1];
var_arg_maxdist=argument[2];

step_size=0.01;
if argument_count>3 step_size=argument[3];

var var_start_x=x;
var var_start_y=y;

var_dist_traveled=0;
if place_meeting_list(x,y,var_arg_obj_list) {
 while place_meeting_list(x+lengthdir_x(step_size,var_arg_dir),y+lengthdir_y(step_size,var_arg_dir),var_arg_obj_list) 
       and var_dist_traveled<=var_arg_maxdist {
  x+=lengthdir_x(step_size,var_arg_dir);
  y+=lengthdir_y(step_size,var_arg_dir);
  var_dist_traveled+=step_size;
 }
 if var_dist_traveled<=var_arg_maxdist {
  x+=lengthdir_x(step_size,var_arg_dir);
  y+=lengthdir_y(step_size,var_arg_dir);
 }
}

// return successful if outside
if var_dist_traveled<=var_arg_maxdist return 1;
else {
 x=var_start_x;
 y=var_start_y;
}
///move_contact_list(obj_list,dir,max_dist,step_size*)
//
// moves the instance running this script a set number of pixels 
//    in the specified direction until it meets a listed instance.
//
// obj_list    a list of instances and/or objects to collide with, real (ds_list with instances and/or objects)
// dir         direction of travel, real
// max_dist    maximum distance of travel, real
// step_size   size of steps to travel, real
//
// Returns successful if collided.
// With this script, instance A can collide with instance B, while 
//    instance C does not (if it is set up appropriately).
// Useful for having psudo-solids with local multiplayer.
// Ignores the "solid" flag.
//
/// GMLscripts.com/license

var var_arg_obj_list;
var_arg_obj_list=argument[0];
var_arg_dir=argument[1];
var_arg_maxdist=argument[2];

step_size=0.01;
if argument_count>3 step_size=argument[3];

var var_start_x=x;
var var_start_y=y;

var_dist_traveled=0;
if not place_meeting_list(x,y,var_arg_obj_list) {
 while not place_meeting_list(x+lengthdir_x(step_size,var_arg_dir),y+lengthdir_y(step_size,var_arg_dir),var_arg_obj_list) 
       and var_dist_traveled<=var_arg_maxdist {
  x+=lengthdir_x(step_size,var_arg_dir);
  y+=lengthdir_y(step_size,var_arg_dir);
  var_dist_traveled+=step_size;
 }
}
// return successful if collided
if var_dist_traveled<=var_arg_maxdist return 1;
else {
 x=var_start_x;
 y=var_start_y;
}
///direction_fix_list(obj_list, angular_precision*, direction_flux_cap*)
// * arguments are optional
//
// corrects the direction of the calling instance to not collide with the target instance (or object).
// returns weather successful
//
// obj_list    a list of instances and/or objects to collide with, real (ds_list with instances and/or objects)
// inst                  instance to avoid, set to -1 to avoid solids.
// angular_precision     precision for checking for empty spots
// direction_flux_cap    cap for direction change
//
///gmlscripts.com

var SCRobj_list, SCRprec, SCRlimit;
SCRobj_list=argument[0];
SCRprec=2;
if argument_count>1 SCRprec=argument[1];
SCRlimit=90;
if argument_count>2 SCRlimit=argument[2];


if place_meeting_list(x+lengthdir_x(speed,direction),y+lengthdir_y(speed,direction),SCRobj_list) {
 //smooth movement
 for(ii=0; ii<=SCRlimit; ii+=SCRprec;){
  if(!place_meeting_list(x+lengthdir_x(speed,direction+ii),y+lengthdir_y(speed,direction+ii),SCRobj_list)) {
   direction+=ii;
   ii=90+1;
   return true;
  }
  if(!place_meeting_list(x+lengthdir_x(speed,direction-ii),y+lengthdir_y(speed,direction-ii),SCRobj_list) and
     ii<=90) {
   direction-=ii;
   ii=90+1;
   return true;
  }
 }
}
return false;

Last edited by lostdarkwolf (2019-03-14 03:41:37)

Offline

Board footer

Powered by FluxBB