之前的canvas小游戏系列欢迎大家戳:

《VUE实现一个Flappy Bird~~~》

《VUE+Canvas实现上吊火柴人猜单词游戏》

《VUE+Canvas 实现桌面弹球消砖块小游戏》

《VUE+Canvas实现雷霆战机打字类小游戏》


如标题,这个游戏大家也玩过,随处可见,左右方向键控制财神移动,接住从天而降的金元宝等,时间一到,则游戏结束。先来看一下效果:

相比于之前的雷霆战机要打出四处飞的子弹,这次元素的运动轨迹就很单一了,垂直方向的珠宝和水平移动的财神爷,类似于之前的代码,这里就说一下关键步骤点吧:

1、键盘控制水平移动的财神爷

这个很简单,同理于《VUE+Canvas 实现桌面弹球消砖块小游戏》滑块的控制:

drawCaishen() {let _this = this;_this.ctx.save();_this.ctx.drawImage(_this.caishenImg,_this.caishen.x,_this.caishen.y,120,120);_this.ctx.restore();
},
moveCaishen() {this.caishen.x += this.caishen.dx;if (this.caishen.x > this.clientWidth - 120) {this.caishen.x = this.clientWidth - 120;} else if (this.caishen.x < 0) {this.caishen.x = 0;}
}

2、从天而降的珠宝

这个也很简单,但要注意的是,珠宝的初始x值不能随机取0~clientWidth了,因为这样很容易造成珠宝堆积在一起,影响了游戏的可玩性,所以珠宝最好是分散在不同的轨道上,这里我们把画布宽度分为5条轨道,初始珠宝的时候,我们就把珠宝分散在轨道上,并且y值随机在一定高度造成参差。而后新生成的珠宝都依据轨道分布来生成,避免珠宝挤在一起。

