为什么我的一些角度在改变时是不正确的?

时间:2015-06-11 17:57:37

标签: javascript dom canvas angle

我用JavaScript和DOM编写了一个程序,它显示了一个弹跳在一个盒子里的球;它是一个画布元素。唯一不能正常工作的是角度。直到角度很小,当球体没有正确地从盒子中弹回时,这是不明显的。角度可以逐渐进入盒子,然后非常陡峭地反弹回来。这似乎可能不是角度输入=角度输出,而是从输出角度开始的角度。这相当于一个角度和它的赞美。问题似乎只发生在一半的反弹类型:它可能不会发生在一个方向的墙上,而是会发生在另一个方向的墙上。

Illustration of possible problemhttp://i.stack.imgur.com/WviEd.gif

我已经发布了代码测试能力的所有代码,并且使用了渐变角度,因此可以看到问题,但问题的角度在checkAngle函数中。 / p>

<!doctype html>
<script src="code/chapter/15_game.js"></script>
<script src="code/game_levels.js"></script>
<script src="code/chapter/16_canvas.js"></script>

<canvas width="400" height="400"></canvas>
<script>
  var cx = document.querySelector("canvas").getContext("2d");

  var lastTime = null;
  function frame(time) {
    if (lastTime != null)
      updateAnimation(Math.min(100, time - lastTime) / 1000);
    lastTime = time;
    requestAnimationFrame(frame);
  }
  requestAnimationFrame(frame);
  var x = y = 200//, angle = 2 * Math.PI * Math.random();
  var angle = 2 * Math.PI / 40 + Math.PI;
  function checkAngle(angle) {
    if(x + 10 >= 400) {
      if(angle <= Math.PI)
        return angle = (Math.PI/2) + ((Math.PI / 2) - reduceAngle(angle));
      else if(angle > Math.PI)
        return angle = (3 * Math.PI / 2) - ((Math.PI / 2) - reduceAngle(angle));
    }else if(x - 10 <= 0) {
      if(angle <= Math.PI)
        return angle = Math.PI/2 - reduceAngle(angle);
      else if(angle > Math.PI)
        return angle = 3* Math.PI/2 + (Math.PI/2  - reduceAngle(angle));
    }else if(y - 10 <= 0) {
      if(angle >= 3 * Math.PI /2)
        return angle = Math.PI/2 - reduceAngle(angle);
      else if(angle < 3 * Math.PI/2)
        return angle = Math.PI - (Math.PI / 2 - reduceAngle(angle));
    }else if(y + 10 >= 400) {
      if(angle <= Math.PI/2)
        return angle = 2*Math.PI - (Math.PI / 2 - reduceAngle(angle));
      else if(angle > Math.PI/2)
        return angle = Math.PI + (Math.PI / 2 - reduceAngle(angle));
    }else
      return angle;
  }
  function reduceAngle(angle) {
    if(angle < Math.PI / 2) {
      return angle;
    }else{
      angle = angle - (Math.PI / 2);
      return reduceAngle (angle);
    }
  }
  function updateAnimation(step) {
    cx.clearRect(0, 0, 400, 400);
    cx.lineWidth = 4;
    cx.strokeRect(0, 0, 400, 400);
    angle = checkAngle(angle);
    x += Math.cos(angle) * step * 200;
    y += Math.sin(angle) * step * 200;
    cx.lineWidth = 2;
    cx.beginPath();
    cx.arc(x, y, 20, 0, 7);
    cx.stroke();
  }
</script>

2 个答案:

答案 0 :(得分:2)

在处理非旋转框中的反射时,在反射时不需要处理角度。只需根据角度定义初始矢量。

var vector = {
      x: speed * Math.cos(angle),
      y: speed * Math.sin(angle)
    };

然后,您只需分别检查x和y的边界,并反转每个轴的斜率值:

  if (x - radius <= 0 || x + radius>= 400) {
    vector.x = -vector.x;      // reflect x
  }
  if (y - radius<= 0 || y + radius> 400) {
    vector.y = -vector.y;      // reflect y
  }

您可以随时通过添加另一个带有delta角的矢量来调整角度。

如果您的反弹框旋转0°,请检查this answer是否有矢量反射。

例如

使用您的代码作为基础,这将实现如下:

var cx = document.querySelector("canvas").getContext("2d");
var lastTime = null;
var x, y;

// calculate an initial vector
var angle = 20 / 180 * Math.PI;   // angle -> radians
var speed = 5;
var vector = {
      x: speed * Math.cos(angle),
      y: speed * Math.sin(angle)
    };

x = y = 200;

function frame(time) {
  if (lastTime != null)
    updateAnimation(Math.min(100, time - lastTime) / 1000);
  lastTime = time;
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);


function checkAngle() {
  var dlt = 10 + 2 + 4;        //include radius and line-widths;
  if (x - dlt <= 0 || x + dlt >= 400) {
    vector.x = -vector.x;      // reflect x
  }
  if (y - dlt <= 0 || y + dlt > 400) {
    vector.y = -vector.y;      // reflect y
  }
}

function updateAnimation(step) {
  cx.clearRect(0, 0, 400, 400);
  cx.lineWidth = 4;
  cx.strokeRect(0, 0, 400, 400);
  
  x += vector.x;    // use our vector
  y += vector.y;
  checkAngle();     // test for hits
  
  cx.lineWidth = 2;
  cx.beginPath();
  cx.arc(x, y, 20, 0, 7);
  cx.stroke();
}
<canvas width="400" height="400"></canvas>

答案 1 :(得分:1)

根据我在你的图纸和演示中所看到的情况来判断,角度是从错误的轴上取下来的。如果接近20度,你会期望球以180-20度离开。相反,它正在做的是离开90+20度。

虽然我无法在代码中找到导致此错误的确切位置,但我觉得我必须指出这一点,希望有人可以改进它。