Calculate arbitrary deflection angles

I would like to change the angle of deflection of the ball every time it hits the wall.

It will vary depending on how close it is to the middle of the wall ...

Right now, I hardcode the changes in X and Y when it hits the surface ... My goal is to get degrees from the current X and Y, apply the changes to degrees (right now I add a random number to degrees), then calculate the new increment values for X and Y. I know how to get newX and newY, but not how to get incremental values.

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

enter image description here

  • So, I calculated that the degrees would be 45 based on this.
  • Then we added a random number to 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, say 55 degrees, * distX

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

And the sin of my corner * 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 this does not mean that my new increasing value of x and y should be based on my angle in frequency.

Code snippet: You can see that I hardcode the increments x,y ( 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; } 
+4
source share
3 answers

This is a rather interesting problem because of its specificity.

Making a ball bounce in a programming language is easy. Like this example .

But it’s clear that your question is not “making it work”; you need explicit control over the coordinates and angles so that you can change them for whatever purpose you had in mind.

Since I'm pretty vulnerable to nerd sniping , I cleaned up my geometric skills and came up with the following snippet of pseudocode (I did this from scratch to make sure I have full control):

Intuition

enter image description here

enter image description here

pseudo code

  theta = starting angle a = current x-coordinate of ball b = current y-coordinate of ball quadrant = quadrant-direction to which ball is moving /> Determine number between 1 and 360: theta /> Calculate quadrant .> 0-90 : quadrant 1: horizontal: 90-a vertical: b alpha: 90 - theta .> 90-180: quadrant 4: horizontal: 90-a vertical: 30-b alpha: theta - 90 .> 180-270: quadrant 3: horizontal: a vertical: 30-b alpha: 270 - theta .> 270-360: quadrant 2: horizontal: a vertical: b alpha: theta - 270 /> Calculate distance to side | /> Calculate distance to top/bottom | .> to side: n(alpha) = horizontal/cos(alpha) .> to top/bottom: m(alpha) = vertical /sin(alpha) /> Determine where ball is going to hit (n = side, m = top/bottom) .> n >= m : bounces at top/bottom .> m >= n : bounces at side .> switch (quadrant) .> 1 : n = right side m = top .> 2 : n = left side m = top .> 3 : n = left side m = bottom .> 4 : n = right side m = bottom /> Calculate coordinates of hit /> Define new angle // Normally, angle of impact = angle of reflection // Let define the angle of impact with respect to the origin (0,0) .> switch (quadrant) .> 1 : .> n >= m (at top/bottom) : x = a + vertical*tan(alpha) y = 0 theta = 180-theta .> m >= n (at side) : x = 90 y = b - horizontal*tan(alpha) theta = 270+alpha .> 2 : .> n >= m (at top/bottom) : x = a - vertical/tan(alpha) y = 0 theta = 270-alpha .> m >= n (at side) : x = 0 y = b - horizontal*tan(alpha) theta = 90-alpha .> 3 : .> n >= m (at top/bottom) : x = a - vertical/tan(alpha) y = 30 theta = 270+alpha .> m >= n (at side) : x = 0 y = b + horizontal*tan(alpha) theta = 90+alpha .> 4 : .> n >= m (at top/bottom) : x = a + vertical/tan(alpha) y = 30 theta = 90-alpha .> m >= n (at side) : x = 90 y = b + horizontal*tan(alpha) theta = 270-alpha /> Define new coordinates (for reusage of function) .> a = x .> b = y .> (optional) if you would like the angles to differ, enter extra term here: .> extra = ... .> theta = theta + extra 

Implementing this code will allow you to work with ease of degrees and still be able to determine the coordinates.

It works as follows:

  • First determine the initial position of the ball (a, b) and its initial direction (theta)

  • Now the program will calculate:

    • If the ball hits the target
    • What are the coordinates of the ball on impact
    • What is the new angle of reflection (this is the part you want to change).

And then it starts again to calculate a new hit.

In JavaScript, the code would look like this:

