Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //differs from shape::rect in that the rectangle is defined
- //by 2 points instead of a top-left position + w,h
- struct shape_quad {
- kit::shape::point a, b; //top-left corner, bottom-right corner
- shape_quad() : a(0, 0), b(0, 0) {}
- shape_quad(kit::shape::rect& r) : a(r.x, r.y), b(r.w, r.h) { b += a; }
- inline void operator-=(const shape_quad& q){ a -= q.a; b -= q.b; }
- inline void operator+=(const shape_quad& q){ a += q.a; b += q.b; }
- inline void operator*=(const kit::s32 & v){ a.x *= v; a.y *= v; b.x *= v; b.y *= v; }
- inline void operator/=(const kit::s32 & v){ a.x /= v; a.y /= v; b.x /= v; b.y /= v; }
- };
- //player collider rect is the same as its blit rect for simplicity
- inline shape::rect Player::getRect(){
- shape::rect result;
- //lock size to a multiple of 2 pixels for even division by 2
- result.w = abs( RND(8.0f*scale) & (~1) );
- result.h = result.w;
- result.x = RND(pos.x) - result.w/2;
- result.y = RND(pos.y) - result.h/2;
- return result;
- }
- void gl_win_drawRectEmpty(shape::rect rect, color::ARGB color, u32 width){
- rect.w += rect.x-1;
- rect.h += rect.y-1;
- shape::point points[5];
- points[0] = shape::point(rect.x, rect.y);
- points[1] = shape::point(rect.w, rect.y);
- points[2] = shape::point(rect.w, rect.h);
- points[3] = shape::point(rect.x, rect.h);
- points[4] = points[0];
- gl_win->drawLines((shape::point*)points, 5, color, width);
- }
- bool rects_overlapping(shape::rect object_rect,
- shape::rect obstacle_rect,
- shape::point* delta_p)
- {
- //get bounding boxes of object and obstacle
- shape_quad obj = object_rect;
- shape_quad obs = obstacle_rect;
- bool overlapping = obj.a.x < obs.b.x && obj.b.x > obs.a.x &&
- obj.a.y < obs.b.y && obj.b.y > obs.a.y;
- //delta is initialized so *delta_p can be set regardless of overlap
- shape::point delta(0, 0);
- if(!overlapping) goto _draw_collision_;
- //find minimum translation vector
- //(movement delta needed to resolve collision)
- s32 overlapX1 = obs.b.x - obj.a.x; //obs right edge relative to obj left edge
- s32 overlapX2 = obj.b.x - obs.a.x; //obj right edge relative to obs left edge
- s32 overlapY1 = obs.b.y - obj.a.y; //obs bottom edge relative to obj top edge
- s32 overlapY2 = obj.b.y - obs.a.y; //obj bottom edge relative to obs top edge
- s32 overlapX = (overlapX1 < overlapX2) ? overlapX1 : -overlapX2;
- s32 overlapY = (overlapY1 < overlapY2) ? overlapY1 : -overlapY2;
- if(abs(overlapX) < abs(overlapY)) delta.x = overlapX; //.y will remain 0
- else delta.y = overlapY; //.x will remain 0
- _draw_collision_:
- #if defined(_DEBUG) && defined(SHOW_COLLISIONS)
- gl_win_drawRectEmpty(object_rect, (overlapping) ? 0x00ff00 : 0xff0000);
- gl_win_drawRectEmpty(obstacle_rect, (overlapping) ? 0x00ff00 : 0xff0000);
- #endif
- if(delta_p) *delta_p = delta;
- return overlapping;
- }
- //returns true if subtile has collision
- //also, r is filled in with the exact rect of the subtile for aabb detection
- static inline bool subtile_is_collidable(s32 x, s32 y){
- //this line is probably redundant
- //if(x<0 || x>=(TILESIZ_X*2) || y<0 || y>=(TILESIZ_Y*2)) return false;
- //get the associated tile (midground is used)
- Tile tile = gl_scene.pat_mg[ ARR2D(x>>1, y>>1, TILESIZ_X) ];
- s32 which_bit = (y&1)<<1 | x&1;
- return (tile.collision>>which_bit)&1;
- }
- //returns true only if resulting bounds have volume
- static inline bool get_tile_bounds(shape_quad& bounds){
- //find the boundaries of all tiles that the player is touching
- //(+= 11 so that an east/south subtile boundary is crossed only when
- // a pixel of the player sprite actually overlaps a given tile)
- bounds.b += shape::point(11, 11);
- bounds /= 12; //convert pixels to subtiles
- //
- bounds.a.x = CLAMP(bounds.a.x, 0, TILESIZ_X*2); //skip subtiles that are off-screen
- bounds.a.y = CLAMP(bounds.a.y, 0, TILESIZ_Y*2); //(2 subtiles in a tile lengthwise)
- //
- bounds.b.x = CLAMP(bounds.b.x, 0, TILESIZ_X*2);
- bounds.b.y = CLAMP(bounds.b.y, 0, TILESIZ_Y*2);
- //bounds.b -= bounds.a; //effectively converts a quad to rect; not necessary
- return bounds.b.x > 0 && bounds.b.y > 0;
- }
- //prototype; tbd: make this better (lol)
- bool Player::colliding(shape::point* delta_p, shape::rect* object_rect){
- shape::rect player_rect_original = getRect();
- shape::rect player_rect = player_rect_original;
- shape_quad player_quad = player_rect;
- shape_quad bounds = player_quad;
- if(object_rect) return rects_overlapping(player_rect, *object_rect, delta_p);
- if(!get_tile_bounds(bounds)){ //there are no subtiles to check; exit early
- if(delta_p) *delta_p = shape::point(0, 0); //neutral delta
- return false;
- }
- shape::point sub;
- shape::rect col(0,0, 12,12); //subtile collider
- s32 xmid = (bounds.a.x+bounds.b.x)/2; //x subtile midpoint
- //bottom-to-top vertically
- for(sub.y=bounds.b.y-1; sub.y>=bounds.a.y; --sub.y){
- col.y = sub.y*12;
- //right-to-left on the left half
- for(sub.x=xmid-1; sub.x>=bounds.a.x; --sub.x){
- //col.x = sub.x*12;
- //gl_win_drawRectEmpty(col, 0x00ffff); //cyan
- if(subtile_is_collidable(sub.x,sub.y)){
- col.x = sub.x*12;
- shape::point delta;
- if(rects_overlapping(player_rect, col, &delta)) player_rect += delta;
- }
- }
- //left-to-right on the right half
- for(sub.x=xmid; sub.x<bounds.b.x; ++sub.x){
- //col.x = sub.x*12;
- //gl_win_drawRectEmpty(col, 0xffff00); //yellow
- if(subtile_is_collidable(sub.x,sub.y)){
- col.x = sub.x*12;
- shape::point delta;
- if(rects_overlapping(player_rect, col, &delta)) player_rect += delta;
- }
- }
- }
- //bounds *= 12;
- //bounds.b -= bounds.a;
- //gl_win_drawRectEmpty(*(shape::rect*)&bounds, 0xff00ff);
- shape::point delta;
- delta.x = player_rect.x - player_rect_original.x;
- delta.y = player_rect.y - player_rect_original.y;
- if(delta_p) *delta_p = delta;
- return delta.x!=0 || delta.y!=0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement