For a pygame program I was working on I want to use a collision system similar to terraria by using a large quanitity of unrotated, same sized squares as the map. Theres a couple issues I came across while coding this.
-
Storage: I need an efficiant way to store my data and have it be good at taking small sample sizes to check collision in. Chunk based collision made the most sense for this process and I tried to apply a number to each block to specify what type of block it is. I assume AABB collision is a bit excessive for this process but I cant quite find out how to simplify it.
-
Collision: I can determine what blocks the player is intersecting with by checking the amount of blocks the players rectangle hitbox intersects with on a evenly spaced grid. Im not sure the formula for that but I doubt its very complicated. Once that is done I can check if any of these are blocks. To ensure players cant go through walls I would need to either make a form of CCD or probally just use a modified slope intercept form since their parallel and symmetrical.
-
Reseting Position: The most basic way I could think to reset the players position was to locate what collision would happen first which lends better to slope intercept collisions since I can consider its lerp output a position in time and the lowest will be the first.
-
Iterating: Now that I know where and when the collision occured, I can find out how it might continue. For collisions with a block above the character I would have to continue the collision with the new location and new delta time = previous delta time * (1-lerp value). Luckily, people tend not to bounce so left,right,floor collisions can just result in a complete stop so a maximum of 2 iterations are needed since you cant have 2 consecutive top collisions.
I feel this should work, but I cant find out how to preform these collisions optimally, if anyone has either the methods or some sample code thay would be helpful.
Heres some basic code if it helps:
# Linear Interpolation 2d
def lerp2(x1,y1: 'point a',x2,y2: 'point b', t) -> tuple:
return x1 + (x1-x2)*t, y1 + (y1-y2)*t
# Is point inside a given rectangle
def in_rect(x,y, rx,ry,rw,rh,rad):
return (rx-rad <x< rx+rw+rad) and (ry-rad <y< ry+rh+rad)
# Finds ab interception on axis B as well as interpolated value
def target_intercept(a1,b1,delta_a,delta_b, target_b):
target_delta = (target_b-b1) / delta_b
return a1 + delta_a*target_delta, -target_delta
# Distance between 2 points (absolute, slower)
def dist(x1,y1: 'point a',x2,y2: 'point b') -> float:
dx,dy = x1-x2, y1-y2
return (dx*dx + dy*dy)**0.5
# Distance between 2 points (relative, faster)
def dist_sq(x1,y1: 'point a',x2,y2: 'point b') -> float:
dx,dy = x1-x2, y1-y2
return dx*dx + dy*dy
# AABB (Axis Aligned Bounding Box) collision detection
def aabb(mx1,my1,Mx1,My1,mx2,my2,Mx2,My2) -> bool:
return mx1<Mx2 and Mx1>mx2 and my1<My2 and My1>my2
Markus Roman is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.