code

 var width = 500; var height = 200; var extra = 0; var a; var b; var x; var y; var angle; var n; var m; var quadrant; var horizontal; var vertical; var alpha; var side; var topbottom; var sides; var i = 1; var txt=document.getElementById("info"); txt.innerHTML="x: "+a+"<br>y: "+b+"<br>angle: "+angle+"<br>quadrant: "+quadrant; function buttonClick() { if (i == 1) { a = 75; b = 75; //determine first angle randonmly angle = Math.floor((Math.random()*360)+1);; } else { a = xcoord(); b = ycoord(); } var oldAngle = angle; angle = findNewCoordinate(a, b, angle); sides = hitWhere(); var txt=document.getElementById("info"); txt.innerHTML="x: "+a+"<br>y: "+b+"<br>horizontal: "+horizontal+"<br>vertical: "+vertical+"<br>n: "+n+"<br>m: "+m+"<br>angle: "+oldAngle+"<br>alpha: "+alpha+"<br>quadrant: "+quadrant+"<br>side: "+topbottom+side+"<br>"+sides+"<br>"+i; i++; } function findNewCoordinate(a, b, angle) { if (angle >= 0 && angle < 90) { quadrant = 1; horizontal = width-a; vertical = b; alpha = (90 - angle); } else if (angle >= 90 && angle < 180) { quadrant = 4; horizontal = width-a; vertical = height-b; alpha = (angle-90); } else if (angle >= 180 && angle < 270) { quadrant = 3; horizontal = a; vertical = height-b; alpha = (270-angle); } else if (angle >= 270 && angle <= 360) { quadrant = 2; horizontal = a; vertical = b; alpha = (angle-270); } var cosa = Math.cos(alpha * Math.PI / 180); var sina = Math.sin(alpha * Math.PI / 180); var tana = Math.tan(alpha * Math.PI / 180); var tant = Math.tan(angle * Math.PI / 180); n = horizontal/cosa; m = vertical/sina; switch (quadrant) { case 1: if (m >= n) //hit at side { y = b - horizontal*tana; x = width; angle = 270+alpha; } else { y = 0; x = a + vertical*tant; angle = 180-angle; } side = "right side"; topbottom = "top"; break; case 2: if (m >= n) //hit at side { y = b-horizontal*tana; x = 0; angle = 90-alpha; } else { y = 0; x = a - vertical/tana; angle = 270-alpha; } side = "left side"; topbottom = "top"; break; case 3: side = "left side"; topbottom = "bottom"; if (m >= n) //hit at side { x = 0; y = b + tana*horizontal; angle = 90+alpha; } else { y = height; x = a - vertical/tana; angle = 270+alpha; } break; case 4: side = "right side"; topbottom = "bottom"; if (m >= n) //hit at side { y = b+horizontal*tana; x = width; angle = 270-alpha; } else { y = height; x = a + vertical/tana; angle = 90-alpha; } break; } //add extra degrees to the angle (optional) angle += extra; context.beginPath(); context.arc(a, b, 5, 0, Math.PI*2, true); context.stroke(); context.closePath(); context.fill(); drawLine(a,b,x,y); return angle; } 

Attention!

Please note that there are many more ways to make a bounce program. But, since I solved the problem geometrically and without "shortcuts" , the unique characteristics of my program make it very easy for you to change your wishes:

  • You can give an extra angle at a bounce angle (use var extra ).
  • You can change the movement of the ball at any time (during a rebound, after a rebound, etc.).
  • You have explicit access to the coordinates of the ball
  • All devices are ordinary (in degrees and coordinates, so they are easy to understand and intuitive).

Also note that I did not make the program very concise, because that is simply not my goal. I wanted to create a program for a bouncing ball, which, although long, is an accurate realization of geometric intuition behind it.

Demo

You can find a demo of my program in this JSFiddle . Please note that the starting angle is determined randomly. Therefore, restarting the program will give a different angle.

enter image description here

Well, what about that.

Good luck building the rest of your program!

+5
source

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 that we have to do two things:

  • Apply the Pythagorean theorem to find the distance to new coordinates
  • Calculate the "new" speed

Before applying the Pythagorean theorem, we must know the direction of motion:

enter image description here

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

pseudo code

 //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 notice that x and y represent the coordinates of the moving ball. This means that in order to reach the new coordinate, we must repeat x += .. and y += .. value of time times.

Therefore, 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 = ? not yet indicated by you. You can let it have a constant speed (friction = 0), or you can implement some kind of model to simulate friction.

Hope this answers your question.

PS. This answer is actually derived from my other answer, as I already indicate the direction and distance between the pixels in my other answer, so the step on x += .. and y += .. is actually quite small / straightforward.

+1
source

depends on the angle at which he entered. So basically in order for the ball to bounce off the wall, simply invert the angle into which it entered, for example. if you use speed, if it is 3, then make it -3 when it collides with the wall, so the ball bounces off the wall at the same angle as before it collided with the wall ...

Hope this helps ... Good luck.

0
source

Source: https://habr.com/ru/post/1493759/


All Articles