Python & Pygame: Ball collision with interior of circle

前端 未结 3 540
时光取名叫无心
时光取名叫无心 2021-01-18 04:16

I\'m making a game in which balls bounce around the inside of a much larger circle. The larger circle doesn\'t move.

Here\'s the code that I\'m currently us

相关标签:
3条回答
  • 2021-01-18 04:21

    Without answering your question, I'd like to comment on your implementation strategy and recommend a new approach. You represent the velocity of the ball in polar coordinate form, as ball.angle and ball.speed.

    I think that this is going to be generally inconvenient for you. For example, in your collision code you end up calling atan2 to turn the vector (dx, dy) into an angle, and then you call sin and cos to turn the angle back into a vector again. (Also, should you ever try to generalize your code to three dimensions, you will find yourself in a world of pain.) So, unless you have particular requirements that necessitate polar coordinates, I recommend that you do what everyone else does, namely represent the velocity of the ball in Cartesian coordinates as the vector (vx, vy).

    I also recommend changing your physics approach from a static one ("is object A currently colliding with object B?") to a dynamic one ("will object A collide with object B during its next movement step?"). In a static physics system you often end up with objects intersecting each other at the end of a movement step, and then you have to figure out the best way to get them to separate again, which is hard to get right.

    If you do both of these, it is straightforward to bounce the ball without any trigonometry.

    Step 1. Transform circle/circle collision into point/circle collision using Minkowski addition:

    Original problem at left shows small circle moving inside a large circle. Transformed problem at right shows point moving in circle whose radius is the difference between the radii of the circles in the original problem.

    Step 2. Consider a time segment in which the ball starts at p = (px,py) and moves by v = (vx,vy). Does it intersect with the circle? You can use a standard line segment/circle test for this except that the sense of the test is reversed.

    Step 3. Find the point of collision c = (cx,cy). The ball bounces off the circle in the same way as it would bounce off the line t tangent to the circle at this point. For a circle centred at the origin, the tangent vector is just (−cy,cx) and I'm sure you can work out how to compute it for other circles.

    Figure described above

    See this answer for how to calculate the new path of the ball based on coefficients of friction and restitution.

    Step 4. Don't forget that the ball may still have some distance to move along the new vector w. If the time step is large enough or the velocity high enough it may collide again during the same time segment.

    0 讨论(0)
  • 2021-01-18 04:34

    I'm glad you liked my tutorial. I like your variation, it should actually be simpler.

    First, I think you need change the test for collision to:

    if distance >= circle.size - ball.size:
    

    Because the larger the ball size, the smaller the distance between its centre and the centre of the circle can be. This should make the balls bounce at the right place (inside the circle).

    Then I think you just need to swap the signs for the x and y and everything should work.

    ball.x += math.sin(angle)
    ball.y -= math.cos(angle)
    

    To move the ball by the correct distance you can calculate the overlap:

    overlap = math.hypot(dx, dy) - (circle.size - ball.size)
    
    if overlap >= 0:
      tangent = math.atan2(dy, dx)
      ball.angle = 2 * tangent - ball.angle
      ball.speed *= elasticity
    
      angle = 0.5 * math.pi + tangent
      ball.x += math.sin(angle)*overlap
      ball.y -= math.cos(angle)*overlap
    

    Good luck

    0 讨论(0)
  • 2021-01-18 04:43

    Most graphics packages use upper-left as start for drawing code. You most likely want 2 sets of coordinates, the one's you collide/move/etc with and the one's for drawing (x-radius, y-radius).

    Also, without having thought about it too much, should the check for intersection be distance + ball.size >= circle.size? The balls distance from the center plus its radius should be less than the circle's radius, if I understood the setup correctly.

    0 讨论(0)
提交回复
热议问题