关于我们

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

< 返回新闻公共列表

vue3 + canvas 实现坦克大战(一)(上)

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

前言


记得几年前刚做前端开发的时候,跟着师傅用纯 Es5 实现了这款坦克大战,那个时候不用考虑工程化可以说我入行前端是从 javaScript 小游戏开始的,时间已匆匆过去了数年,前端发展日新月异,各种新框架、新概念层出不穷,很容易就迷失在对各种新技术的盲目学习和应用中,真正的编程是什么呢?值得思考的问题。


我准备用 vue3 重新实现一下这款游戏,顺便回顾和梳理下自己的知识体系。

Es5版本:

在线游戏、源代码


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


让我们开始吧!


架构搭建


项目技术选型为 vue3、vite、less、pnpm、ts,按照vue3 官网文档来新建项目,注意:虽然我用了 vue3 实际上只是强行尝鲜,主体内容都是 js 用到的框架特性有限。


$ pnpm create vite-- --template vue $ cd$ pnpm install $ pnpm add -D less $ pnpm dev

   


Canvas 构造函数


游戏的核心为 canvas 画布和坦克元素,我们定义两个构造函数

canvas 构造函数的定义参数、方法:dom、dimension 尺寸、renderTo 渲染函数、drawText 文本绘制函数、drawImageSlice 图片绘制函数


画布绘制


canvas 图层按照一般的游戏设计优化理念,需要为静态背景和动态元素单独用不同的 canvas 图层表示,每次更新时只需要重新绘制动态元素就好了,我抽象出一个渲染函数


// 渲染 this.renderTo = function renderTo(container_id) {  if (!is_rendered) {  let container = document.getElementById(container_id)  //画布起始坐标  dom = document.createElement('canvas') // 创造canvas画布  dom.setAttribute('class', 'canvas')  ctx = dom.getContext('2d')  dom.setAttribute('width', container.clientWidth)  dom.setAttribute('height', container.clientHeight)  // 画布尺寸  dimension = {  x: container.clientWidth,  y: container.clientHeight,  }  container.insertBefore(dom, container.firstChild) // 插入cantainer容器  } }

   


文本渲染


想要知道画布中的具体位置坐标,可以定义一个函数,当鼠标滑动时候执行来将当前位置坐标绘制出来


this.drawText = function drawText(text, offset_left, offset_top, font) {  ctx.font = font || '25px Calibri'  ctx.fillStyle = '#fff'  ctx.fillText(text, offset_left, offset_top) }

   



画布重绘前的 clear


每次重绘前需要先擦掉整个画布


this.clear = function clear() {  ctx.clearRect(0, 0, dimension.x, dimension.y) }

   


核心:绘制函数


坦克、子弹、建筑等元素等绘制都是通过这个函数来完成的,实现远离是利用来雪碧图,通过坐标抓取特定位置的图片元素来获取各种不同坦克等元素的UI;

通过 rotate 旋转元素来实现坦克的转向;


this.drawImageSlice = function drawImage(img_ele, sx, sy, sWidth, sHeight, x, y, rotatation) {  ctx.save()  ctx.translate((2 * x + sWidth) / 2, (2 * y + sHeight) / 2) // 改变起始点坐标  ctx.rotate((Math.PI / 180) * rotatation) // 旋转  x = x || 0  y = y || 0  ctx.drawImage(img_ele, sx, sy, sWidth, sHeight, -sWidth / 2, -sHeight / 2, sWidth, sHeight)  ctx.restore() // 复原 }

   



/template/Home/leiyu/PC/Static