Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate random bounce angles

I'd like to make a ball bounce angle change each time it hits a wall.

It will change based on how near the middle of the wall it hits...

Right now, I'm hard coding the change in X and Y when it hits a surface... My goal is to get the degrees from current X and Y, apply a change to the degrees (Right now I'm add a random number to the degrees), then calculate the new incrementing values for X and Y. I know how to get the newX and newY, but not how to get the incrementing values.

The green is the starting x y of (5,5)... the blue is the next frame of (4,4).

enter image description here

  • So I calculated the degrees to be 45 based on that.
  • Then added a random number to the degrees.
  • Then, I want to get the new x and y coordinates. So I followed this method...

currX (5) - wallX (0) = distX (5)

currY (5) - wallY (0) = distY (5)

Take the cosine of my angle + random increment, we'll say 55 degrees, * distX

cos(55 degrees) = .5735... .5735 x distX (5) = 2.86

And sin of my angle * distY

sin(55 degrees) = .8191... .8191 x distY (5) = 4.09

newX = cos result (2.86) + originX (5) = 7.86

newY = sin result (4.09) + originY (5) = 9.09

newX, newY = (7.86, 9.09)

Okay... so I have my new coordinates...

But those don't equate to what my new incrementing value of x and y should be based on my angle in incidence.

Code snippet: You can see that I'm hard coding the x,y increments (dragger.x += 2; )

        function tick() {
            var rand = Math.floor((Math.random()*10)+1);

            console.log("ticking..." + rand);
            if (dragger.x >= 400-20) {
                dragger.xDir = "right";         
            }
            if (dragger.x < 20) {
                dragger.xDir = "left";      
            }       
            if (dragger.y >= 150-20) {
                dragger.yDir = "up";
            }
            if (dragger.y < 20) {
                dragger.yDir = "down";
            }

            var oldX = dragger.y;
            var oldY = dragger.x;

            if (dragger.xDir == "left") {
                dragger.x += 2; 
            }
            else {
                dragger.x -= 2;
            }
            if (dragger.yDir == "up") {
                dragger.y -= 2;
            }
            else {
                dragger.y += 2;
            }
            //post update...
            var newX = dragger.y;
            var newY = dragger.x;                   

            var angle = getAngle(newX, oldX, newY, oldY)
            angle+=rand;

            $('#getAngle').empty();
            $('#getAngle').append("bounce angle (degrees): " + angle);


            //console.log(xDir);
            // update the stage:
            stage.update();
        }

        function getAngle(x2, x1, y2, y1) {             
            var deltaX = Math.abs(x2-x1);
            var deltaY = Math.abs(y2-y1);
            var radians = Math.atan2(deltaX, deltaY);
            var degrees = radians * (180/Math.PI);
            return degrees;
        }
like image 856
user3871 Avatar asked Mar 23 '23 00:03

user3871


1 Answers

We know that

distance = average velocity x time //if acceleration is constant

Hence

time = distance / average velocity

Applying this knowledge to a two dimensional field (distance) means we have to do two things:

  • Apply Pythagoras theorem to find distance to new coordinates
  • Calculate the 'new' velocity

Before we apply the Pythagoras theorem, we have to know the direction of the move:

enter image description here

Now to find the distance to the new coordinates, we apply pythagoras theorem:

Pseudocode

//Change in coordinates
dx = Math.abs(newX - oldX);
dy = Math.abs(newY - oldY);

//Distance to travel
distance = Math.sqrt( Math.pow(dx, 2) + Math.pow(dy,2) );

//Units per increase
// time = distance / average velocity

velocity = ?;
time = distance / velocity;

//Now to find x+= .. and y+= .. we apply our knowledge of direction
//Together with our knowledge of the time it takes

case north east:        x += (dx / time);           y += (dy / time);

case south east:        x += (dx / time);           y -= (dy / time);

case north west:        x -= (dx / time);           y -= (dy / time);

case south west:        x -= (dx / time);           y += (dy / time);

Now note that the x and y represent the coordinates of the moving ball. This means that we must repeat x += .. and y += .. value of time times to reach the new coordinate.

Hence you can do something like:

for (int i = 0; i < time; i ++)
{
    switch (direction)
    {
           case "north east":  x += (dx / time);  y += (dy / time); break;

           case "south east":  x += (dx / time);  y -= (dy / time); break;

           case "north west":  x -= (dx / time);  y -= (dy / time); break;

           case "south west":  x -= (dx / time);  y += (dy / time); break;
    }
}

Also note that velocity = ? is yet to be specified by you. You can let it have a constant velocity (friction = 0), or you can implement some kind of model to mimick friction.

I hope this answers your question.

PS. This answer is actually a derivative of my other answer as I already specify direction and pixel distance in my other answer hence the step to x += .. and y += .. is actually pretty small/ straightforward.

like image 96
Jean-Paul Avatar answered Mar 31 '23 15:03

Jean-Paul