GameMaker [Solved]Bouncing off Circle Line

gdkid

Member
Hi guys

I'm having the problem with making a ball bouncing off a circle line

I attached my screenshot so you can get my point.

So the white circle is created using draw_circle

I'd like to make the yellow ball bounce off the circle line, but since it doesn't have a mask, I found it difficult to do so.

Here's the code that I come up so far

I checked the area outside the circle, when the ball collides with this area then it will bounce back

But it doesn't seem to work, since the ball just comes through the circle line.

Code:
if(!collision_circle(room_width/2,room_height/2,global.radius,objBallParent,false,false))
{
    direction += 360-(direction*2)

}
Thanks in advance for your help
 

Attachments

NightFrost

Member
Since both are round, you don't need to do any collision checking. You just measure if the ball has moved over certain distance from the center of the circle, being the circle radius minus the ball radius. Bounce angle can be figured from the angle difference between the ball's current direction and its position's angle as measured from the center of the circle.
 

gdkid

Member
Since both are round, you don't need to do any collision checking. You just measure if the ball has moved over certain distance from the center of the circle, being the circle radius minus the ball radius. Bounce angle can be figured from the angle difference between the ball's current direction and its position's angle as measured from the center of the circle.
Sounds like a good alternative, thanks a lot Nightfrost, will give it a try.
 

gdkid

Member
Hi @NightFrost

Just implement the code as you suggested


Code:
dist = point_distance(ball.x,ball.y,room_width/2,room_height/2);

if (dist >= (global.radius - ball.radius))
{
dir =point_directionball.x,ball.y,room_width/2,room_height/2);
hspeed = 8* cos(dir);
vspeed = 8* -sin(dir);

}
It works, but not perfect, since the ball often "shake" a few times at the collision point (seems a bit weird) before bouncing back and moves

Do you have any suggestion where I can improve the code?
 

NightFrost

Member
It could be that after turning around, the ball is still beyond the rebound distance due to rounding. A fix might be as simple as not testing for a new bounce on a step immediately after a bounce.
 

GMWolf

aka fel666
Bounce angle can be figured from the angle difference between the ball's current direction and its position's angle as measured from the center of the circle.
Angles for bouncing gets complicated fast.

Use vectors!
I would normally recommend the impulse method, but a simple alternative is the penalty method.
It goes something like this:

Get the depth of the collision.
Code:
var d = point_distance(ball.x, ball.y, room_width / 2, room_height / 2) - ball.radius;
If you want to collide with the inside of the circle, the reverse it
Code:
d =global.radius - d;
Now find the collision normal. In our case it's quite simple:
Code:
var nx = (room_width / 2) - ball.x;
var ny = (room_height / 2) - ball.y;
//Normalize
if(nx != 0 && ny != 0)
{
    var nl = sqrt(sqr(nx) + sqr(ny));
    nx /= nl;
    ny /= nl;
}
now we can add a force in that direction proportional to the depth:
Code:
var k = 0.2; //change k to get the response you need.
var fx = nx * d * k;
var fy = ny * d * k;

ball.hspeed += fx;
ball.vspeed += fy;

Hope this helps.
 
Last edited:

gdkid

Member
Thanks @GMWolf

