在javascript中绘制轨迹?

时间:2015-06-11 10:59:03

标签: javascript canvas

不知道还有什么要问这个问题。我正在使用HTML格式,并希望从画布的左下角开始绘制射弹的轨迹,以一定的角度拍摄,具有一定的速度(如45degrees 10ms) 。到目前为止,我主要看到使用

ctx.beginPath();

ctx.moveTo(0, 0);

ctx.lineTo((180), 180);

ctx.stroke();

但那只画一条直线?

2 个答案:

答案 0 :(得分:3)

维基百科有一些准确的[x,y]轨迹计算:

http://en.wikipedia.org/wiki/Trajectory_of_a_projectile

但是如果你只是想让你的射弹对目标形成弧线,你可以这样做:

  • 给定起点(p0)和目标点(p2),
  • 计算垂直于p0&的中点的点。 p2在指定距离(p1),
  • 绘制从p0到p2的二次曲线,其中p1为曲线中间控制点。

enter image description here

如果你想沿着该二次曲线绘制点,你可以使用De Casteljau算法,然后沿着绘制的点绘制你的射弹:

function getQuadraticBezierXYatT(startPt,controlPt,endPt,T) {
    var x = Math.pow(1-T,2) * startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x; 
    var y = Math.pow(1-T,2) * startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y; 
    return( {x:x,y:y} );
}



var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

var p0={x:0,y:ch};
var p2={x:180,y:180};
var distance=25;
var p1;

var nextTime=0;
var delay=1000/60*3;
var pts;
var ptIndex=0;

redraw();

$myslider=$('#myslider');
$myslider.attr({min:0,max:100}).val(distance);
$myslider.on('input change',function(){
  distance=parseInt($(this).val());
  redraw();
});

$('#plot').click(function(){
  pts=plot(p0,p1,p2);
  ptIndex=0;
  requestAnimationFrame(animatePlot);    
});

function animatePlot(time){
  //    if(time<nextTime){requestAnimationFrame(animatePlot);}
  nextTime=time+delay;
  if(ptIndex<pts.length){
    var p=pts[ptIndex];
    ctx.clearRect(0,0,cw,ch);
    ctx.beginPath();
    ctx.arc(p.x,p.y,2,0,Math.PI*2);
    ctx.closePath();
    ctx.fill();
    ctx.beginPath();
    ctx.arc(p2.x,p2.y,4,0,Math.PI*2);
    ctx.closePath();
    ctx.fill();
    ctx.fillText('['+p2.x+','+p2.y+']',p2.x+10,p2.y);        
    ptIndex++;
    requestAnimationFrame(animatePlot);
  }
}

function plot(p0,p1,p2){
  var pts=[];
  var lastX=p0.x;
  var lastY=p0.y;
  for(var T=0;T<500;T++){
    var p=getQuadraticBezierXYatT(p0,p1,p2,T/500);
    var dx=p.x-lastX;
    var dy=p.y-lastY;
    if(dx*dx+dy*dy>1){
      pts.push({x:p.x,y:p.y});
      lastX=p.x;
      lastY=p.y;
    }
  }
  return(pts)
}

function redraw(){
  p1=pointPerpendicularToMidpoint(p0,p2,distance);
  ctx.clearRect(0,0,cw,ch);
  ctx.beginPath();
  ctx.moveTo(p0.x,p0.y);
  ctx.quadraticCurveTo(p1.x,p1.y,p2.x,p2.y);
  ctx.stroke();
  ctx.beginPath();
  ctx.arc(p2.x,p2.y,4,0,Math.PI*2);
  ctx.closePath();
  ctx.fill();
  ctx.fillText('['+p2.x+','+p2.y+']',p2.x+10,p2.y);
}


function pointPerpendicularToMidpoint(p0,p2,distance){
  var dx=p2.x-p0.x;
  var dy=p2.y-p0.y;
  var midpoint={ x:p0.x+dx*0.50, y:p0.y+dy*0.50, };
  var angle=Math.atan2(dy,dx);
  var perpendicularPoint={
    x: midpoint.x+distance*Math.cos(angle-Math.PI/2),
    y: midpoint.y+distance*Math.sin(angle-Math.PI/2)        
  };
  return(perpendicularPoint);
}

function getQuadraticBezierXYatT(startPt,controlPt,endPt,T) {
  var x = Math.pow(1-T,2) * startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x; 
  var y = Math.pow(1-T,2) * startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y; 
  return( {x:x,y:y} );
}
&#13;
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
Change Curve:&nbsp<input id=myslider type=range>
<br>
<button id=plot>Plot the curve</button>
<br>
<canvas id="canvas" width=300 height=250></canvas>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

你想要的是一个在X和Y方向都有速度的物体。对于每次迭代,您都会因重力而降低Y的速度。对于每次迭代,您可以绘制一条线,请参见下面的示例。

&#13;
&#13;
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");

c.width = 450;
c.height = 300;

var x = 0;
var y = 300;
var oldX = 0;
var oldY = 300;
var xVel = 10;
var yVel = -20;
var g = 1;


var myInterval = setInterval(function () {
                               x+=xVel;
                               y+=yVel;
                               yVel+=g;
                               ctx.beginPath();
                               ctx.moveTo(oldX,oldY);
                               ctx.lineTo(x,y);
                               ctx.stroke();
                               oldX = x;
                               oldY = y;
  
  if (y>c.height) {clearInterval(myInterval);}
                             },20);
&#13;
canvas {
    border: 1px solid black;
}
&#13;
<canvas id="canvas"></canvas>
&#13;
&#13;
&#13;