javascript - 如何让汽车沿着路径行驶

标签 javascript jquery html canvas

我正在用 javascript 开发一个动画,其中汽车向一个人移动并选择,但目前我只是用下面的代码斜向驾驶到那个人,而不是一条路径。

Car.prototype.main = function() {
      var angle = angleBetweenTwoPoints(this.target.position, this.position);
      var cos = Math.cos(degreeToRadian(angle)) * -1;
      var sin = Math.sin(degreeToRadian(angle));
      var _this = _super.call(this) || this;
      this.angle = angle;
      this.position.x += cos * this.speed;
      this.position.y -= sin * this.speed;
      if (distance(this.position, this.target.position) < 10 && this.image == GameImage.getImage("hero") ) {
        this.target.position.x = Math.random() * mainCanvas.width;
        this.target.position.y = Math.random() * mainCanvas.height;
        this.hitCount++;
        console.log(hitCount);
        ctx.fillText("points : " + hitCount, 32, 32);
         this.changeImage = true;
          _this.speed = 3;
        this.changeImageTime = Date.now() + 600; //0.5 sec from now.

        this.image = (this.image == GameImage.getImage("hero"))? GameImage.getImage("hero_other") : GameImage.getImage("hero");

      }

      if(this.changeImage){
      if(Date.now() > this.changeImageTime){
        this.changeImage = false;
        _this.speed = 9;
        this.image = (this.image == GameImage.getImage("hero_other"))? GameImage.getImage("hero") : GameImage.getImage("hero_other");
      }
    }


    };
    return Car;
  }(Actor));

但除此之外,我想遵循一条路径。当您单击图像时,我还创建了一些网格,它会记录控制台是哪个网格。但我无法在路径中移动汽车。为了完全理解动画是在 animation .

感谢任何帮助

最佳答案

作为队列的路点。

对于路径点路径跟随,您使用一种称为队列的数组类型。顾名思义,队列保存需要使用的项目,具体来说,它们需要按照到达的顺序使用。队列中的第一个对象是第一个输出的对象(除非您排队)

在 JavaScript 中,使用数组很容易实现队列。

const path = {
    points : [],
    currentPos : null,
    dist : 0,
    totalDistMoved : 0,
    atEnd : false,
    addPoint(x,y) { 
        if(this.currentPos === null){ 
           this.currentPos = { x :0,y : 0};
           this.dist = 0; 
           this.totalDistMoved = 0;
        }
        this.points.push({x,y}) ;
    },
    moveAlong(dist){
        if(dist > 0){
           if(this.points.length > 1){ 
              var x = this.points[1].x - this.points[0].x;
              var y = this.points[1].y - this.points[0].y;
              var len = Math.sqrt(x*x+y*y) ;
              if(len - this.dist < dist){  
                 this.points.shift(); 
                 dist -= (len - this.dist);
                 this.totalDistMoved += (len - this.dist);
                 this.dist = 0; 
                 this.moveAlong(dist); 
                 return;
              }
              const frac =  this.dist + dist / len;
              this.currentPos.x = this.points[0].x + x * frac;
              this.currentPos.y = this.points[0].y + y * frac;
              this.dist += dist;
              this.totalDistMoved += dist;
          }else{
              this.currentPos.x = this.points[0].x;
              this.currentPos.y = this.points[0].y;
              this.dist = 0;
              this.atEnd = true;
          }
        }
     }
  }

使用

添加一些航点。

path.addPoint(1,1);
path.addPoint(100,20);
path.addPoint(110,120);
path.addPoint(210,120);
path.addPoint(250,420);

然后为动画的每一步获取一段距离

 path.moveAlong(10); // move ten pixels

并使用当前位置

 ctx.drawImage(car,path.currentPos.x,path.currentPos.y);

当你知道你已经到达路径的尽头时。

  if(path.atEnd) {
        // you have arrived
  }

并且您随时知道自己已经走了多远

  path.totalDistMoved       

这适用于仅向前播放的动画。它将忽略负距离,因为当您经过它们时,路径点将被转储

如果您希望重用路径对象,或者如果您正在添加路径点,则需要进行一些修改

一个简单的例子。

物体以恒定的速度移动。单击页面可添加更多航点。

