前言
记得几年前刚做前端开发的时候,跟着师傅用纯 Es5 实现了这款坦克大战,那个时候不用考虑工程化可以说我入行前端是从 javaScript 小游戏开始的,时间已匆匆过去了数年,前端发展日新月异,各种新框架、新概念层出不穷,很容易就迷失在对各种新技术的盲目学习和应用中,真正的编程是什么呢?值得思考的问题。
我准备用 vue3 重新实现一下这款游戏,顺便回顾和梳理下自己的知识体系。
Es5版本:
W/上 S/下 A/左 D/右 F/射击
让我们开始吧!
架构搭建
项目技术选型为 vue3、vite、less、pnpm、ts,按照vue3 官网文档来新建项目,注意:虽然我用了 vue3 实际上只是强行尝鲜,主体内容都是 js 用到的框架特性有限。
$ pnpm create vite <project-name> -- --template vue $ cd <project-name> $ 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() // 复原 }