HTML5 Canvas - Javascript - 如何计算任何坐标之间的直线路径

时间:2015-11-05 15:26:18

标签: javascript html5 html5-canvas linear-algebra game-physics

我认识到这个问题的各种形式已被提出并在本论坛中得到了普遍的回答。但是我发现我仍然不知道如何做这项工作。

情景:

  • 我有一个HTML5 Canvas,其中0,0坐标位于左上角。
  • 我有一个可以在画布上移动的对象(播放器) WASD。
  • 我希望能够让玩家射击(施法,投掷,等等) 从他们当前的x,y坐标到某个方向的东西 点击鼠标。
  • 我想在原点(鼠标点击时的播放器位置)和目标(xy点击鼠标的位置)之间的直线上设置对象(子弹,火球等)的动画。

我可以获得所有原点和目标坐标,我尝试将它们放入矢量函数中,以确定下一个x,y坐标是什么,以使射弹动画化,但是我无法理解如何执行此操作。

一个重要的注释(可能很重要):我不想使用其他库或jquery我只想在javascript中编写它。

我基本上是在Lost Decades simple HTML5 game example工作并试图扩展它

我创造了一个像这样的射弹物体:

spl = {
  ox: 0,
  oy: 0,
  dx: 0,
  dy: 0,
  speed: 256,
  vector: {
    len: 0
  }
};

在鼠标点击事件监听器上我这样做:

addEventListener("mousedown", function(e){
  spl.ox = mvo.x;
  spl.oy = mvo.y;
  spl.dx = e.x;
  spl.dy = e.y;
  spl.vector = doVector(spl.ox, spl.oy, spl.dx, spl.dy);

}, false);

其中 spl.ox,oy是玩家在点击事件中的位置 spl.dx,dy是鼠标点击的矢量

我的doVector函数是我只是试图计算出这样的线性代数数学(它似乎没有逻辑地解决我的问题):

 function doVector(ox, oy, dx, dy){

    var diffX = (dx - ox);
    var diffY = (dy - oy);

    var length = Math.round(Math.sqrt(diffX*diffX+diffY*diffY));
    var normX = Math.round(dx/length);
    var normY = Math.round(dy/length);
    var normProof = (normX*normX+normY*normY);
    var dotProd = (ox*dx)+(oy*dy);
      return{
          len: length,
          dist: dist,
          normX: normX,
          normY: normY,
          normProof: normProof,
          dotProd: dotProd
      }
    }

我的更新功能(我认为是我应该将我的增量矢量用于spl对象的地方)只是处理玩家与isd的运动:

//update objects --/////////////dddw
var update = function(modifier){

  if(87 in keysDown){ //up
    mvo.y -= Math.round(mvo.speed * modifier);
  }

 if(83 in keysDown){ //down
    mvo.y += Math.round(mvo.speed * modifier);
  }

 if(65 in keysDown){ //left
    mvo.x -= Math.round(mvo.speed * modifier);
  }

 if(68 in keysDown){ //right
    mvo.x += Math.round(mvo.speed * modifier);
  }


}// END update objects --/////////////

当我试图找出矢量/速度事物的数学时,我的渲染函数变得臃肿:

// render everything
var render = function (){

    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.textAlign = "left";
    ctx.textBaseline = "top";


    ctx.font = "10px verdana";
    ctx.fillStyle = "#000088";
    ctx.fillText("MVO", mvo.x, mvo.y);
    ctx.fillText(mvo.x + ", " + mvo.y, mvo.x-9, mvo.y+11);

    ctx.fillStyle = "#008800";
    ctx.fillText("OXY", spl.ox, spl.oy);
    ctx.fillText(spl.ox + "," + spl.oy, spl.ox-9, spl.oy+11);

    ctx.fillStyle = "#880000";
    ctx.fillText("DXY", spl.dx-18, spl.dy-18);
    ctx.fillText(spl.dx + "," + spl.dy, spl.dx-29, spl.dy-7);


    ctx.font = "12px verdana";
    ctx.fillStyle = "#bbbbbb";
    ctx.fillText("mvo x,y: " + mvo.x + ", " + mvo.y, 32, 32);
    ctx.fillText("thing: ", 32, 44);
    ctx.fillText("thing: ", 32, 56);
    ctx.fillText("thing: ", 32, 68);
    ctx.fillText("thing:" , 32, 80);


    ctx.fillText("spl origin: " + spl.ox + "," + spl.oy, 525, 32);
    ctx.fillText("spl destination: " + spl.dx + "," + spl.dy, 525, 44);
    ctx.fillText("vector length: " + spl.vector.len, 525, 56);
    ctx.fillText("spl normalized: " + spl.vector.normX + "," + spl.vector.normY, 525, 68);
    ctx.fillText("spl norm proof: " + spl.vector.normProof, 525, 80);
    ctx.fillText("spl norm dotProd: " + spl.vector.dotProd, 525, 92);
}

最后我的主循环看起来像是

// Main loop
var main = function(){
   var now = Date.now();
   var delta = now - then;

   update(delta/1000);
   render();

   then = now;

   requestAnimationFrame(main);
};

现在,首先,如果你已经阅读并完成了这一切,那么非常感谢你的大脑周期。

其次,我想要做的就是确定如何重新计算在两个坐标之间移动的对象的向量,并相应地更新x,y位置。

我可能完全是愚蠢的,因为我读过great thing on linear algebra for games但似乎无法使其发挥作用。任何帮助将非常感激。

1 个答案:

答案 0 :(得分:0)

不要围绕你的方向向量,否则你的子弹方向将会关闭,它将会错过目标 正如enhzflep所说,使用diffXdiffYdxdy用于规范化,否则将完全错误。

var length = Math.sqrt(diffX*diffX+diffY*diffY);
var normX = diffX/length;
var normY = diffY/length;

要实际移动子弹,您必须更新其在update功能中的位置。您需要通过添加方向乘以速度和时间增量(modifier)来更新项目符号位置。

spl.ox += spl.vector.normX * spl.speed * modifier;
spl.oy += spl.vector.normY * spl.speed * modifier;

然后,您可以在render函数

中绘制它
ctx.beginPath();
ctx.arc(spl.ox, spl.oy, 5, 0, 2 * Math.PI, false);
ctx.fillStyle = "#000000";
ctx.fill();
ctx.fillText(spl.ox.toFixed(2) + "," + spl.oy.toFixed(2), spl.ox-40, spl.oy+6);

JSFiddle