中秋接月饼

news2024/11/27 9:52:31

请添加图片描述
hellow大家好,中秋佳节到了,欢乐度节的同时,技术也要跟上呀,这次我们通过canvas实现一个中秋接月饼的小游戏,三连不迷路哦~

展示一下游戏成品:
请添加图片描述

准备游戏背景

首先我们将游戏背景界面绘制出来。
游戏背景界面由一个游戏窗口和两个装饰元素组成。
请添加图片描述

<template>
  <div class="canvasBar">
    <canvas
      id="myCanvas"
      width="900"
      height="600"
      style="background-color: #dc181b; border-radius: 20px"
    ></canvas>
    <img class="icon1" src="../assets/test/icon2.gif" alt="" />
    <img class="icon2" src="../assets/test/icon1.png" alt="" />
  </div>
</template>
.canvasBar {
  background-color: #f9c245;
  position: relative;
  width: 1100px;
  margin-top: 70px;
  padding: 15px 0;
  .icon1 {
    position: absolute;
    top: 0px;
    left: 90px;
    width: 300px;
  }
  .icon2 {
    position: absolute;
    bottom: -24px;
    right: 80px;
    width: 200px;
  }
}

游戏背景就完成了,是不是很有节日气氛呢?
接下来我们绘制从天而降的月饼(因为我们是接月饼游戏嘛~)

绘制一个月饼

