关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

vue3 + canvas 实现坦克大战系列(二):核心原理讲解(上)

发布时间:2023-06-26 21:00:18

前言


接着上篇讲,本篇主要给大家讲解一下子弹击中物体、物体销毁、敌方坦克构建生成、运动算法、爆炸效果、以及障碍物的生成;了解了这些我相信你可以不依赖游戏引擎实现大部分小游戏的开发。

Es5版本: 在线游戏 源代码

W/上 S/下 A/左 D/右 F/射击

让我们开始吧!


敌方坦克的生成


我们可以使用 for 循环和Tank 构造函数,批量制造多个敌方坦克,x,y 为其在画布中的坐标,direction 为坦克当前方向,type 为精灵图中截取坦克图片的信息,包含了坐标,尺寸,类型等


for(let t=0; t<20; t++) {  let tank = new Tank(new TankConfig({  x: 100 + t*30,  y: 100,  direction: DIRECTION.DOWN,  type: TANK_TYPE.ENEMY0,  is_player: 0  }))  tank.star(); } ENEMY0: {  type: 'ENEMY1',  dimension: [30, 30],  image_coordinates: [129, 1, 129, 33] }

   


坦克移动的算法


emove 函数就是就是物体移动状态下每帧都会执行的函数,将根据当前方向修改下帧的坐标,当下帧坐标到达地图边缘时将执行 dir 函数更新坦克方向,如果是子弹则将销毁。


this.emove = function (d, obstacle_sprites) {  this.direction = d  switch (d) {  case DIRECTION.UP:  if (  (obstacle_sprites && !this.checkRangeOverlap(obstacle_sprites)) ||  !obstacle_sprites  ) {  this.y -= this.speed   if (this.y <= 10) {  this.dir()  }  } else {  this.dir()  }  break  ...

   


dir 函数用来随机修改移动的方向,当然这个函数不能每帧都调用,否则坦克将像无头苍蝇一样了;那么什么时候需要修改方向呢,我们认为当坦克和物体相撞的时候或者到达地图边缘时修改方向是合理的;子弹也可以认为是一个物体,所以子弹到达坦克周边一定距离时也将引起坦克规避动作,也就是将触发dir 函数。


this.dir = function () {  if(Math.floor(Math.random()*10) === 0 || Math.floor(Math.random()*10) === 1) {  this.direction = DIRECTION.UP;  };  if(Math.floor(Math.random()*10) === 2 || Math.floor(Math.random()*10) === 3) {  this.direction = DIRECTION.DOWN;  };  if(Math.floor(Math.random()*10) === 4 || Math.floor(Math.random()*10) === 5) {  this.direction = DIRECTION.LEFT;  };  if(Math.floor(Math.random()*10) === 6 || Math.floor(Math.random()*10) === 7) {  this.direction = DIRECTION.RIGHT;  };  if(Math.floor(Math.random()*10) === 8 || Math.floor(Math.random()*10) === 9) {  this.dir();  } }

   



子弹击中物体的算法


我们定义 checkRangeOverlap 函数来判断两个物体是否相撞,uiobjs 为画布中所有的元素对象列表,包含 坦克、子弹、障碍物等;

this.getFrontPoints() 函数将根据当前方向返回包含三个顶端点坐标数组,形成判断区域;

uiobjs[o].getCornerPoints() 函数返回当前元素的四个边角坐标数组,形成判断区域;

然后getFrontPoints() 的三个点坐标 将分别和 uiobjs[o].getCornerPoints() 的四边坐标进行点对点判断,根据x, y 数值满足下方四个条件时则认为此点坐标在元素内部。


// 判断点坐标是否在区域内部,以识别是否相撞  CanvasSprite.prototype.checkRangeOverlap = function (uiobjs) {  for (let o in uiobjs) {  let obstacle_cp = uiobjs[o].getCornerPoints()  let fp = this.getFrontPoints()  for (let idx = 0; idx < fp.length; idx++) {  if (  fp[idx].x > obstacle_cp[0].x &&  fp[idx].x < obstacle_cp[1].x &&  fp[idx].y > obstacle_cp[0].y &&  fp[idx].y < obstacle_cp[2].y  ) {  return true  }  }  }  return false  }

   



// 返回当前物体顶端三坐标  CanvasSprite.prototype.getFrontPoints = function () {  let front_point  switch (this.direction) {  case DIRECTION.UP:  front_point = [  new Point(this.x, this.y),  new Point((2 * this.x + this.width) / 2, this.y),  new Point(this.x + this.width, this.y),  ]  break  ... 缩略,下左右方向  }  return front_point  }

   



// 返回元素四边坐标形成的矩形区域范围  CanvasSprite.prototype.getCornerPoints = function () {  var corner_points  switch (this.direction) {  case DIRECTION.UP:  corner_points = [  new Point(this.x, this.y),  new Point(this.x + this.width, this.y),  new Point(this.x + this.width, this.y + this.height),  new Point(this.x, this.y + this.height),  ]  break  ... 缩略,下左右方向  }  return corner_points  }

   



啊 坦克搞多了!但是可以看到子弹击中效果是成功的,你发现了没,击中后有一个爆炸效果,这个是怎么实现的呢?


/template/Home/leiyu/PC/Static