generateTreasure() {let _this = this;if (_this.treasureArr.length < MaxNum) {let random = Math.floor(Math.random() * TreasureNames.length);let channel = _this.getRandomArbitrary(1, 5);_this.treasureArr.push({x: _this.channelWidth * (1 / 2 + (channel - 1)) - 30,y: 0,name: TreasureNames[random],speed: _this.getRandomArbitrary(2, 4)});}
},
filterTreasure(item) {let _this = this;if (item.x <= _this.caishen.x + 110 &&item.x >= _this.caishen.x &&item.y > _this.caishen.y) {// 判断和财神的触碰范围_this.score += _this.treasureObj[item.name].score;return false;}if (item.y >= _this.clientHeight) {return false;}return true;
},
drawTreasure() {let _this = this;_this.treasureArr = _this.treasureArr.filter(_this.filterTreasure);_this.treasureArr.forEach(item => {_this.ctx.drawImage(_this.treasureObj[item.name].src,item.x,item.y,60,60);item.y += item.speed;});
},
getRandomArbitrary(min, max) {return Math.random() * (max - min) + min;
}

这里用filter函数过滤掉应该消失的珠宝,如果用for+splice+i--的方法会造成抖动。

然后给予每个珠宝随机的运动速度,当珠宝进入财神爷的图片范围时则累加相应分数。

3、倒计时圆环

设置倒计时30s,那么在requestAnimationFrame的回调里计算当前时间与上次时间戳毫秒差值是否大于1000,实现秒的计算,然后取另一时间戳累加progress,实现圆环的平滑移动。

drawCountDown() {// 画进度环let _this = this;_this.progress += Date.now() - _this.timeTag2;_this.timeTag2 = Date.now();_this.ctx.beginPath();_this.ctx.moveTo(50, 50);_this.ctx.arc(50,50,40,Math.PI * 1.5,Math.PI * (1.5 + 2 * (_this.progress / (countDownInit * 1000))),false);_this.ctx.closePath();_this.ctx.fillStyle = "yellow";_this.ctx.fill();// 画内填充圆_this.ctx.beginPath();_this.ctx.arc(50, 50, 30, 0, Math.PI * 2);_this.ctx.closePath();_this.ctx.fillStyle = "#fff";_this.ctx.fill();// 填充文字_this.ctx.font = "bold 16px Microsoft YaHei";_this.ctx.fillStyle = "#333";_this.ctx.textAlign = "center";_this.ctx.textBaseline = "middle";_this.ctx.moveTo(50, 50);_this.ctx.fillText(_this.countDown + "s", 50, 50);}
(function animloop() {_this.ctx.clearRect(0, 0, _this.clientWidth, _this.clientHeight);_this.loop();animationId = window.requestAnimationFrame(animloop);if (_this.countDown === 0) {_this.gameOver = true;window.cancelAnimationFrame(animationId);}if (Date.now() - _this.timeTag >= 1000) {_this.countDown--;_this.timeTag = Date.now();}
})();

至此,一个非常简单的财神爷接元宝的小游戏就完成了,当然可以为了增加难度,设置不间断地丢炸弹这一环节,原理同珠宝的运动是一样的。

下面还是附上全部代码,供大家参考学习:

<template><div class="caishen"><canvas id="caishen" width="1200" height="750"></canvas><div class="container" v-if="gameOver"><div class="dialog"><p class="once-again">恭喜!</p><p class="once-again">本回合夺宝:{{ score }}分</p></div></div></div>
</template><script>
const TreasureNames = ["yuanbao","tongqian","jintiao","shuijin_red","shuijin_blue","fudai"
];
let animationId = null;
let countDownInit = 0;
const MaxNum = 5;
export default {name: "CaiShen",data() {return {score: 0,ctx: null,caishenImg: null,clientWidth: 0,clientHeight: 0,channelWidth: 0,caishen: {x: 0,y: 0,speed: 8,dx: 0},progress: 0,countDown: 30,timeTag: Date.now(),timeTag2: Date.now(),treasureArr: [],gameOver: false,treasureObj: {yuanbao: {score: 5,src: null},tongqian: {score: 2,src: null},jintiao: {score: 10,src: null},shuijin_red: {score: 20,src: null},shuijin_blue: {score: 15,src: null},fudai: {score: 8,src: null}}};},mounted() {let _this = this;let container = document.getElementById("caishen");_this.ctx = container.getContext("2d");_this.clientWidth = container.width;_this.clientHeight = container.height;_this.channelWidth = Math.floor(_this.clientWidth / 5);_this.caishenImg = new Image();_this.caishenImg.src = require("@/assets/img/caishen/财神爷.png");_this.initTreasures();countDownInit = _this.countDown;_this.caishen.x = _this.clientWidth / 2 - 60;_this.caishen.y = _this.clientHeight - 120;document.onkeydown = function(e) {let key = window.event.keyCode;if (key === 37) {// 左键_this.caishen.dx = -_this.caishen.speed;} else if (key === 39) {// 右键_this.caishen.dx = _this.caishen.speed;}};document.onkeyup = function(e) {_this.caishen.dx = 0;};_this.caishenImg.onload = function() {(function animloop() {_this.ctx.clearRect(0, 0, _this.clientWidth, _this.clientHeight);_this.loop();animationId = window.requestAnimationFrame(animloop);if (_this.countDown === 0) {_this.gameOver = true;window.cancelAnimationFrame(animationId);}if (Date.now() - _this.timeTag >= 1000) {_this.countDown--;_this.timeTag = Date.now();}})();};},methods: {initTreasures() {let _this = this;Object.keys(_this.treasureObj).forEach(key => {_this.treasureObj[key].src = new Image();_this.treasureObj[key].src.src = require(`@/assets/img/caishen/${key}.png`);});for (let i = 0; i < MaxNum; i++) {let random = Math.floor(Math.random() * TreasureNames.length);_this.treasureArr.push({x: _this.channelWidth * (1 / 2 + i) - 30,y: _this.getRandomArbitrary(0, 20),name: TreasureNames[random],speed: _this.getRandomArbitrary(2, 4)});}},loop() {let _this = this;_this.drawCountDown();_this.drawCaishen();_this.moveCaishen();_this.generateTreasure();_this.drawTreasure();_this.drawScore();},drawCaishen() {let _this = this;_this.ctx.save();_this.ctx.drawImage(_this.caishenImg,_this.caishen.x,_this.caishen.y,120,120);_this.ctx.restore();},moveCaishen() {this.caishen.x += this.caishen.dx;if (this.caishen.x > this.clientWidth - 120) {this.caishen.x = this.clientWidth - 120;} else if (this.caishen.x < 0) {this.caishen.x = 0;}},drawScore() {let _this = this;_this.ctx.beginPath();_this.ctx.fillStyle = "#fff";_this.ctx.textAlign = "center";_this.ctx.textBaseline = "middle";_this.ctx.fillText(_this.score + "分", 30, _this.clientHeight - 10);_this.ctx.closePath();},drawCountDown() {// 画进度环let _this = this;_this.progress += Date.now() - _this.timeTag2;_this.timeTag2 = Date.now();_this.ctx.beginPath();_this.ctx.moveTo(50, 50);_this.ctx.arc(50,50,40,Math.PI * 1.5,Math.PI * (1.5 + 2 * (_this.progress / (countDownInit * 1000))),false);_this.ctx.closePath();_this.ctx.fillStyle = "yellow";_this.ctx.fill();// 画内填充圆_this.ctx.beginPath();_this.ctx.arc(50, 50, 30, 0, Math.PI * 2);_this.ctx.closePath();_this.ctx.fillStyle = "#fff";_this.ctx.fill();// 填充文字_this.ctx.font = "bold 16px Microsoft YaHei";_this.ctx.fillStyle = "#333";_this.ctx.textAlign = "center";_this.ctx.textBaseline = "middle";_this.ctx.moveTo(50, 50);_this.ctx.fillText(_this.countDown + "s", 50, 50);},filterTreasure(item) {let _this = this;if (item.x <= _this.caishen.x + 110 &&item.x >= _this.caishen.x &&item.y > _this.caishen.y) {// 判断和财神的触碰范围_this.score += _this.treasureObj[item.name].score;return false;}if (item.y >= _this.clientHeight) {return false;}return true;},drawTreasure() {let _this = this;_this.treasureArr = _this.treasureArr.filter(_this.filterTreasure);_this.treasureArr.forEach(item => {_this.ctx.drawImage(_this.treasureObj[item.name].src,item.x,item.y,60,60);item.y += item.speed;});},getRandomArbitrary(min, max) {return Math.random() * (max - min) + min;},generateTreasure() {let _this = this;if (_this.treasureArr.length < MaxNum) {let random = Math.floor(Math.random() * TreasureNames.length);let channel = _this.getRandomArbitrary(1, 5);_this.treasureArr.push({x: _this.channelWidth * (1 / 2 + (channel - 1)) - 30,y: 0,name: TreasureNames[random],speed: _this.getRandomArbitrary(2, 4)});}}}
};
</script><!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
#caishen {background-color: #b00600;background-image: url("~assets/img/caishen/brick-wall.png");
}
.container {position: absolute;top: 0;right: 0;bottom: 0;left: 0;background-color: rgba(0, 0, 0, 0.3);text-align: center;font-size: 0;white-space: nowrap;overflow: auto;
}
.container:after {content: "";display: inline-block;height: 100%;vertical-align: middle;
}
.dialog {width: 400px;height: 300px;background: rgba(255, 255, 255, 0.5);box-shadow: 3px 3px 6px 3px rgba(0, 0, 0, 0.3);display: inline-block;vertical-align: middle;text-align: left;font-size: 28px;color: #fff;font-weight: 600;border-radius: 10px;white-space: normal;text-align: center;.once-again-btn {background: #1f9a9a;border: none;color: #fff;}
}
</style>

VUE+Canvas实现财神爷接元宝小游戏相关推荐

  1. 《uni-app》一个非canvas的飞机对战小游戏实现-敌机模型实现

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言-博主看到后会去代替大家踩坑的-接下来的几篇都是uni-app的小实战,有助于我们更好的去学 ...

  2. 《uni-app》一个非canvas的飞机对战小游戏实现(一)准备

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言-博主看到后会去代替大家踩坑的-接下来的几篇都是uni-app的小实战,有助于我们更好的去学 ...

  3. 《uni-app》一个非canvas的飞机对战小游戏-启动页

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言-博主看到后会去代替大家踩坑的-接下来的几篇都是uni-app的小实战,有助于我们更好的去学 ...

  4. 《uni-app》一个非canvas的飞机对战小游戏实现-我方飞机实现

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言-博主看到后会去代替大家踩坑的-接下来的几篇都是uni-app的小实战,有助于我们更好的去学 ...

  5. 《uni-app》一个非canvas的飞机对战小游戏实现-碰撞检测的实现

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言-博主看到后会去代替大家踩坑的-接下来的几篇都是uni-app的小实战,有助于我们更好的去学 ...

  6. 技术交流:接元宝小游戏(JQ转JS并解决游戏过程问题)

    接元宝小游戏:要求很简单,将源码中的JQ转为JS来实现游戏的整个过程,并解决游戏过程中出现的问题. 目录 解决游戏中的两个问题: JQ源码 问题解决和总结 解决游戏中的两个问题: 元宝有时不下落 没有 ...

  7. 基于vue框架使用canvas实现井字棋小游戏

    引言:最近实现了一个图片上传压缩的功能,使用了canvas,所以学习一下canvas的语法,实现一个井字棋小游戏,这个小游戏可以人人对弈,如果大家有兴趣,可以对代码进行迭代,比如采用极大值极小值搜索法 ...

  8. canvas实现H5接物类小游戏

    在vue中实现接物类小游戏 先放张效果图 <template><div id="container"><div id="guidePanel ...

  9. 使用canvas写一个flappy bird小游戏

    简介 canvas 是HTML5 提供的一种新标签,它可以支持 JavaScript 在上面绘画,控制每一个像素,它经常被用来制作小游戏,接下来我将用它来模仿制作一款叫flappy bird的小游戏. ...

最新文章

  1. 基于OpenCV创建视频会议虚拟背景
  2. 170页PPT入门深度强化学习! 汪荣贵 图灵人工智能 昨天
  3. 解决MySQL8.0报错:Unknown system variable 'validate_password_policy'
  4. python里面的之前打过的记忆信息-python中的if __name__ == 'main'
  5. Solaris的硬件相关命令
  6. PyCharm:调试遇到问题
  7. Ctrl+F5为强制刷新
  8. Python实现好友管理系统
  9. matlab轴向柱塞泵动力学仿真,基于ADAMS柔性模型的轴向柱塞泵动力学仿真
  10. CENTOS安装XXNET
  11. 恒讯科技分享:rust服务器搭建教程
  12. 淘客链接转成正常淘宝链接JAVA代码实现
  13. python怎样计算增长率_Python令人难以置信的增长
  14. 苹果应用审核指南最新
  15. 简单的把cad怎么转换成pdf格式呢?
  16. 免费在线CAD转PDF怎么批量转换
  17. 这世界就是,一些人总在昼夜不停地运转,而另外一些人,起床就发现世界已经变了。...
  18. Windows Server 2012 如何实现多个用户远程桌面登陆?
  19. 台式计算机激光头,cd机激光头维修论坛-CD机维修,我家台式CD机坏了,进仓后激光头只动动,但是不发红光,懂的朋友来指点。-电气资讯 - 电工屋...
  20. java 判断文章的重复率_5个避免意外论文重复率高的方法

热门文章

  1. elementui表格父子表_vue+element-ui实现主子表
  2. idea上git更改分支方便快捷
  3. 微信PC版 2.7.1.43 多开 防撤回 支持小程序 绿色版
  4. python 抓取内涵段子
  5. oracle 12c to_char 函数(1) 日期-字符串
  6. ch02-1880-2010年间全美婴儿姓名
  7. iOS 手写键盘与触摸手势冲突,导致崩溃闪退
  8. 区块链技术中的那些能商用的企业级应用
  9. 赛联区块链教育为潍柴动力提供区块链技术培训
  10. 零插件sketchup草图大师su逆向建模“世纪钟”雕塑