Advertisement
Kitomas

work for 2024-06-07

Jun 7th, 2024
500
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.11 KB | None | 0 0
  1. //differs from shape::rect in that the rectangle is defined
  2.  //by 2 points instead of a top-left position + w,h
  3. struct shape_quad {
  4.   kit::shape::point a, b; //top-left corner, bottom-right corner
  5.  
  6.   shape_quad() : a(0, 0), b(0, 0) {}
  7.   shape_quad(kit::shape::rect& r) :  a(r.x, r.y), b(r.w, r.h)  {  b += a;  }
  8.  
  9.   inline void operator-=(const shape_quad& q){ a -= q.a;  b -= q.b; }
  10.   inline void operator+=(const shape_quad& q){ a += q.a;  b += q.b; }
  11.   inline void operator*=(const kit::s32  & v){ a.x *= v;  a.y *= v;  b.x *= v;  b.y *= v; }
  12.   inline void operator/=(const kit::s32  & v){ a.x /= v;  a.y /= v;  b.x /= v;  b.y /= v; }
  13.  
  14. };
  15.  
  16.  
  17.  
  18.  
  19.  
  20. //player collider rect is the same as its blit rect for simplicity
  21. inline shape::rect Player::getRect(){
  22.   shape::rect result;
  23.  
  24.   //lock size to a multiple of 2 pixels for even division by 2
  25.   result.w = abs( RND(8.0f*scale) & (~1) );
  26.   result.h = result.w;
  27.   result.x = RND(pos.x) - result.w/2;
  28.   result.y = RND(pos.y) - result.h/2;
  29.  
  30.   return result;
  31. }
  32.  
  33.  
  34.  
  35.  
  36.  
  37. void gl_win_drawRectEmpty(shape::rect rect, color::ARGB color, u32 width){
  38.   rect.w += rect.x-1;
  39.   rect.h += rect.y-1;
  40.  
  41.   shape::point points[5];
  42.   points[0] = shape::point(rect.x, rect.y);
  43.   points[1] = shape::point(rect.w, rect.y);
  44.   points[2] = shape::point(rect.w, rect.h);
  45.   points[3] = shape::point(rect.x, rect.h);
  46.   points[4] = points[0];
  47.  
  48.   gl_win->drawLines((shape::point*)points, 5, color, width);
  49.  
  50. }
  51.  
  52.  
  53.  
  54.  
  55.  
  56. bool rects_overlapping(shape::rect object_rect,
  57.                        shape::rect obstacle_rect,
  58.                        shape::point* delta_p)
  59. {
  60.   //get bounding boxes of object and obstacle
  61.   shape_quad obj = object_rect;
  62.   shape_quad obs = obstacle_rect;
  63.  
  64.  
  65.   bool overlapping = obj.a.x < obs.b.x  &&  obj.b.x > obs.a.x  &&
  66.                      obj.a.y < obs.b.y  &&  obj.b.y > obs.a.y;
  67.  
  68.   //delta is initialized so *delta_p can be set regardless of overlap
  69.   shape::point delta(0, 0);
  70.  
  71.   if(!overlapping) goto _draw_collision_;
  72.  
  73.  
  74.   //find minimum translation vector
  75.    //(movement delta needed to resolve collision)
  76.   s32 overlapX1 = obs.b.x - obj.a.x; //obs right edge relative to obj left edge
  77.   s32 overlapX2 = obj.b.x - obs.a.x; //obj right edge relative to obs left edge
  78.   s32 overlapY1 = obs.b.y - obj.a.y; //obs bottom edge relative to obj top edge
  79.   s32 overlapY2 = obj.b.y - obs.a.y; //obj bottom edge relative to obs top edge
  80.  
  81.   s32 overlapX = (overlapX1 < overlapX2) ? overlapX1 : -overlapX2;
  82.   s32 overlapY = (overlapY1 < overlapY2) ? overlapY1 : -overlapY2;
  83.  
  84.   if(abs(overlapX) < abs(overlapY)) delta.x = overlapX; //.y will remain 0
  85.   else                              delta.y = overlapY; //.x will remain 0
  86.  
  87.  
  88. _draw_collision_:
  89. #if defined(_DEBUG) && defined(SHOW_COLLISIONS)
  90.   gl_win_drawRectEmpty(object_rect,   (overlapping) ? 0x00ff00 : 0xff0000);
  91.   gl_win_drawRectEmpty(obstacle_rect, (overlapping) ? 0x00ff00 : 0xff0000);
  92. #endif
  93.  
  94.  
  95.   if(delta_p) *delta_p = delta;
  96.   return overlapping;
  97.  
  98. }
  99.  
  100.  
  101.  
  102.  
  103.  
  104. //returns true if subtile has collision
  105.  //also, r is filled in with the exact rect of the subtile for aabb detection
  106. static inline bool subtile_is_collidable(s32 x, s32 y){
  107.   //this line is probably redundant
  108.   //if(x<0 || x>=(TILESIZ_X*2)  ||  y<0 || y>=(TILESIZ_Y*2)) return false;
  109.  
  110.   //get the associated tile (midground is used)
  111.   Tile tile = gl_scene.pat_mg[ ARR2D(x>>1, y>>1, TILESIZ_X) ];
  112.   s32 which_bit = (y&1)<<1 | x&1;
  113.  
  114.   return (tile.collision>>which_bit)&1;
  115.  
  116. }
  117.  
  118.  
  119.  
  120. //returns true only if resulting bounds have volume
  121. static inline bool get_tile_bounds(shape_quad& bounds){
  122.   //find the boundaries of all tiles that the player is touching
  123.    //(+= 11 so that an east/south subtile boundary is crossed only when
  124.    // a pixel of the player sprite actually overlaps a given tile)
  125.   bounds.b += shape::point(11, 11);
  126.   bounds /= 12; //convert pixels to subtiles
  127.    //
  128.   bounds.a.x = CLAMP(bounds.a.x, 0, TILESIZ_X*2); //skip subtiles that are off-screen
  129.   bounds.a.y = CLAMP(bounds.a.y, 0, TILESIZ_Y*2);  //(2 subtiles in a tile lengthwise)
  130.    //
  131.   bounds.b.x = CLAMP(bounds.b.x, 0, TILESIZ_X*2);
  132.   bounds.b.y = CLAMP(bounds.b.y, 0, TILESIZ_Y*2);
  133.  
  134.   //bounds.b -= bounds.a; //effectively converts a quad to rect; not necessary
  135.  
  136.   return bounds.b.x > 0  &&  bounds.b.y > 0;
  137.  
  138. }
  139.  
  140.  
  141.  
  142. //prototype; tbd: make this better (lol)
  143. bool Player::colliding(shape::point* delta_p, shape::rect* object_rect){
  144.   shape::rect player_rect_original = getRect();
  145.   shape::rect player_rect          = player_rect_original;
  146.  
  147.   shape_quad player_quad = player_rect;
  148.   shape_quad bounds      = player_quad;
  149.  
  150.  
  151.   if(object_rect) return rects_overlapping(player_rect, *object_rect, delta_p);
  152.  
  153.  
  154.   if(!get_tile_bounds(bounds)){ //there are no subtiles to check; exit early
  155.     if(delta_p) *delta_p = shape::point(0, 0); //neutral delta
  156.     return false;
  157.   }
  158.  
  159.  
  160.  
  161.   shape::point sub;
  162.   shape::rect col(0,0, 12,12); //subtile collider
  163.   s32 xmid = (bounds.a.x+bounds.b.x)/2; //x subtile midpoint
  164.  
  165.   //bottom-to-top vertically
  166.   for(sub.y=bounds.b.y-1; sub.y>=bounds.a.y; --sub.y){
  167.     col.y = sub.y*12;
  168.  
  169.     //right-to-left on the left half
  170.     for(sub.x=xmid-1; sub.x>=bounds.a.x; --sub.x){
  171.       //col.x = sub.x*12;
  172.       //gl_win_drawRectEmpty(col, 0x00ffff); //cyan
  173.  
  174.       if(subtile_is_collidable(sub.x,sub.y)){
  175.         col.x = sub.x*12;
  176.         shape::point delta;
  177.         if(rects_overlapping(player_rect, col, &delta)) player_rect += delta;
  178.       }
  179.  
  180.     }
  181.  
  182.     //left-to-right on the right half
  183.     for(sub.x=xmid; sub.x<bounds.b.x; ++sub.x){
  184.       //col.x = sub.x*12;
  185.       //gl_win_drawRectEmpty(col, 0xffff00); //yellow
  186.  
  187.       if(subtile_is_collidable(sub.x,sub.y)){
  188.         col.x = sub.x*12;
  189.         shape::point delta;
  190.         if(rects_overlapping(player_rect, col, &delta)) player_rect += delta;
  191.       }
  192.  
  193.     }
  194.  
  195.   }
  196.  
  197.  
  198.   //bounds *= 12;
  199.   //bounds.b -= bounds.a;
  200.   //gl_win_drawRectEmpty(*(shape::rect*)&bounds, 0xff00ff);
  201.  
  202.   shape::point delta;
  203.   delta.x = player_rect.x - player_rect_original.x;
  204.   delta.y = player_rect.y - player_rect_original.y;
  205.  
  206.   if(delta_p) *delta_p = delta;
  207.  
  208.   return delta.x!=0 || delta.y!=0;
  209.  
  210. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement