javascript - 如何让球以正确的方向而不是直线从桨上反弹

标签 javascript canvas

请原谅我对 JS 的新知识。 我已经创建了一个非常简单的 Canvas ,其中一个矩形由 keydownevents 控制,另一个只是在 rAF 中围绕 Canvas 移动。

我现在想知道,如果移动的球撞到用户的矩形会发生碰撞并反弹回来,但会以正确的 Angular 反弹,而不是像我尝试过但失败的那样反向反弹。

我知道我需要计算它在用户矩形上的位置,但我不知道从哪里开始或如何开始 有人能给我指出正确的方向或给我一小段该怎么做吗?

我将省略 Keycode 函数以节省空间,因为不需要它们。

function init() {

    canvas = document.getElementById("canvasdemo");
    ctx = canvas.getContext("2d");

    canvasWidth = canvas.width;
    canvasHeight = canvas.height;

    drawSquare();
}

function drawSquare() {

  ctx.clearRect(0, 0, canvasWidth, canvasHeight);
  // user controlled square
  ctx.fillStyle = "blue";
  ctx.fillRect(rect.x, rect.y, rect.w, rect.h);
  requestAnimationFrame(drawSquare); 


  if (rect.x + rect.vx > canvasWidth - 20 || rect.x + rect.vx < 0)
    rect.vx = -rect.vx;
  if (rect.y + rect.vy > canvasHeight - 20 || rect.y + rect.vy < 0)
    rect.vy = -rect.vy;

  rect.x += rect.vx;  
  rect.y += rect.vy;   

  // Moving Square 1 (left-right):

  requestAnimationFrame(squareTwo);

   if (dir1 == "right") {
      if (xpos < canvasWidth - 35) {
        xpos += 2;
      }else{
        dir1 = "left";
      }
    }

    if (dir1 == "left") {
      if (xpos>0) {
        xpos -= 2;
      }else{
        dir1 = "right";
      }
   }
}
// Second square
 function squareTwo() {

    ctx.fillStyle = "black";
    ctx.fillRect(xpos, ypos, 35, 35);
    ctx.fill();    
}

最佳答案

要计算你可以做的反射 -

首先,将法线定义为基于焊盘 Angular 向量:

function getNormal(a) {
    return {
        x: Math.sin(a),    // this will be 90° offset from the
        y: -Math.cos(a)    // incoming angle
    }
}

然后用点积计算与传入向量的入射 Angular :

function reflect(n, v) {
    var d = 2 * dot(v, n);   // calc dot product x 2
    v.x -= d * n.x;          // update vectors reflected by
    v.y -= d * n.y;          // normal using product d
    return v
}

// helper, calc dot product for two vectors
function dot(v1, v2) {
    return v1.x * v2.x + v1.y * v2.y
}

然后你需要一个 HitTest 来触发反射。当被击中时,将传入的向量反射到与焊盘成 90° 切线的法线上。

一个简单的演示:

function getNormal(a) {
  return {
    x: Math.sin(a),
    y: -Math.cos(a)
  }
}

function reflect(n, v) {
  var d = 2 * dot(v, n);
  v.x -= d * n.x;
  v.y -= d * n.y;
  return v
}

function dot(v1, v2) {
  return v1.x * v2.x + v1.y * v2.y
}

// --- for demo only ---
var ctx = document.querySelector("canvas").getContext("2d"),
    balls = [], padAngle = 0, angleDlt = 0.005;

function Ball() {         // a Ball object for demo (replace or use existing)
  var me = this;
  init();
  this.update = function() {
    if (this.posX < 0 || this.posX > 500 || this.posY < -4 || this.posY > 150) init();
    this.posX += this.x;
    this.posY += this.y;
    ctx.rect(this.posX - 2, this.posY - 2, 4, 4);
  };
  
  function init() {
    me.posX = Math.random() * 100 + 200;
    me.posY = -4;
    me.x = Math.random() - 0.5;
    me.y = 1;
    me.hit = false;
  }
}

// init some balls
for(var i = 0; i < 4; i++) balls.push(new Ball());

// animate demo
(function loop() {

  ctx.clearRect(0, 0, 500, 150);
  
  // speeds up frames but preserves some accuracy
  for(var subframes = 0; subframes < 3; subframes++) {

    ctx.beginPath();
    
    // render pad
    padAngle += angleDlt;
    if (padAngle < -Math.PI * 0.2 || padAngle > Math.PI * 0.2) angleDlt = -angleDlt;
    drawPad(padAngle);
    
    // get normal
    var normal = getNormal(padAngle);
    
    // hit test using the pad's path - this is where we do the reflection
    for(var i = 0, ball; ball = balls[i++];) {
      if (!ball.hit && ctx.isPointInPath(ball.posX, ball.posY)) {
        ball.hit = true;
        reflect(normal, ball);
      }
    }

    // update balls
    for(var i = 0, ball; ball = balls[i++];) ball.update();
  }
  
  ctx.fill();
  requestAnimationFrame(loop)
})();

function drawPad(angle) {
  ctx.translate(250, 100);
  ctx.rotate(angle);
  ctx.rect(-50, -3, 100, 6);
  ctx.setTransform(1,0,0,1,0,0);
}
<canvas width=500></canvas>

关于javascript - 如何让球以正确的方向而不是直线从桨上反弹,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29910502/

相关文章:

node.js - 错误 : CAIRO_FORMAT_RGB30 was not declared in this scope

javascript - kendoui grid,当autoBind配置设置为false时绑定(bind)数据

javascript - 免费代码营 : TWITCH TV API: Trying to move everything from getJSONs to AJAX requests

javascript - Canvas 的砌体布局

c# - WPF Listview 项目垂直定位与 Canvas 重叠问题

javascript - 使用 raphael.js 绘制直线的正确方法是什么?

javascript - 使用drawImage复制到HTML Canvas 时图像被剪裁

javascript - extjs4:如何提交相同的表单数据两次

javascript - 在 ag-grid 中处于行编辑模式时可以阻止排序吗?

javascript - 搜索并替换对象数组中的键