我正在参加掘金社区游戏创意投稿大赛团队赛,详情请看:游戏创意投稿大赛
项目地址: codeape.site:8181/#/protectTh…
基本介绍
开发技术:canvas,vue2,js
前几天看到逛掘金看到了这个活动,正好我也在弄这个项目,就打算参加一下了,这次也是我在掘金发表的第一篇文章。
这是一个网页版的塔防小游戏,名称叫做保卫大司马(类似于保卫萝卜),大司马作为终点,有生命值,选用植物大战僵尸的素材来充当敌人和塔防,部分塔防使用一些主播火柴人图片(自己画的,有点丑)。
在本项目的开发过程中也涉及到不少的知识点,同时也挺锻炼思维的,由于最近忙着毕业答辩和一些工作,时间比较赶,很多功能还未完善。
开发流程
1. canvas开发小游戏基本流程
首先需要把canvas的2d上下文保存下来(接下来就对其进行绘画就好了),然后是初始化数据,接下来是加载图片
this.canvas = this.$refs.canvasRef;
this.ctx = this.canvas.getContext("2d");
this.initAllGrid()
this.initMovePath()
this.onKeyDown()
await this.allGifToStaticImg()
// 加载图片
this.imgOnloadObj = await this.loadImage(this.imgObj);
this.towerOnloadImg = await this.loadImage(this.towerList, 'img');
this.towerBulletOnloadImg = await this.loadImage(this.towerList, 'bulletImg');
this.startAnimation()
2. 初始化数据
将所需要的数据进行初始化,这里需要初始化页面中所有的格子数据(暂时定为每格大小50px*50px),初始化行动轨迹(就是页面中地下可供移动的格子)
/** 初始化所有格子 */
initAllGrid() {
const { x_num, y_num } = this.gridInfo
const arr = []
for(let i = 0; i < x_num; i++) {
arr.push([])
for(let j = 0; j < y_num; j++) {
arr[i][j] = 0
}
}
this.gridInfo.arr = arr
},
/** 初始化行动轨迹 */
initMovePath() {
const size = this.gridInfo.size
const movePathItem = {x: 0, y: 50, x_y: 3}
const movePath = []
// 控制x y轴的方向 1:左 2:下 3:右 4:上
let x_y = 3
for(let i = 0; i < this.floorTile.num; i++) {
switch (i) {
// case: 等于多少就 向一个方向移动(控制x_Y等于几)
}
// 将该份数据保存下来
movePath.push(JSON.parse(JSON.stringify(movePathItem)))
// 给格子数组中赋值,标记该位置情况为:有地板了
this.gridInfo.arr[movePathItem.y/size][movePathItem.x/size] = 1
}
this.movePath = movePath
},
3. gif图转png
由于canvas是一帧一帧将内容画出来的,所以gif图对于canvas不管用,需要转成多张静态图片。这里就需要用到Promise.all了等待所有图片都转成静态图片再开始下面的操作。而其中单张gif转静态图片需要用到libgif.js,其中的SuperGif方法可以用来操作gif图片。
/** 等待所有的gif图生成静态图片 */
async allGifToStaticImg() {
return Promise.all(this.enemySource.map((item, index) =>
this.gifToStaticImg(index))).then(res => {
this.loadingDone = true
}
)
},
/** 单张gif转静态图片 */
gifToStaticImg(index) {
// 主要流程如下
const gifImg = document.createElement('img');
gifImg.src = imgSource
// gifImg.style.transform = 'rotate(90deg)';
// 创建gif实例
const rub = new SuperGif({ gif: gifImg } );
rub.load(() => {
const imgList = [];
for (let i = 1; i <= rub.get_length(); i++) {
// 遍历gif实例的每一帧
rub.move_to(i);
const imgUrl = rub.get_canvas()
imgList.push(imgUrl)
}
this.enemySource[index].imgList = imgList
resolve()
});
}
4. 加载图片
canvas绘画的图像需要创建一个Image对象,等待图片加载完成,再将数据保存下来。
/** 加载图片 imgUrl: 图片数组, objKey: 在数组中的key值 */
loadImage(imgUrl, objKey) {
return new Promise((resolve, reject) => {
const imgObj = {}; // 保存图片资源
let tempImg, imgLength = 0, loaded = 0;
for (let key in imgUrl) {
imgLength++; // 初始化要加载图片的总数
tempImg = new Image();
tempImg.src = !objKey ? imgUrl[key] : imgUrl[key][objKey];
imgObj[key] = tempImg;
tempImg.onload = function () {
loaded++; // 统计已经加载完毕的图像
// 所有的图片都加载完毕
if (loaded >= imgLength) {
resolve(imgObj)
}
};
}
})
},
5. 开始动画绘画
这里使用requestAnimationFrame()来进行绘画,它的作用类似于定时器,但是它能做到比定时器更加流程的动画效果,能达到每秒60帧的刷新率,对于需要高刷新的小游戏很适合。
/** 开启动画绘画 */
startAnimation() {
const that = this;
(function go() {
that.startDraw();
if (!that.isPause) {
// 时间间隔为 1000/60 每秒 60 帧
requestAnimationFrame(go);
}
})();
},
6. 开始绘画和操作数据
当上面准备工作做好后,就开始游戏开发了,主要开发模式为:操作数据,然后绘画图像。由于页面的绘画一直是持续的。对于场上敌人的出现,只需处理数据就好了,对于建造塔防,发射子弹等就需要额外绘画了。
7. 判断敌人是否进入塔防攻击范围
主要是通过以下函数来进行判断,判断敌人图片的四个角是否进入了攻击范围(这里就不复杂化:数学中一个圆和一个矩形相遇),四个角都计算到圆心的距离是否小于半径即可。
/** 判断值是否在圆内 */
checkValInCircle(enemy, tower) {
const {x, y, w, h} = enemy
const angleList = [
this.calculateDistance(tower, x, y),
this.calculateDistance(tower, x + w, y),
this.calculateDistance(tower, x + w, y + h),
this.calculateDistance(tower, x , y + h),
]
if(angleList.some(item => item <= tower.r)) {
return true
}
return false
},
/** 计算点到圆心的距离之间的距离 */
calculateDistance(tower, x, y) {
const {x: _x, y: _y} = tower
const size_2 = this.gridInfo.size / 2
return this.powAndSqrt(_x + size_2 - x, _y + size_2 - y)
},
/** 两值平方相加并开方 求斜边 */
powAndSqrt(val1, val2) {
return Math.sqrt(Math.pow(val1, 2) + Math.pow(val2, 2))
},
以上就是本塔防游戏开发的主要思路以及主要功能代码了。
今天的文章头号玩家-保卫大司马分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/17444.html