我们先绘制一个静态的月饼到界面上试试水。
首先我们使用 document.querySelector(“#myCanvas”)获取到刚刚的 canvas 元素,然后使用 canvas.getContext(“2d”)获取 2d 画笔,使用最后使用 drawImage 函数将月饼图片绘制到界面上。

注意,drawImage 四个参数分别为:Image 对象(需要使用 new Image()获取并为 src 赋值)、left 值、top 值、宽度、高度。

请添加图片描述

let ctx;
function init() {
  let canvas = document.querySelector("#myCanvas");
  ctx = canvas.getContext("2d");
  draw();
}
function draw() {
  let img = new Image();
  img.src = new URL("../assets/test/moonCake1.png", import.meta.url).href;
  ctx.drawImage(img, 300, 40, 90, 90);
}

一个月饼完成啦。

一个下落的月饼

我们计划除了月饼还可能降落一些其他玩意儿,比如炸弹、锦囊之类的道具。

所以这里写两个类,一个是降落物品类(里面包含降落函数和降落速度),一个是月饼类(里面包含月饼图片)和月饼位置。
这里月饼类继承了降落物品类。因为它是个会降落的月饼。

请添加图片描述

...
class FallReward {
  basePace = 500;
  fallDown() {
    this.top = this.top + 10;
    setTimeOut(() => {
      this.fallDown();
    }, this.basePace);
  }
}

class MoonCake extends FallReward {
  constructor({ left, top = 0, src }) {
    super();
    this.top = top;
    this.left = left;
    this.img = new Image();
    this.img.src = src;
    this.fallDown();
  }
}
...

上面我们写好了 2 个类,FallReward 类中,有下落 10 的的间隔时间(默认 500,后续越来快,该时间也越来越小),和下落方法(一旦触发该方法物品将一直下落。)
MoonCake 类继承了 FallReward 类,同时描述了物品的具体位置和图片,也就是在这个类中,准备好了要绘制的一切参数,并且触发了下落。

然后我们使用 MoonCake 类构建一个下落的月饼实例,并且绘制到屏幕上。

因为绘制的部分会越来越复杂,我们将绘制的部分放置在 draw 方法中。

let ctx;
function init() {
  let canvas = document.querySelector("#myCanvas");
  ctx = canvas.getContext("2d");
  draw();
}

let moonObj = new MoonCake({
  left: 300,
  src: new URL("../assets/test/moonCake1.png", import.meta.url).href,
});

function draw() {
  ctx.clearRect(0, 0, 900, 600); // 清空画布 如不调用
  ctx.drawImage(moonObj.img, moonObj.left, moonObj.top, 80, 80);
  requestAnimationFrame(draw); // 触发重绘
}

init();

这里有 3 个要点:

  1. 在 moonObj 中的 src 参数使用了 new URL 的句式,不懂的朋友可以在下面留言或者点点 ♥♥。这里是因为博主使用了 vite 框架,在引入图片的时候这样写,如果是 webpack 框架,就可以采用 require(…)来引入。
  2. clearRect 函数,不清楚这个作用的同学也可以 ♥♥ 点起来。这里是将之前绘制的清空,然后重新绘制,下落的月饼实际是由于无数个不同坐标的月饼组成,如果不在每次绘制前清空,下落轨迹会留下一串月饼。
  3. requestAnimationFrame 函数,在屏幕的每个刷新时刻调用,可以看作 setIntervel 升级版。

会降落的月饼就画好啦。

一群下落的月饼

游戏是接月饼,当然不能接完一个月饼就结束啦,要有很多月饼随机的往下掉。
这里的随机指的是横向位置随机和产生数量随机,纵向位置是固定的:都是从最上方开始掉落。

请添加图片描述

接下来我们绘制一群下落的月饼。

在 draw 函数中,我们要让所有的月饼一起下落,可以将所有的月饼实例维护在一个列表中,然后再 draw 中绘制列表中的所有月饼当前的位置。

刚刚月饼实例在创建的时候就已经触发了不断下落的周期性变更内部属性的函数,所以在 draw 函数中只要遍历列表进行绘制即可。

...
function draw() {
  ctx.clearRect(0, 0, 900, 600); // 清空画布
  getMoonList.forEach((moonObj) => {
    ctx.drawImage(moonObj.img, moonObj.left, moonObj.top, 80, 80);
  })
  requestAnimationFrame(draw); // 触发重绘
}
...

接下来创建月饼实例列表 getMoonList,该列表周期性的填入一批数量随机的月饼。

function init() {
  let canvas = document.querySelector("#myCanvas");
  ctx = canvas.getContext("2d");
  setMoonList()
  setInterval(() => {
    setMoonList()
  }, 5000)
  draw();
}

...
let getMoonList = [];

let setMoonList = () => {
  for (let i = 0; i < Math.round(Math.random() * 4); i++) {
    getMoonList.push(
      new MoonCake({
        left: Math.round(Math.random() * 700),
        src: new URL("../assets/test/moonCake1.png", import.meta.url).href,
      })
    );
  }
};
...

从上面的代码中可以看到,getMoonList 周期性的填入数量 0-5 个月饼,位置为 left 0-700。

一批下落的月饼就写好啦。

接月饼的篮子

然后我们放置一个篮子来接月饼,篮子如果接到了月饼,分数就+1。
篮子只能在窗口底部活动,所以 bottom 为 0。

篮子使用键盘左右按键来控制。

请添加图片描述

绘制篮子,还是创建一个类,然后再 flaw 中绘制,篮子类和月饼类的区别就是位置不同,也没有下落功能。

...
class Basket {
  constructor({ left, top = 490, src }) {
    this.top = top;
    this.left = left;
    this.img = new Image();
    this.img.src = src;
  }
}
let basket = new Basket({
  left: 350,
  src: new URL("../assets/test/basket.png", import.meta.url).href,
});
...
function draw() {
  ctx.clearRect(0, 0, 900, 600); // 清空画布
  getMoonList.forEach((moonObj) => {
    ctx.drawImage(moonObj.img, moonObj.left, moonObj.top, 80, 80);
  });
  ctx.drawImage(basket.img, basket.left, basket.top, 150, 120); // 这行是新加的
  requestAnimationFrame(draw); // 触发重绘
}
...

这时篮子就出现在游戏界面了,然后为篮子添加键盘监听,在监听到键盘左右键时,改变篮子的位置。

...
class Basket {
  constructor({ left, top = 490, src }) {
    this.top = top;
    this.left = left;
    this.img = new Image();
    this.img.src = src;

    document.addEventListener("keydown", (event) => {
      if(event.code === 'ArrowLeft') {
        this.left = this.left - 20
      } else if(event.code === 'ArrowRight') {
        this.left += 20
      }
    });
  }
}
...

这样,一个可以用键盘控制移动的篮子就做好啦。

分数记录

接到月饼,就要记录分数啦。我们在界面上添加一个分数牌用来展示分数。

分数可以在月饼坐标改变的时候,计算其与篮子是否重合,具体算法是当月饼 top 值小于篮子 top 值时,月饼的 left 值是否在篮子 left 值-篮子 left 加篮子宽度减月饼宽度范围内,如果符合条件,则加一分。

分值展示在界面左下角。

请添加图片描述

首先在月饼类和下落类中添加分值 scoreSpace,下落类分值默认为 0,月饼类中分值修改为 1.
在下落类的下落函数中添加判断。

且月饼掉入篮子后就隐藏了,一个月饼只记一分。这里添加 display 标志位。

let scoreNum = ref(0) // vue3语法,可以更方便的将scoreNum绑定到界面 也可以使用document获取元素的方式为界面赋值![请添加图片描述](https://img-blog.csdnimg.cn/30fdb2fcebe54d44926641256270c46a.gif)

class FallReward {
  ...
  scoreSpace = 0
  display = false
  fallDown() {
    ...
    if(this.top > basket.top && this.top < basket.top + 80 && this.left > basket.left && this.left < basket.left + 70 && !this.display) {
      scoreNum.value = scoreNum.value + this.scoreSpace
      this.display = true
    }
    setTimeout(() => {
      this.fallDown();
    }, this.basePace);
  }
}
class MoonCake extends FallReward {
  constructor({ left, top = 0, src }) {
    ...
    this.scoreSpace = 1
  }
}

function draw() {
  ctx.clearRect(0, 0, 900, 600);
  getMoonList.forEach((moonObj) => {
    if(!moonObj.display) { // 已经接到的话就不展示啦
      ctx.drawImage(moonObj.img, moonObj.left, moonObj.top, 80, 80);
    }
  });
  ctx.drawImage(basket.img, basket.left, basket.top, 150, 120);
  requestAnimationFrame(draw);
}

scoreNum.value(vue3 访问方式)的值就是分值啦。

然后我们将分值展示在界面左下角。

...
<div class="scoreCard">
  <img class="scoreIcon" src="../assets/test/moonCake1.png" alt="" />× {{
  scoreNum }}
</div>
...
...
.scoreCard {
  text-align: left;
  margin-left: 110px;
  display: flex;
  align-items: center;
  margin-top: -50px;
  .scoreIcon {
    width: 40px;
  }
}
...

游戏结束

到这一步,游戏主体就完成啦!但是游戏还没有终点,我们可以通过在界面中掉落炸弹的方式来结束游戏。

炸弹如何添加呢?在哪里判断是否接到了炸弹呢?
这作为大家的一个思考题,欢迎大家在评论中秀出你的炸弹代码。

思考题结果会在晚一点之后补充到评论区,在此之前请大家踊跃思考吧!

此外,大家对增加游戏的趣味性还有什么建议呢?也欢迎大家补充到评论区哦,有趣的游戏创意可能被翻牌到下一章节哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1028868.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

滚雪球学Java(37):深入了解Java方法作用域和生命周期,让你写出更高效的代码

&#x1f3c6;本文收录于「滚雪球学Java」专栏&#xff0c;专业攻坚指数级提升&#xff0c;助你一臂之力&#xff0c;带你早日登顶&#x1f680;&#xff0c;欢迎大家关注&&收藏&#xff01;持续更新中&#xff0c;up&#xff01;up&#xff01;up&#xff01;&#xf…

微信重磅更新!有人已经涨粉好几万了!

公众号又更新了。 一个是发布功能升级&#xff0c;新发布的内容将展示在公众号主页&#xff0c;并有机会获得平台推荐。但仍然不会推送给用户&#xff0c;这是除了次数以外&#xff0c;和群发文章仅有的区别了。 ▲ 图片来源&#xff1a;微信公众号平台 不过目前仅支持用网页…

Android调用相机拍照,展示拍摄的图片

调用相机&#xff08;隐式调用&#xff09; //自定义一个请求码 这里我设为10010int TAKE_PHOTO_REQUEST 10010;int RESULT_CANCELED 0;//定义取消码//触发监听&#xff0c;调用相机image_camera.setOnClickListener(new View.OnClickListener() {Overridepublic void onCli…

Network: use `--host` to expose

vite 启动项目提示 Network: use --host to expose 同事不能通过本地IP地址访问项目 解决方案&#xff1a;package.json中启动命令配置本地IP地址 vite --host 192.168.200.252

windows11中安装curl

windows11中安装curl 1.下载curl curl 下载地址&#xff1a;curl 2.安装curl 2.1.解压下载的压缩包 解压文件到 C:\Program Files\curl-8.3.0_1-win64-mingw 目录 2.2.配置环境变量 WINS 可打开搜索栏&#xff0c;输入“编辑系统环境变量” 并按回车。 3.可能遇到的问题 3…

天地图绘制区域图层

背景&#xff1a; 业务方要求将 原效果图 参考效果图 最终实现效果 变更点&#xff1a; 1.将原有的高德地图改为天地图 2.呈现形式修改&#xff1a;加两层遮罩&#xff1a;半透明遮罩层mask区域覆盖物mask 实现过程&#xff1a; 1.更换地图引入源 <link rel"style…

BI系统上的报表怎么导出来?附方法步骤

在BI系统上做好的数据可视化分析报表&#xff0c;怎么导出来给别人看&#xff1f;方法有二&#xff0c;分别是1使用报表分享功能&#xff0c;2使用报表导出功能。下面就以奥威BI系统为例&#xff0c;简明扼要地介绍这两个功能。 1、报表分享功能 作用&#xff1a; 让其他同事…

SqlServer备份与还原 System.Data.SqlClient.SqlError: 媒体集有 2 个媒体簇,但只提供了 1 个。必须提供所有成员

System.Data.SqlClient.SqlError: 媒体集有 2 个媒体簇,但只提供了 1 个。必须提供所有成员。 (Microsoft.SqlServer.Smo) 这是由于你备份时&#xff0c;没有去掉默认的C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Backup\数据库名.bak&#xff0c;而又添加了一个新路…

【扩散生成模型】Diffusion Generative Models

提出扩散模型思想的论文&#xff1a; 《Deep Unsupervised Learning using Nonequilibrium Thermodynamics》理解 扩散模型综述&#xff1a; “扩散模型”首篇综述论文分类汇总&#xff0c;谷歌&北大最新研究 理论推导、代码实现&#xff1a; What are Diffusion Models?…

【办公小神器】:快速批量转换Word、Excel、PPT为PDF脚本!

文章目录 ✨哔哩吧啦✨脚本使用教程✨温馨小提示设置&#x1f4da;资源领取 专栏Python零基础入门篇&#x1f525;Python网络蜘蛛&#x1f525;Python数据分析Django基础入门宝典&#x1f525;小玩意儿&#x1f525;Web前端学习tkinter学习笔记Excel自动化处理 ✨哔哩吧啦 前…

Linux 安装 git

一 . 安装git 方式1&#xff1a;通过yum 安装 yum -y install git查看是否安装成功 git --version安装目录在&#xff1a;/usr/libexec/git-core yum 安装有一些缺点 &#xff1a;不能自己指定安装目录、安装版本 方式 2 下载tar.gz 包 配置 查看git 版本&#xff1a;Index…

windows11专业版下安装ubuntu20终端应用

主要步骤如下&#xff1a; https://blog.csdn.net/i_ziyu/article/details/127603934 https://blog.csdn.net/qq_17525509/article/details/122287051 搜索windows功能&#xff1a; 在设置里面&#xff1a; 设置–更新和安全–开发者选项 打开开发者模式。 去应用商店下载&a…

ChatGPT实战-构建文章分析AI聊天机器人

视频版本&#xff1a; ChatGPT实战-构建文章分析AI聊天机器人 简介 本文实现如下功能&#xff1a; 当浏览一篇文章&#xff0c;点击分享&#xff0c;分享到聊天软件的对话框中。它就会生成一个文章的总结和分析结果。例如分析是否有逻辑问题&#xff0c;是否有诱导购买&#…

基于SSM+Vue的在线购书商城系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

浅谈 React 与 Vue 更新机制的差异

前言 哈喽&#xff0c;大家好&#xff0c;我是 Baker &#xff01;&#x1f389; 对于前端的 Vue 和 React 相信大家并不陌生&#xff0c;这两个库有着截然不同的设计思想和发展目标&#xff0c;对于我们上层使用者来说&#xff0c;研究它们的差异不仅让我们更加深入的去理解…

使用自定义插槽(slot)来将数据传递给插槽内容。el-step

description为描述性文字&#xff0c;需使用slot来自定义文字。 A 是 Vue 3 中的语法糖&#xff0c;用于简洁地定义插槽。用来绑定step组件中description。step可使用插槽 B是绑定date数据实现自定义描述文字。

VoxWeekly|The Sandbox 生态周报|20230918

欢迎来到由 The Sandbox 发布的《VoxWeekly》。我们会在每周发布&#xff0c;对上一周 The Sandbox 生态系统所发生的事情进行总结。 如果你喜欢我们内容&#xff0c;欢迎与朋友和家人分享。请订阅我们的 Medium 、关注我们的 Twitter&#xff0c;并加入 Discord 社区&#xf…

linux安装配置 flume

目录 一 解压安装包 二 配置部署 &#xff08;1&#xff09;修改配置 &#xff08;2&#xff09;下载工具 &#xff08;3&#xff09;创建配置文件 &#xff08;4&#xff09;启动监听测试 &#xff08;5&#xff09;flume监控文件 一 解压安装包 这里提供了网盘资源 链…

狂热过后,RPA到底是什么?

随着科技的不断进步&#xff0c;人工智能正在逐步渗透到各个领域&#xff0c;并不断演变&#xff0c;成为更加便捷的方式步入万家&#xff0c;让科技的变革的春风吹入了千行百业&#xff0c;落入千家万户。而“RPA”&#xff08;Robotic Process Automation&#xff0c;即机器人…

视频去LOGO的方法,AI自动完美地去除视频LOGO

喜欢做影视剧剪辑的朋友&#xff0c;可能会遇到下载的影视剧本身存在字幕、台标的情况&#xff0c;这些和新的剪辑主题不相符的原片元素&#xff0c;都会影响我们最终的成片效果。不过也无需烦恼哦&#xff0c;我们可以利用AI视频处理工具&#xff0c;自动去除视频中的logo或其…