2

Currently i am working on bouncing a ball of a wall, in classic 2D-geometry.

The wall can be hit on both vertical and horizontal sides, and the result of the reflection depends on which side the ball hits.

I have tried some different solutions, but they just make me more confused.

How can i determine whether the ball is hitting a vertical or horizontal side of the wall?

PseudoCode for the overview:

iterate through each wall
if (collision between ball and wall)
  determine if vertical/horizontal hit
  calculate new velocity for ball

I use this code for collision detection and it works like a charm: source: Circle-Rectangle collision detection (intersection)

var isCollision = function (_projectile) {
    if(direction != undefined){
        var circleDistance = {};
        circleDistance.x = Math.abs(_projectile.getCenter().x - centerX);
        circleDistance.y = Math.abs(_projectile.getCenter().y - centerY);

        if (circleDistance.x > (width/2 + _projectile.getRadius())) { return false; }
        if (circleDistance.y > (height/2 + _projectile.getRadius())) { return false; }

        if (circleDistance.x <= (width/2)) { return true; }
        if (circleDistance.y <= (height/2)) { return true; }

        var cornerDistance_sq = square(circleDistance.x - width/2) + square(circleDistance.y - height/2);

        return (cornerDistance_sq <= (square(_projectile.getRadius())));
    }
    return false;
};

var square = function(_value){
    return _value * _value;
};

Thank you!

Community
  • 1
  • 1
ChristopherMortensen
  • 1,093
  • 2
  • 8
  • 10
  • 1
    I think playing with some basic match of x and y positioning will tell you which wall the ball is hitting. However, please show some code that shows your effort on the technical side of things. – Software Guy May 12 '15 at 22:11

2 Answers2

3

update after question update

Asuming the ball has a direction/velocity vector dx,dy and has a radius of r (ball.x, ball.y are the ball positions of the ball center) do sth like this (have used similar in a billiard game, it is basic geometry and physics):

if (ball.x+ball.dx+r > wallV.x) ball.dx = -ball.dx // ball bounces off the 
vertical wall

if ( ball.y+ball.dy+r > wallH.y ) ball.dy = -ball.dy // ball bounces off horizontal wall

do similar for opposite walls if needed, since velocity vector changes, the new ball position after bouncing (or anyway) will be ball.x += ball.dx; ball.y += ball.dy;

enter image description here

Bonus if you add some friction factor (meaning the magnitudes of dx dy eventually fade away to zero, the ball eventually stops after following a path)

Nikos M.
  • 8,033
  • 4
  • 36
  • 43
  • Thank you for your answer. I will implement this solution and see the result. Cheers. – ChristopherMortensen May 12 '15 at 22:39
  • I just got a question: "wallV" and "wallH" in your example, are they different "wall-objects"? - Because i only work with identical square-walls. Or am i misunderstanding something in your code? – ChristopherMortensen May 12 '15 at 22:52
  • each wall will be located in different positions and orientations so a vertical wall (lets say `wallV`) will have certain `x,y` coordinates and a horizontal wall (lets say `wallH`) will have different and the test will have to know the positions of the walls to determine if ball bounces off there – Nikos M. May 12 '15 at 22:55
  • each `wallV`, `wallH` etc can be instances of same object or class they just differ on their coordinates and orientations – Nikos M. May 12 '15 at 22:55
2

To solve properly a collision, you can't just test on X => if collision solve and return THEN test on y => if collision solve on y.
You have to check which axe (x OR y) collides first, and there's also the case when the ball hits two walls at the same time.
So you can't just reason with space : you have to deal with time, and compute an ETA -Estimated Time Arrival- for all walls, based on the ball speed (assuming walls are still).

pseudo code :

minETA = a too big number;
colliderList = [];
for (each wall in walls) {
   thisWallETA = computeETA(ball, wall);
   if (thisWallETA > minETA) continue;
   if (thisWallETA < minETA) {
      minETA = thisWallETA;
      colliderList.length = 0;
      colliderList.push(wall);
      continue;
   } 
   if (thisWallETA == minETA) {
      colliderList.push(wall);
      continue;          
   }
}

Then when the colliderList has only one item => solve on corresponding axe. If it has two items => solve on both axes.
Then increase the current time by minETA, and try again until the currentTime + minETA you found is > to thisCycleTime + thisCycleDt.

If you're interested, i might clarify some things up.

Good luck !

GameAlchemist
  • 18,995
  • 7
  • 36
  • 59