# Elastic Circle-Circle collision detection and response / Slime Volleyball physics

I am trying to recreate the Slime Volleyball game; however I am unsure how to go about implementing the physics of the ball movement.

The game consists of a circular ball and semi circle players that hit the ball over a net and against a wall. The ball cannot touch the floor.

I need to understand how exactly to implement the hitting of the ball against the player and what the physics entails.

I have already implemented gravity with a bouncing ball.

It is hard to find information related to implementing such physics from a game development perspective and I only have vague ideas about change in momentum from googling. If anyone could explain how to do so, I would greatly appreciate it.

• You might want to look up "Elastic Collision" Commented Nov 12, 2015 at 16:19
• Please include details about exactly what it is about the physics in this game that you want to replicate. Remember that many people on this site who might want to help you have never played this game, and they shouldn't have to go do extra research just to figure out what your question means. Commented Nov 12, 2015 at 17:18
• You might want to look up box2d Commented Feb 12, 2016 at 3:37

Basically, you want to implement circle-cirle collision detection and response. I consider your character a static object and the ball a dynamic object. I do this because it makes everything a lot easier, and the character doesn't move too much anyways.

First, your ball should have a velocity vector and a position. You need to get it's old and new position (the new position is just old position + velocity) and it's radius. You should also have the position and radius of the player.

The old and new position of the ball forms a line, get the distance of the line and the player's position:

In case you don't know how to calculate the distance between a line and a point, here's a great StackOverflow answer for that.

d will always be the closest the 2 circles get to each other. If it's bigger than the sum of the 2 radiuses, then they never collide. This is the end of the broad phase.

Now we can get the exact point the 2 circles collide:

d is the closest the 2 circles get, t is the sum of the circles' radiuses. s is the distance of the collision point from the closest point, this is unknown but you can calculate it with the Pythagorean theorem:

s = sqrt(t * t - d * d)


Now calculate the distance between the closest point and the old position (get the distance from the old position and the player, then use the Pythagorean theorem again with the distance and d), divide s from it, then multiply the normalized velocity vector of the ball with the result. Again, in pseudo code:

func get_position(float s, float d, vec2 old_position, vec2 player, vec2 velocity) {
u := mag(player - old_position)
dist := sqrt(u * u - d * d) - s
return player + normalize(velocity) * dist
}


Now the bouncing part. The normal at the intersection of the 2 circles is always equal to the normalized version of the vector between the intersection point and the center of the circle, thus it's also the normalized version of the vector going from the player's position to the ball's new position.

Let's call the normal n and the velocity vector v

Based on this other nice Mathematics answer, you can get the new velocity vector with the following formula:

v2 := v - 2 * dot(v, n) * n


Set the velocity of the player to v2 and done. Now, here's the complete answer in pseudo code (I assume you have a way to set the player's velocity and position, here I use the set_player(vec2 new_pos, vec2 new_velocity) function):

func intersect(vec2 ball_pos, float ball_radius, vec2 ball_velocity, vec2 player_pos, float player_radius) {
d := line_point_dist(ball_pos, ball_pos + ball_velocity, player_pos)
if (d > t) do
# The balls never intersect
return
end
s := sqrt(t * t - d * d)
pos := get_position(s, d, ball_pos, player_pos, ball_velocity)

n := normalize(pos - player_pos)
new_velocity := ball_velocity - 2 * dot(ball_velocity, n) * n

set_player(pos, new_velocity)
}

func line_point_dist(vec2 start, vec2 end, vec2 point) {
l := pow(mag(end - start), 2)
if (l == 0) do
return mag(end - start)
end
t := max(min(1, dot(point - end, end - start) / l))
proj := start + t * (end - start)
return mag(point - proj)
}

func get_position(float s, float d, vec2 old_position, vec2 player, vec2 velocity) {
u := mag(player - old_position)
dist := sqrt(u * u - d * d) - s
return player + normalize(velocity) * dist
}


In addition to madneon's answer, when you've detected a collision with the player, take the result of:

A = P - B


where P and B are position vectors representing the position of the player and the ball, respectively. Multiply the resulting vector A by a static amount (force used) and then apply it as acceleration to the ball. This should give you the physics of the ball rebounding off the players.

Its not very complicated, all you need is to consider 3 things:

1. Ball's position (x, y) and velocity (vx and vy).
2. Constant gravity (g).
3. Bounce conditions.

On every game loop you need to apply gravity, like:

vy += g;


Then apply velocity:

x += vx;
y += vy;


Then check these result for collision with players and/or screen edges and ground.

Depending on your game engine, you might need to "correct" these calculations by multiplying them by your current tick time (eg. vy += g * tick_time), setting proper constant gravity, and setting proper starting/after-bounce velocity (eg. vx and vy depending on player's bounce angle - you might have to use sin/cos functions).

• It doesn't seem complicated because you skipped the most complicated part: How to calculate the new movement vector of the ball after the collision. Commented Feb 11, 2016 at 14:13
• @Philipp That's not complicated either, it just requires some reading on it, see my answer above Commented Jan 25, 2017 at 20:37

The lazy solution: Use an existing 2d physics engine which is able to handle elastic collisions between circles (and circles with rectangles for the net). There is no reason to reinvent the wheel.

• -1 although I agree, this is a poor answer to the question. Mainly because it does not answer the question. (I am sorry for the downvote! I appreciate everything you do for us here!)
– Evorlor
Commented May 15, 2016 at 0:27