如何让球在正确的方向上从桨上反弹而不是直线 [英] How to have ball bounce off paddle in right directions not as a straight line

查看:19
本文介绍了如何让球在正确的方向上从桨上反弹而不是直线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请原谅我对 JS 非常陌生.我已经创建了一个非常简单的画布,其中一个矩形由 keydownevents 控制,另一个只是在 rAF 中的画布上移动.

Forgive my complete noobness here as very new to JS. I've created a really simple canvas with one rectangle being controlled by keydownevents and one just moving around the canvas in rAF.

我现在想要的是,如果移动的球击中用户矩形以碰撞和反弹,而是以正确的角度反弹,而不是像我尝试过但失败的那样反向.

I want to now have if the moving ball hits the users rectangle to collide and bounce back but to bounce at the right angle that it hits not just in reverse like i have tried and failed at.

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

I know i need to calculate where it hits on the users rect, but I have no idea where to start or how Can someone point me in the right direction or give me a small snippet of what to do?

我将省略 Keycode 函数以留出空格,因为它们不需要.

I'll leave out the Keycode functions for space as they're not needed.

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();    
}

推荐答案

计算你可以做的反射 -

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

First, define the normal as a vector based on the pads angle:

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

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

Then use dot-product to calculate the incident angle with the incoming vector:

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
}

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

Then you need a hit-test to trigger the reflection. When hit, reflect the incoming vector on the normal which is 90° tangent to the pad.

一个简单的演示:

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>

这篇关于如何让球在正确的方向上从桨上反弹而不是直线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