I used the code in the Step event of object but it moves quite crazy (it doesn't bounce off the circle line )

As you suggested, the code is as follow (in Step Event)
Code:
var d = point_distance(ball.x, ball.y, room_width / 2, room_height / 2) - ball.radius;

d =global.radius - d;

var nx = (room_width / 2) - ball.x;
var ny = (room_height / 2) - ball.y;
//Normalize
if(nx != 0 && ny != 0)
{
    var nl = sqrt(sqr(nx) + sqr(ny));
    nx /= nl;
    ny /= nl;
}

var k = 0.2; //change k to get the response you need.
var fx = nx * d * k;
var fy = ny * d * k;

ball.hspeed += fx;
ball.vspeed += fy;
Do we have to check the value of "d" before applying the normalize process and force?
 

GMWolf

aka fel666
Yeah, you will want to check that you are actually colliding with the circle.
So you could check that d > 0 for example.

The code care right out of my head so it could be a little wrong, you might need to tweak it/debug it a little.
 

gdkid

Member
OK, I tweak the code a little bit
Code:
var d = point_distance(ball.x, ball.y, room_width / 2, room_height / 2) ;

if (d >= (global.radius  - ball.radius)) //since the collision is inside the circle
{

var nx = (room_width / 2) - ball.x;
var ny = (room_height / 2) - ball.y;
//Normalize
if(nx != 0 && ny != 0)
{
    var nl = sqrt(sqr(nx) + sqr(ny));
    nx /= nl;
    ny /= nl;
}

var k = 0.2; //change k to get the response you need.
var fx = nx * d * k;
var fy = ny * d * k;

ball.hspeed += fx;
ball.vspeed += fy;
}
Now it works like a charm :D

Thank you so much you guys @GMWolf and @NightFrost
 

GMWolf

aka fel666
Oh, I almost forgot, before you move on, it would be great if you made sure you understand what every line of code is doing.
If you are not sure what some of the code is doing or why, please ask! We would be happy to explain.
 

gdkid

Member
Oh, I almost forgot, before you move on, it would be great if you made sure you understand what every line of code is doing.
If you are not sure what some of the code is doing or why, please ask! We would be happy to explain.
It'd be great, frankly I was so happy it works that I forgot about this, too. :D

Please explain your code, it seems brilliant, but I'm still not sure what it is doing

Starting from here


Code:
var nx = (room_width / 2) - ball.x;

.....
 

GMWolf

aka fel666
You are going to need to ask more specific questions I'm afraid...
Starting from here


Code:
var nx = (room_width / 2) - ball.x;

.....
Here we are getting the difference between the ball position and the circle position.
If we do it for X and y, this gives us the direction between them (as a vector, in terms of X and y). After that we nornalize it (divide by its length) which makes it have a length of one. So nx and ny represent the direction from the ball to the circle. In other words, the direction of the collision, or 'collision normal'.
 

gdkid

Member
@GMWolf :Sorry for being vague

What I meant is, I need the explanation for the whole code starting from "var nx = (room_width / 2) - ball.x" :)

I'll ask questions next to the code (in comment form)

Code:
// So at first we calculate the direction of the collision from the ball to the circle (nx and ny)

var nx = (room_width / 2) - ball.x;
var ny = (room_height / 2) - ball.y;

//Then we normalize it

if(nx != 0 && ny != 0) // Is this step checking if the ball is not in the center of the circle?
{
    var nl = sqrt(sqr(nx) + sqr(ny)); // Correct me, is it a Pythagorean theorem ?
    nx /= nl; // So this step is the normalization, I'm kind of noob about this, why do we divide nx and ny to nl?
    ny /= nl;
}


var k = 0.2;
var fx = nx * d * k; //This one is brilliant, but I don't know about this formula, what dpes "k" stand for?
var fy = ny * d * k;

ball.hspeed += fx;
ball.vspeed += fy;
}
 

GMWolf

aka fel666
So yes, we are in essence calculating the distance to the ball along the X, and the Y axis separately.
(nx, ny) is a vector that represents the direction and distance from the ball to the circle. A vector is a direction and distance, but represented and the distance along X axis, and distance along Y axis.

Yes, that is the Pythagorean theorem! Exactly right! We use it the get the actual distance from ball to circle.

By dividing (nx, ny) by its length, we get a new vector with a length of 1. (x/x ==1 right? Here it's the same but we do it along X and y separately).
Making a vector have a length of one means it now only represents the direction, and we loose the length component of the vector. This is called normalizing. We do that because we care about the direction to apply the force in. The actual distance between the ball and circle doesn't matter.

That last equation is similar to the spring equation, or hooks law.
Basically we apply a force in the direction (nx, ny) proposal to how 'deep' the collision is.
K is a constant used to change how 'hard' the spring is. A value of 1 would represent a perfectly stuff collision. But in practice this ends up quite unstable, so we use a smaller value instead.

This is called the penalty method for collision response. You should find a lot of info about it online.
If you are interested in learning more, look at the impulse method. That is what games tend to use most often.

I would also recommend you learn vectors. Very useful tools in games programming.


[Edit]
The check we do is to check that the distance isn't 0. That is because dividing by 0 is not allowed.
 
Last edited:

gdkid

Member
Hi @GMWolf

Is it possible if I add some random to the force applied to hx (or hy) ? Since the balls keep moving in the same direction back and forth through the center

var fx = nx * d * k * random_range(1.5,2.5);
 

GMWolf

aka fel666
Hi @GMWolf

Is it possible if I add some random to the force applied to hx (or hy) ? Since the balls keep moving in the same direction back and forth through the center

var fx = nx * d * k * random_range(1.5,2.5);
Yeah sure. The code you posted should do the trick. Though the values are a little high.
If you don't want the ball to speed up, you could add the random values to nx and ny before they are normalized
 
Top