const ctx = canvas.getContext("2d");
requestAnimationFrame(mainLoop);
function mainLoop(time){
    gTime = !gTime ? time : gTime;
    fTime = time - gTime;
    gTime = time;
    if(canvas.width !== innerWidth || canvas.height !== innerHeight){
        canvas.width = innerWidth;
        canvas.height = innerHeight;
    }else{
        ctx.setTransform(1,0,0,1,0,0);
        ctx.clearRect(0,0,canvas.width,canvas.height);
    }
    if(mouse.button){
        if(!point){
            point = {x:0,y:0};
            path.addPoint(point);
        }
        point.x = mouse.x;
        point.y = mouse.y;

    }else{ 
         if(point){ point = null }
    }
    
    ctx.beginPath();
    var i = 0;
    while(i < path.points.length){ ctx.lineTo(path.points[i].x,path.points[i++].y)}
    ctx.strokeStyle = "blue";
    ctx.lineWidth = 2;
    ctx.stroke();
    
    var i = 0;
    while(i < path.points.length){ ctx.strokeRect(path.points[i].x-4,path.points[i++].y-4,8,8)}
    
    path.moveAlong(4 * fTime / 100);
    var x = path.currentPos.x - thingPos.x;
    var y = path.currentPos.y - thingPos.y;
    thingPos.x = path.currentPos.x;
    thingPos.y = path.currentPos.y;
    drawThing(thingPos.x,thingPos.y,Math.atan2(y,x));


    requestAnimationFrame(mainLoop);
}
var point;
const thingPos = {x:0,y:0};
const path = {
  points : [],
  currentPos : null,
  distAlong : 0,
  totalDistMoved : 0,
  atEnd : false,
  addPoint(x,y) { 
      if(y === undefined){
         this.points.push(x); // add point as object
         return;
      }
      if(this.currentPos === null){ 
         this.currentPos = { x :0,y : 0};
         this.distAlong = 0; 
         this.totalDistMoved = 0;
      }
      
      this.points.push({x,y}) ;
  },
  moveAlong(dist){
      if(dist > 0){
         if(this.points.length > 1){ 
            var x = this.points[1].x - this.points[0].x;
            var y = this.points[1].y - this.points[0].y;
            var len = Math.sqrt(x*x+y*y) ;
            if(len - this.distAlong < dist){  
               this.points.shift(); 
               dist -= (len - this.distAlong);
               this.totalDistMoved += (len - this.distAlong);
               this.distAlong = 0; 
               this.moveAlong(dist); 
               return;
            }
            const frac =  (this.distAlong + dist) / len;
            this.currentPos.x = this.points[0].x + x * frac;
            this.currentPos.y = this.points[0].y + y * frac;
            this.distAlong += dist;
            this.totalDistMoved += dist;
        }else{
            this.currentPos.x = this.points[0].x;
            this.currentPos.y = this.points[0].y;
            this.distAlong = 0;
            this.atEnd = true;
        }
      }
   }
}

path.addPoint(20,20);
path.addPoint(120,20);
path.addPoint(220,120);
path.addPoint(320,120);
path.addPoint(420,20);

function mouseEvents(e) {
    const m = mouse;
    m.x = e.pageX;
    m.y = e.pageY;
    m.button = e.type === "mousemove" ? m.button : e.type === "mousedown";
}
function drawThing(x,y,dir) {
    ctx.setTransform(1,0,0,1,x,y);
    ctx.rotate(dir);
    ctx.fillStyle = "red";
    ctx.strokeStyle = "black";
    ctx.lineWidth = 2;
    ctx.beginPath();
    var i = 0;
    while(i < thing.length){ ctx.lineTo(thing[i++],thing[i++]) };
    ctx.closePath();
    ctx.fill();
    ctx.stroke();
  
}
const thing = [-20,-10,20,-10,22,-7,22,7,20,10,-20,10];
var gTime;  // global and frame time
var fTime;
const mouse = { x:0,y:0,button:false};
["mousemove","mousedown","mouseup"].forEach(t=>document.addEventListener(t,mouseEvents));
canvas {
position: absolute;
top : 0px;
left : 0px;
}
<canvas id="canvas"></canvas>
click drag to add waypoints.

关于javascript - 如何让汽车沿着路径行驶,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44732436/

相关文章:

javascript - 导航到子状态也会刷新其父状态

使用原型(prototype)的 Javascript 类系统

javascript - 字符串内字符 (') 的问题

Jquery - 将委托(delegate)绑定(bind)到所有 "a"标签

javascript - 代码在 Chrome 中有效,但在 IE 中无限循环

HTML/CSS :CamelCase vs Underscores

javascript - 每次加载适当的页面时,如何使脚本仅重定向一次?

javascript - 结合进度条将文本颜色更改为特定宽度?

javascript - 在 JavaScript 函数之外传递值

html - 将鼠标悬停在菜单上会显示子菜单,内容会向下滑动。如何不向下滑动内容和子菜单重叠内容?