在js中返回精确的向量分量canvas

Returning precise vector components in js canvas

我一直在努力渲染从 "enemy" 节点到 2D 11:11 网格中的 "player" 节点(0:0 = 顶部-左)在 JS/Canvas。 After a lot of reading up 我已经设法让镜头接近,但不是很成功。我认为我的速度函数有点出问题,但我真的不知道为什么。这是三角函数:

this.getVelocityComponents = function(speed){
// loc (location of enemy actor) = array(2) [X_coord, Y_coord]
// des (destination (ie. player in this instance)) = array(2) [X_coord, Y_coord]
var i, sum, hyp, output = [], dis = [];
var higher = false;
for (i in loc) {      
  sum = 0;
  if (loc[i] > des[i])
    sum = loc[i] - des[i];        
  if (loc[i] < des[i]) 
    sum = des[i] - loc[i];
  dis.push(sum);
}    
hyp = Math.sqrt(Math.pow(dis[X], 2) + Math.pow(dis[Y], 2));
if (dis[X] > dis[Y]) {
  output[X] = (speed *  Math.cos(dis[X]/hyp))        
  output[Y] = (speed *  Math.sin(dis[Y]/hyp))        
} else if (dis[X] < dis[Y]) {
  output[X] = (speed *  Math.cos(dis[Y]/hyp))              
  output[Y] = (speed *  Math.sin(dis[X]/hyp))        
}
return output;

}

这是让弹丸框架的X和Y前进的指令:

          var distance = [];
      for (i in loc) {      
        var sum = 0;
        if (loc[i] > des[i])
          sum = loc[i] - des[i];        
        if (loc[i] < des[i]) 
          sum = des[i] - loc[i];
        distance.push(sum);
      }  

      if (distance[X] > distance[Y]) {
        frm[X] += (loc[X] < des[X]) ? v[X] : -v[X];
        frm[Y] += (loc[Y] < des[Y]) ? v[Y] : -v[Y];
      } else {
        frm[Y] += (loc[Y] < des[Y]) ? v[X] : -v[X];
        frm[X] += (loc[X] < des[X]) ? v[Y] : -v[Y]; 
      }

下面是截图。蓝色是玩家,粉色是敌人,黄色圆圈是弹丸

如您所见,快到目标了。

我是不是做错了什么?我需要做什么?

解决方案比这简单得多。

你应该怎么办?

1) 计算从敌人到玩家的向量。那将是拍摄方向。

2) 归一化向量:这意味着您构建一个长度为 1 且方向相同的向量。

3) 将该向量乘以你的速度:现在你有一个正确的速度向量,具有正确的范数,针对玩家。

下面的一些代码可以帮助您理解:

function spawnBullet(enemy, player) { 
  var shootVector = [];

  shootVector[0] = player[0] - enemy[0];
  shootVector[1] = player[1] - enemy[1];

  var shootVectorLength = Math.sqrt(Math.pow(shootVector[0], 2) + Math.pow(shootVector[1],2));

  shootVector[0]/=shootVectorLength;
  shootVector[1]/=shootVectorLength;

  shootVector[0]*=bulletSpeed;
  shootVector[1]*=bulletSpeed;

 // ... here return an object that has the enemy's coordinate
 // and shootVector as speed

 }

然后,由于您在计算中不使用时间 (!!wrooong!!;-) ),您将使子弹直接移动:

bullet[0] += bullet.speed[0];
bullet[1] += bullet.speed[1];

现在,固定步长的问题是您的游戏 运行 在 30fps 设备上比在 60fps 设备上慢两倍。解决方案是计算自上次刷新以来经过了多少时间,我们称这个时间为 'dt'。使用那个时间将引导您进行更新,例如:

bullet[0] += dt * bullet.speed[0];
bullet[1] += dt * bullet.speed[1];

现在您将与帧速率无关,您的游戏在任何设备上的感觉都一样。

要计算从敌人到玩家的方向,您可以稍微简化计算。

求方向角

var diffX = Player.x - Enemy.x,        // difference in position
    diffY = Player.y - Enemy.y,
    angle = Math.atan2(diffY, diffX);  // atan2 will give the angle in radians

请注意,对于 atan2,Y 的差异首先出现,因为 canvas 的方向为 0°,指向右侧。

速度矢量

然后使用角度和速度计算速度矢量:

// calculate velocity vector
var speed = 8,
    vx = Math.cos(angle) * speed,   // angle x speed
    vy = Math.sin(angle) * speed;

如果时间很重要,您可能要考虑将时间作为一个因素。你可以在这里看到 my answer 的例子。

演示

使用这些计算,您将始终能够 "hit" 拥有射弹的玩家(重新加载演示以将敌人位置更改为随机 y):

var ctx = document.querySelector("canvas").getContext("2d"),
    Player = {
      x: 470,
      y: 75
    },
    Enemy = {
      x: 100,
      y: Math.random() * 150  // reload demo to change y-position
    };

// calculate angle
var diffX = Player.x - Enemy.x,
    diffY = Player.y - Enemy.y,
    angle = Math.atan2(diffY, diffX);

// calculate velocity vector
var speed = 8,
    vx = Math.cos(angle) * speed,   // angle x speed
    vy = Math.sin(angle) * speed,
    x = Enemy.x,          // projectil start
    y = Enemy.y + 50;

// render
(function loop() {
  ctx.clearRect(0, 0, 500, 300);
  ctx.fillRect(Player.x, Player.y, 30, 100);
  ctx.fillRect(Enemy.x, Enemy.y, 30, 100);
  ctx.fillRect(x - 3, y -3, 6, 6);
  x += vx;
  y += vy;
  if (x < 500) requestAnimationFrame(loop);
})();
<canvas width=500 height=300></canvas>