Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace HC with either bump or manually written collision detection system. #3

Open
noooway opened this issue Dec 18, 2016 · 7 comments

Comments

@noooway
Copy link
Owner

noooway commented Dec 18, 2016

No description provided.

@Giseudo
Copy link

Giseudo commented Jan 14, 2017

When using HC to rebound the ball, sometimes (when frame rate drops) the ball can ignore wall collision response, causing some weird behaviors… like losing the ball. I've noticed you're updating the Wiki with new content (such as using LÖVE's default physics).

Since love already has its own game loop function (update), do we need also to calculate the fixed timestep for updating the resolve_collisions? Or by using LÖVE's physics this problem should be already fixed?

@noooway
Copy link
Owner Author

noooway commented Jan 14, 2017

When using HC to rebound the ball, sometimes (when frame rate drops) the ball can ignore wall collision response, causing some weird behaviors… like losing the ball.

Yes, this is also one of the reasons I want to replace HC with something different.

The problem is following: during the update cycle, I update the positions of the game objects
and after that check for overlaps between them. For the ball I calculate

function Ball:update( dt )
   self.position = self.position + self.speed * dt
   .....
end

If the product self.speed * dt becomes large, the ball can cover large enough distance to
get through other objects (such as walls), without causing a collision.
This can happen in two cases. The first one is when the dt is large.
I believe, this is what happens when the frame rate drops.
It is possible to remedy this by setting minimal value for dt in love.update and love.draw, i.e.
do something like

function love.update( dt )
   local min_dt = 0.01 
   if (  dt > min_dt ) then 
      dt = min_dt
   end                                                                    
   ball:update( dt )                                                                            
   platform:update( dt )                                                                        
   .....                                                    
end              

I believe, that way the collisions on low framerate should be resolved correctly.

However, the bug also can happen when the speed of the ball becomes high enough.
It is possible to test it by inserting the following function in the main.lua.

function love.keyreleased( key, code )
   if key == 'up' then
      ball.speed = ball.speed + 100 * ball.speed:normalized()
      print( "current ball speed: ", ball.speed )
   end
end

On my machine, the ball passes through the walls somewhere around current ball speed: (-1431.3708498985,-1431.3708498985). Unfortunately, I can't think of any modifications to dt, that can solve this problem.

The correct solution requires to implement a more complicated collision detection algorithm, e.g. continuous collision detection.

The simple collision detection algorithm I describe in parts 1-3 and 1-4 is also susceptible
to this bug. But I do plan to improve it and switch to CCD in later chapters. Probably, I'll
use Bump library, which implements it.

Hope, this answers your question.

Regarding the simple code for collisions I use in parts 1-3, 1-4, I would prefer to avoid the term "LÖVE's default physics" because it can be confused with love.physics module, which I don't use. This module handles both collision detection and collision resolution, but does it in physically realistic way. This requires to deal with a lot of additional parameters. It can be a great choice for more advanced games, but definitely not necessary for such a simple one that I describe.

@Giseudo
Copy link

Giseudo commented Jan 14, 2017

Yeah, now that I've finished replacing HC library, I can see that indeed we're not using the love.physics module, instead doing the detection and resolving by ourselves.

Thank you for the detailed answer…
Keep up the great work!

@saramont
Copy link

saramont commented Aug 25, 2017

Hi! I am now following this tutorial (great job by the way!) and I encountered the same problem: when the speed of the ball increases the ball sometimes goes beyond the walls.
I think that this problem happens in 4 cases:

  1. The ball collides against the left wall but the ball's x coordinate is greater than the wall's center x
    coordinate, in this case the ball_shift_x is positive instead of negative and so the ball_position_x
    increases and the ball exits the screen.

  2. The ball collides against the right wall and the ball's x coordinate is lesser than the wall's center x
    coordinate.

  3. The ball collides against the top wall and the ball's y coordinate is lesser than the wall's center y
    coordinate.

  4. The ball collides against the bottom wall and the ball's y coordinate is greater than the wall's center y
    coordinate.

In all this cases the shift sign is not the one that it should be in order for the ball to bounce on the wall.

I managed to solve this issue manually with this function:

function ball.bad_position()
  if ball.x >= love.graphics.getWidth() - walls.wall_thickness then   
    ball.x = love.graphics.getWidth() - walls.wall_thickness - 1
  elseif ball.x <= walls.wall_thickness then  
    ball.x = walls.wall_thickness + 1
  end
  
  if ball.y <= walls.wall_thickness then 
    ball.y = walls.wall_thickness + 1
  elseif ball.y >= love.graphics.getHeight() - walls.wall_thickness then   
    ball.y = love.graphics.getHeight() - walls.wall_thickness - 1
  end
end

The function is called at the start of the collisions.resolve_collisions function so if the ball is bad positioned it is positioned again in a way that it can bounce on the wall.

At least for me this is working, but I just started learning lua and LOVE and I'm not a programmer so I'm not really an expert or anything, I just hope this is somehow useful.
(I'm not english so I apologize for any grammar mistakes, I tried to be as clear as possible)

@noooway
Copy link
Owner Author

noooway commented Aug 28, 2017

when the speed of the ball increases the ball sometimes goes beyond the walls.

Yes, the current collision detection algorithm doesn't work correctly for objects moving at high speed. It seems to me, the problem is not limited to ball-walls collisions but also concerns ball-platform and ball-blocks collisions. That is, at high enough speed the ball can pass not only through walls, but also through platform and blocks.

I managed to solve this issue manually with this function:

While the solution you propose allows to keep the ball inside the game area, it seems it won't handle ball-blocks and ball-platform collisions correctly.

One way to deal with this problem for all types of collisions is to determine whether or not a path the ball covers during a single update cycle intersects any other objects.

I believe, this can be implemented in the following way.
Position of the ball at the beginning of the update cycle is known.
A new position the ball should be placed at if there are no collisions can be computed in the ball.update:

function ball.update( dt )
   ball.possible_position_x = ball.position_x + ball.speed_x * dt
   ball.possible_position_y = ball.position_y + ball.speed_y * dt   
end

Before actually placing the ball into this possible new position

function ball.move_to_possible_position()
   ball.position_x = ball.possible_position_x
   ball.position_y = ball.possible_position_y
end

it is first necessary to check for intersections of the line segment between the old and new positions and any other game objects.

This can be done in the functions responsible for collisions between various objects

-- (this is a pseudocode, not an actual code).
function collisions.ball_platform_collision( ball, platform )
   local intersects = collisions.check_trajectory_intersections( platform, ball )
   if intersects then
      ball.resolve_intersection( platform )
   end
end

In the collisions.check_trajectory_intersections both old and possible new ball positions are used (ball.position_x and ball.possible_position_x).

I believe such method should work, but I'm not sure about details. I'll try to implement it and if there is any noticeable improvement I'll include it as an appendix.

@saramont
Copy link

saramont commented Aug 28, 2017

I noticed the problem only with the ball-walls collision so I tried to solve only that.
Thank you for your detailed replay!
Are you also going to write the appendices about classes implementation ? I would be very interested in them.

@noooway
Copy link
Owner Author

noooway commented Aug 28, 2017

Are you also going to write the appendices about classes implementation ? I would be very interested in them.

Yes, I have been thinking to write a couple of appendices illustrating a typical implementation of classes in Lua and how to use them to represent game objects. Lua is a bit different from other programming languages in it's approach to classes and it has taken me quite some time to understand how it works.

Actually, in the initial version of this tutorial classes have been introduced early on.
This version is still available in the Archive section; classes are discussed in the third part.

While I have been thinking to illustrate classes implementation, I don't think I'm going to discuss usual OOP design issues (inheritance, etc).

In any case, regarding the classes and OOP, I would suggest to consult Programming in Lua (the first edition is available online ), numerous tutorials on Lua-users wiki or, probably, this more recent introductory article.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants