You are not logged in.
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.
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
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