• 售前

  • 售后

热门帖子
入门百科

VUE+Canvas实现财神爷接元宝小游戏

[复制链接]
萍381 显示全部楼层 发表于 2021-10-26 13:59:18 |阅读模式 打印 上一主题 下一主题
之前的canvas小游戏系列接待各人戳:
《VUE实现一个Flappy Bird~~~》
《猜单词游戏》
《VUE+Canvas 实现桌面弹球消砖块小游戏》
《VUE+Canvas实现雷霆战机打字类小游戏》
如标题,这个游戏各人也玩过,随处可见,左右方向键控制财神移动,接住从天而降的金元宝等,时间一到,则游戏结束。先来看一下结果:

相比于之前的雷霆战机要打出到处飞的子弹,这次元素的运动轨迹就很单一了,垂直方向的珠宝和程度移动的财神爷,类似于之前的代码,这里就说一下关键步调点吧:
1、键盘控制程度移动的财神爷
这个很简单,同理于《VUE+Canvas 实现桌面弹球消砖块小游戏》滑块的控制:
  1. drawCaishen() {
  2.       let _this = this;
  3.       _this.ctx.save();
  4.       _this.ctx.drawImage(
  5.         _this.caishenImg,
  6.         _this.caishen.x,
  7.         _this.caishen.y,
  8.         120,
  9.         120
  10.       );
  11.       _this.ctx.restore();
  12. },
  13. moveCaishen() {
  14.       this.caishen.x += this.caishen.dx;
  15.       if (this.caishen.x > this.clientWidth - 120) {
  16.         this.caishen.x = this.clientWidth - 120;
  17.       } else if (this.caishen.x < 0) {
  18.         this.caishen.x = 0;
  19.       }
  20. }
复制代码
2、从天而降的珠宝
这个也很简单,但要留意的是,珠宝的初始x值不能随机取0~clientWidth了,因为如许很轻易造成珠宝堆积在一起,影响了游戏的可玩性,所以珠宝最好是分散在差别的轨道上,这里我们把画布宽度分为5条轨道,初始珠宝的时间,我们就把珠宝分散在轨道上,而且y值随机在肯定高度造成参差。而后新生成的珠宝都依据轨道分布来生成,克制珠宝挤在一起。
  1. generateTreasure() {
  2.       let _this = this;
  3.       if (_this.treasureArr.length < MaxNum) {
  4.         let random = Math.floor(Math.random() * TreasureNames.length);
  5.         let channel = _this.getRandomArbitrary(1, 5);
  6.         _this.treasureArr.push({
  7.           x: _this.channelWidth * (1 / 2 + (channel - 1)) - 30,
  8.           y: 0,
  9.           name: TreasureNames[random],
  10.           speed: _this.getRandomArbitrary(2, 4)
  11.         });
  12.       }
  13. },
  14. filterTreasure(item) {
  15.       let _this = this;
  16.       if (
  17.         item.x <= _this.caishen.x + 110 &&
  18.         item.x >= _this.caishen.x &&
  19.         item.y > _this.caishen.y
  20.       ) {
  21.         // 判断和财神的触碰范围
  22.         _this.score += _this.treasureObj[item.name].score;
  23.         return false;
  24.       }
  25.       if (item.y >= _this.clientHeight) {
  26.         return false;
  27.       }
  28.       return true;
  29. },
  30. drawTreasure() {
  31.       let _this = this;
  32.       _this.treasureArr = _this.treasureArr.filter(_this.filterTreasure);
  33.       _this.treasureArr.forEach(item => {
  34.         _this.ctx.drawImage(
  35.           _this.treasureObj[item.name].src,
  36.           item.x,
  37.           item.y,
  38.           60,
  39.           60
  40.         );
  41.         item.y += item.speed;
  42.       });
  43. },
  44. getRandomArbitrary(min, max) {
  45.       return Math.random() * (max - min) + min;
  46. }
