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
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.
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?
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.
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.
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?
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.
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 Thank you so much you guys @GMWolf and @NightFrost
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. 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; .....
You are going to need to ask more specific questions I'm afraid... 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'.
@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; }
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.
Now I got it Thanks @GMWolf for your detailed explanation. Will definitely take a look into vectors, sounds like a lot of fun.
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