Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- On Slopes and Grids: subpixel-perfect top-down movement and collision line without objects - Game Maker Studio
- by Ariak
- Includes:
- * Scripts for place_meeting and collision_point, factoring in 45° triangles using only grids
- * Script for collision line that is subpixel perfect - including 45° triangles and many other shapes in grids
- * subpixel 2D topdown movement code for moving along 45° slopes (grid based - no objects, easily adaptable though)
- *NOTE* 1. cell dimensions is 32x32 px! 2. This code assumes a square player hitbox.
- /// ========================================= GRID PLACE MEETING===================================================================
- Place Meeting: This is actually 2 scripts - it needs to know the sprite_widht,height of the calling object!
- /// ========== 1: gridcol_place_meeting ===============================
- ///gridcol_place_meeting(xx,yy);
- var xx=argument0;
- var yy=argument1;
- var col=false;
- // Adjust for object dimensions => find the borders from the sprite-origin given by xx,yy
- var left,right,up,down;
- left = xx-sprite_width/2;
- right= xx+(sprite_width/2)-1;
- up = yy-sprite_height/2;
- down = yy+(sprite_height/2)-1;
- // Check object/sprite borders
- col = ( gridcol_quadrant_rectangle(xx,yy,left,up) ||
- gridcol_quadrant_rectangle(xx,yy,right,up) ||
- gridcol_quadrant_rectangle(xx,yy,left,down) ||
- gridcol_quadrant_rectangle(xx,yy,right,down));
- return col;
- /// ========== 2: gridcol_quadrant_rectangle ===============================
- ///gridcol_quadrant_rectangle(ox,oy,xx,yy);
- var ox=argument0; // origin of sprite,object
- var oy=argument1;
- var xx=argument2; // target coordinates to check as determined by gridcol_place_meeting
- var yy=argument3;
- var ax=31*(ox>xx); // Quadrant intersections along border - see the visualization for this
- var ay=31*(oy>yy);
- var tx = xx mod 32;
- var ty = yy mod 32;
- var col=false;
- switch (obj_player.grid[# xx div 32, yy div 32]){
- case 2: col = ( (tx >= ty) || (tx >= ay) || (ax >= ty) ); break;
- case 3: col = ( (tx <= ty) || (tx <= ay) || (ax <= ty) ); break;
- case 1: col = ( (31-tx >= ty) || (31-tx >= ay) || (31-ax >= ty) ); break;
- case 4: col = ( (31-tx <= ty) || (31-tx <= ay) || (31-ax <= ty) ); break;
- case 5: col = true; break;
- }
- return col;
- /// ========================================== COLLISION POINT ==================================================================
- ///gridcol_point(x,y)
- //Determines if the given coordinates collide with a wall - much easier then the quadrant_rectangle!
- var tx = argument0 mod 32;
- var ty = argument1 mod 32;
- var col=false;
- switch (obj_player.grid[# argument0 div 32, argument1 div 32]){
- case 2: col = (tx >= ty); break;
- case 3: col = (tx <= ty); break;
- case 1: col = (31-tx >= ty); break;
- case 4: col = (31-tx <= ty); break;
- case 5: col=1; break;
- }
- return col;
- /// ========================================== COLLISION LINE ==================================================================
- ///gridcol_line(x1,x1,x2,y2);
- //=== INPUT ===
- var sx=argument0; var sy=argument1; var tx=argument2; var ty=argument3;
- // Check Start + End Point
- var col=(gridcol_point(sx,sy)||gridcol_point(tx,ty)); if col return col;
- // Check INTEGER X coordinates that intersect with grid, determine according y values mathmatically
- var deltax=abs((tx div 32) - (sx div 32));
- if deltax>0{
- var xslope=((ty-sy)/(tx-sx));
- var cx=(sx&~31)+31*(tx>sx);
- var cy=sy+xslope*(cx-sx)
- col = (gridcol_point(cx,cy)||gridcol_point((tx&~31)+31*(tx<sx),ty+xslope*(((tx&~31)+31*(tx<sx))-tx))); if col return col;
- var dirx=(tx>sx)-(tx<sx);
- repeat(deltax-1){
- col = (gridcol_point(cx+dirx,cy+xslope*dirx)||gridcol_point(cx+32*dirx,cy+xslope*32*dirx)); if col return col;
- cx+=32*dirx;
- cy+=xslope*32*dirx;
- }
- }
- // Check INTEGER Y coordinates that intersect with grid, determine according x values mathematically
- var deltay=abs((ty div 32) - (sy div 32));
- if deltay>0{
- var yslope=((tx-sx)/(ty-sy));
- var cy=(sy&~31)+31*(ty>sy);
- var cx=sx+yslope*(cy-sy)
- col=(gridcol_point(cx,cy)||gridcol_point(tx+yslope*(((ty&~31)+31*(ty<sy))-ty),(ty&~31)+31*(ty<sy))); if col return col;
- var diry=(ty>sy)-(ty<sy);
- repeat(deltay-1){
- col = (gridcol_point(cx+yslope*diry,cy+diry)||gridcol_point(cx+yslope*32*diry,cy+32*diry)); if col return col;
- cy+=32*diry;
- cx+=yslope*32*diry;
- }
- }
- return col;
- /// ========================================== 2D TOP DOWN MOVEMENT ==================================================================
- PLAYER CREATE EVENT:
- ///Variables for Movement
- mspd = 3; // maximum movement speed
- avx = 0; // actual velocity x - is used for saving uneven number remainder!
- avy = 0; // actual velocity y
- PLAYER STEP EVENT:
- /// Movement and Collision
- // Grab Keyboard Inputs
- var horizontal = keyboard_check(ord('D'))-keyboard_check(ord('A'));
- var vertical = keyboard_check(ord('S'))-keyboard_check(ord('W'));
- // Technically unneccesary as mspd can simply be multiplied with the keyboard checks above! Tutorial purpose.
- var vx=horizontal*mspd;
- var vy=vertical*mspd;
- // Move with Collision checks
- gridcol_move_speeds(vx,vy);
- /// ========================= Collision Script ===========================================
- Collision Movement Script for 2D topdown with subpixels, along 45° slopes based on grids.
- ///gridcol_move_speeds(vx,vy)
- //Input
- avx+=argument0;
- avy+=argument1;
- var vx=avx div 1;
- var vy=avy div 1;
- avx-=vx;
- avy-=vy;
- // Y + X AXIS
- var angle=point_direction(0,0,vx,vy);
- var pvx=vx*abs(dcos(angle));
- var pvy=vy*abs(dsin(angle));
- if !gridcol_place_meeting(x+pvx,y+pvy) {x=round(x+pvx);y=round(y+pvy);}
- else{
- // X AXIS
- if vx!=0{
- if vy!=0 {vy=((vy>0)-(vy<0))*abs(vx)}
- var sx=x;
- var svx=(vx>0)-(vx<0);
- repeat(abs(vx)){
- if !gridcol_place_meeting(x+svx,y) {x+=svx;}
- else {break;}
- }
- vx=round((vx-(x-sx))*dsin(45));
- if vx!=0{
- var ydir=(!gridcol_place_meeting(x+svx,y+1))-(!gridcol_place_meeting(x+svx,y-1));
- if ydir!=0{
- x+=svx;y+=ydir;
- repeat(abs(vx)-1){
- if (!gridcol_place_meeting(x+svx,y+ydir)) {x+=svx;y+=ydir;}
- else {break;}
- }
- }
- }
- }
- // Y AXIS
- if vy!=0{
- var sy=y;
- var svy=(vy>0)-(vy<0);
- repeat(abs(vy)){
- if !gridcol_place_meeting(x,y+svy) {y+=svy;}
- else {break;}
- }
- vy=round((vy-(y-sy))*dsin(45));
- if vy!=0{
- var xdir=(!gridcol_place_meeting(x+1,y+svy))-(!gridcol_place_meeting(x-1,y+svy));
- if xdir!=0{
- x+=xdir;y+=svy;
- repeat(abs(vy)-1){
- if (!gridcol_place_meeting(x+xdir,y+svy))
- {x+=xdir;y+=svy;}
- else {break;}
- }
- }
- }
- }
- } //END
Add Comment
Please, Sign In to add comment