计算随机反弹角度

Gro*_*ler 4 javascript angle

我想每次撞到墙壁时都会改变球的弹跳角度.

它将根据它击中墙壁中间的距离而发生变化......

现在,当我遇到表面时,我很难对X和Y的变化进行编码......我的目标是从当前的X和Y获得度数,对度数应用一个变化(现在我随机添加一个数字到度),然后计算X和Y的新增量值.我知道如何获得newX和newY,但不知道如何获得增量值.

绿色是开始x y(5,5)......蓝色是下一帧(4,4).

在此输入图像描述

  • 所以我计算了45基于此的度数.
  • 然后在度数中添加一个随机数.
  • 然后,我想得到新的x和y坐标.所以我按照这种方法 ......

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

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

取我的角度的余弦+随机增量,我们会说55度,*distX

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

和我的角度的罪恶*distiy

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)

好的......所以我有了新的坐标......

但那些并不等于我的新增量值,xy应该基于我的发病率角度.

代码片段:你可以看到我很难对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;
        }
Run Code Online (Sandbox Code Playgroud)

Jea*_*aul 5

由于它的特异性,这是一个非常有趣的问题.

用编程语言弹球可以很容易地完成.像这个例子.

但显然,你的问题不是"让它发挥作用"; 你想要明确控制坐标和角度,以便你可以根据自己的想法改变它们.

因为我非常容易受到书呆子狙击,所以我摒弃了几何技能并想出了下面的伪代码(我从头开始做这个以确保我完全控制):

直觉

在此输入图像描述

在此输入图像描述

伪代码

 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's 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
Run Code Online (Sandbox Code Playgroud)

实现此代码将允许您使用度数的简单性并仍然能够确定坐标.

它的工作原理如下:

  • 首先确定球的初始位置(a,b)和它的初始方向(theta)

  • 现在该程序将计算:

    • 球将要击中的地方
    • 撞击球的坐标是什么
    • 新的反射角度是什么(这是你要改变的部分)

然后它重新开始计算新的命中.

在JavaScript中,代码如下所示:

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;
}
Run Code Online (Sandbox Code Playgroud)

重要

请注意,还有很多方法可以制作弹跳程序.但是,因为我在几何上解决了这个问题而没有"快捷方式",所以我的程序的独特特性使你可以很容易地将它改变为你的喜好:

  • 您可以轻松地为弹跳角度提供额外的角度(使用var extra).
  • 你可以随时改变球的运动(弹跳后,弹跳后等)
  • 您可以明确访问球的坐标
  • 所有单位都是传统的(以度和坐标为单位;因此易于理解和直观).

另请注意,我没有使程序非常简洁,因为这根本不是我的目标.我想创造一个弹跳球程序,尽管它是长度的,但却完全体现了它背后的几何直觉.

演示

你可以在这个JSFiddle中找到我的程序的演示.请注意,起始角度是随机确定的.因此重新启动程序将给出不同的角度.

在此输入图像描述

嗯,就是这样.

祝你好好构建其余的程序!