复制代码
这里用filter函数过滤掉应该消散的珠宝,如果用for+splice+i--的方法会造成抖动。
然后给予每个珠宝随机的运动速度,当珠宝进入财神爷的图片范围时则累加相应分数。
3、倒计时圆环
设置倒计时30s,那么在requestAnimationFrame的回调里盘算当前时间与前次时间戳毫秒差值是否大于1000,实现秒的盘算,然后取另一时间戳累加progress,实现圆环的平滑移动。
  1. drawCountDown() {
  2.       // 画进度环
  3.       let _this = this;
  4.       _this.progress += Date.now() - _this.timeTag2;
  5.       _this.timeTag2 = Date.now();
  6.       _this.ctx.beginPath();
  7.       _this.ctx.moveTo(50, 50);
  8.       _this.ctx.arc(
  9.         50,
  10.         50,
  11.         40,
  12.         Math.PI * 1.5,
  13.         Math.PI * (1.5 + 2 * (_this.progress / (countDownInit * 1000))),
  14.         false
  15.       );
  16.       _this.ctx.closePath();
  17.       _this.ctx.fillStyle = "yellow";
  18.       _this.ctx.fill();
  19.       // 画内填充圆
  20.       _this.ctx.beginPath();
  21.       _this.ctx.arc(50, 50, 30, 0, Math.PI * 2);
  22.       _this.ctx.closePath();
  23.       _this.ctx.fillStyle = "#fff";
  24.       _this.ctx.fill();
  25.       // 填充文字
  26.       _this.ctx.font = "bold 16px Microsoft YaHei";
  27.       _this.ctx.fillStyle = "#333";
  28.       _this.ctx.textAlign = "center";
  29.       _this.ctx.textBaseline = "middle";
  30.       _this.ctx.moveTo(50, 50);
  31.       _this.ctx.fillText(_this.countDown + "s", 50, 50);
  32.     }
复制代码
  1. (function animloop() {
  2.         _this.ctx.clearRect(0, 0, _this.clientWidth, _this.clientHeight);
  3.         _this.loop();
  4.         animationId = window.requestAnimationFrame(animloop);
  5.         if (_this.countDown === 0) {
  6.           _this.gameOver = true;
  7.           window.cancelAnimationFrame(animationId);
  8.         }
  9.         if (Date.now() - _this.timeTag >= 1000) {
  10.           _this.countDown--;
  11.           _this.timeTag = Date.now();
  12.         }
  13. })();
复制代码
至此,一个非常简单的财神爷接元宝的小游戏就完成了,固然可以为了增长难度,设置不制止地丢炸弹这一环节,原理同珠宝的运动是一样的。
下面还是附上全部代码,供各人参考学习:
  1. <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() {
  2.       // 画进度环
  3.       let _this = this;
  4.       _this.progress += Date.now() - _this.timeTag2;
  5.       _this.timeTag2 = Date.now();
  6.       _this.ctx.beginPath();
  7.       _this.ctx.moveTo(50, 50);
  8.       _this.ctx.arc(
  9.         50,
  10.         50,
  11.         40,
  12.         Math.PI * 1.5,
  13.         Math.PI * (1.5 + 2 * (_this.progress / (countDownInit * 1000))),
  14.         false
  15.       );
  16.       _this.ctx.closePath();
  17.       _this.ctx.fillStyle = "yellow";
  18.       _this.ctx.fill();
  19.       // 画内填充圆
  20.       _this.ctx.beginPath();
  21.       _this.ctx.arc(50, 50, 30, 0, Math.PI * 2);
  22.       _this.ctx.closePath();
  23.       _this.ctx.fillStyle = "#fff";
  24.       _this.ctx.fill();
  25.       // 填充文字
  26.       _this.ctx.font = "bold 16px Microsoft YaHei";
  27.       _this.ctx.fillStyle = "#333";
  28.       _this.ctx.textAlign = "center";
  29.       _this.ctx.textBaseline = "middle";
  30.       _this.ctx.moveTo(50, 50);
  31.       _this.ctx.fillText(_this.countDown + "s", 50, 50);
  32.     },    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实现财神爷接元宝小游戏的文章就介绍到这了,更多相干vue接元宝游戏内容请搜索脚本之家从前的文章或继续欣赏下面的相干文章希望各人以后多多支持脚本之家!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作