GMS 2 [Solved]Bouncing off Circle Line

Discussion in 'Programming' started by gdkid, Jul 7, 2019.

  1. gdkid

    gdkid Member

    Joined:
    Sep 22, 2016
    Posts:
    32
    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
     

    Attached Files:

  2. NightFrost

    NightFrost Member

    Joined:
    Jun 24, 2016
    Posts:
    1,785
    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 likes this.
  3. gdkid

    gdkid Member

    Joined:
    Sep 22, 2016
    Posts:
    32
    Sounds like a good alternative, thanks a lot Nightfrost, will give it a try.
     
  4. gdkid

    gdkid Member

    Joined:
    Sep 22, 2016
    Posts:
    32
    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?
     
  5. NightFrost

    NightFrost Member

    Joined:
    Jun 24, 2016
    Posts:
    1,785
    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.
     
  6. gdkid

    gdkid Member

    Joined:
    Sep 22, 2016
    Posts:
    32
    So should we use the Alarm to check this, like every 2-3 steps?
     
  7. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,315
    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: Jul 9, 2019
    gdkid likes this.
  8. gdkid

    gdkid Member

    Joined:
    Sep 22, 2016
    Posts:
    32
    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?
     
  9. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,315
    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.
     
  10. gdkid

    gdkid Member

    Joined:
    Sep 22, 2016
    Posts:
    32
    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 likes this.
  11. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,315
    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.
     
  12. gdkid

    gdkid Member

    Joined:
    Sep 22, 2016
    Posts:
    32
    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;
    
    .....
     
  13. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,315
    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'.
     
  14. gdkid

    gdkid Member

    Joined:
    Sep 22, 2016
    Posts:
    32
    @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;
    }
     
  15. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,315
    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: Jul 12, 2019 at 11:21 AM
    gdkid likes this.
  16. gdkid

    gdkid Member

    Joined:
    Sep 22, 2016
    Posts:
    32
    Now I got it :D

    Thanks @GMWolf for your detailed explanation.

    Will definitely take a look into vectors, sounds like a lot of fun.
     
  17. gdkid

    gdkid Member

    Joined:
    Sep 22, 2016
    Posts:
    32
    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);
     
  18. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,315
    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
     
  19. gdkid

    gdkid Member

    Joined:
    Sep 22, 2016
    Posts:
    32

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice