0

I know this has been asked a lot, but personally, i couldn't find a suitable answer. Pretty much everywhere, the function looks something like:

function rccol(rect, circle){
    var dx = Math.abs(circle.x - (rect.x + rect.width / 2));
    var dy = Math.abs(circle.y - (rect.y + rect.height / 2));

    if(dx > circle.radius + rect.width / 2) return false;
    if(dy > circle.radius + rect.height / 2) return false;

    if(dx <= rect.width) return true;
    if(dy <= rect.height) return true; 

    var dx = dx - rect.width;
    var dy = dy - rect.height
    return((dx * dx + dy * dy) <= (circle.radius * circle.radius));
}

And that works perfectly. The issue is that I'm using it for collision detection in a game, where the circle is the player's collision box, and the square is let's say a wall. I need to be able to determine where the contact occurred so that i can actually prevent the "player" from going into the "wall" so the simple boolean that gets returned, doesn't really work in my use-case.

kriskotoo BG
  • 313
  • 5
  • 16

1 Answers1

0

Having circle center coordinates (cx, cy), you can calculate squared distance from circle center to rectangle.

dx = Max(Abs(cx - rect.center.x) - rect.width / 2, 0)
dy = Max(Abs(cy - rect.center.y) - rect.height / 2, 0)
SquaredDistance = dx * dx + dy * dy

When circle is outside of rectangle initially, it is possible to remove Max call.

dx = Abs(cx - rect.center.x) - rect.width / 2
dy = Abs(cy - rect.center.y) - rect.height / 2

Also we can remove Abs for known initial position (note - upto moment of sign change!)

if cx >= rect.center.x:
      dx = cx - rect.center.x - rect.width / 2
else:
      dx =  - cx + rect.center.x - rect.width / 2

To avoid a lot od different cases, we can virtually put player in the first quadrant relative to rectangle center and correspondingly change coordinates and velocity components

if cx0 < 0:
   cx0 = - cx0
   vx = -vx
if cy0 < 0:
   cy0 = - cy0
   vy = -vy

To register collision moment, you have to substitute coordinates with parametric equations using start point and velocity vector components (vx, vy)

cx = cx0 + vx * t
cy = cy0 + vy * t

and solve (quadratic) equation for t

SquaredDistance - Radius^2 = 0

(cx0 + vx * t - rect.center.x - rect.width/2)^2 + 
(cy0 + vy * t - rect.center.y - rect.height/2)^2 - 
Radius^2 = 0

Ater that you can get zero (no collision), one (touch event) or two roots (moment of collision and moment of exit).

MBo
  • 77,366
  • 5
  • 53
  • 86
  • The thing is, currently the "Player" or the circle object does not have a variable for a velocity, as it travels at a fixed speed.. – kriskotoo BG Jan 25 '21 at 14:19
  • Player definitely has velocity components ;) How is his movement described? With speed and angle? – MBo Jan 25 '21 at 14:35
  • For now, just adding a "speed" value to the x and y cordinates based on the user inuput – kriskotoo BG Jan 25 '21 at 14:42
  • if position changes as `x += vx` on timer, then `vx` is x-component of velocity – MBo Jan 25 '21 at 14:44
  • huh.. yeah, but I'm having a bit of trouble understanding how exactly to implement this.. – kriskotoo BG Jan 25 '21 at 14:52
  • Values and ratio of addends vx and vy define speed and direction of moving. You can substirute starting coordinates and these components into equation and get quadratic equation. – MBo Jan 25 '21 at 14:56
  • no, i got that part down, what i meant is actually *using* the equations to get the side of impact, maybe i'm just not understanding the examples.. I'm fairly new to this type of stuff, and i need more "in-depth" explanations, sorry! – kriskotoo BG Jan 25 '21 at 15:00
  • I addes some explanations – MBo Jan 25 '21 at 15:03
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/227801/discussion-between-kriskotoo-bg-and-mbo). – kriskotoo BG Jan 25 '21 at 15:35