LCODER之微信小游戏开发:一、微信小游戏基础知识

356 阅读7分钟

一、注册开发者账号

自行查阅微信开发者文档。

二、创建自己的第一个微信小游戏

自行查阅微信开发者文档。创建完后,得到第一个默认的小飞机游戏。如图所示:

image.png

三、微信小游戏项目结构

在上一小节,我们创建了自己的第一个微信小游戏,也就是微信开发者工具给我们自动创建的小飞机游戏。首先我们来认识一下小飞机游戏的项目结构。小飞机的项目结构如下图所示。

1746841943077.png

源码目录介绍
├── audio                                      // 音频资源
├── images                                     // 图片资源
├── js
│   ├── base
│   │   ├── animatoin.js                       // 帧动画的简易实现
│   │   ├── pool.js                            // 对象池的简易实现
│   │   └── sprite.js                          // 游戏基本元素精灵类
│   ├── libs
│   │   └── tinyemitter.js                     // 事件监听和触发
│   ├── npc
│   │   └── enemy.js                           // 敌机类
│   ├── player
│   │   ├── bullet.js                          // 子弹类
│   │   └── index.js                           // 玩家类
│   ├── runtime
│   │   ├── background.js                      // 背景类
│   │   ├── gameinfo.js                        // 用于展示分数和结算界面
│   │   └── music.js                           // 全局音效管理器
│   ├── databus.js                             // 管控游戏状态
│   ├── main.js                                // 游戏入口主函数
│   └── render.js                              // 基础渲染信息
├── .eslintrc.js                               // 代码规范
├── game.js                                    // 游戏逻辑主入口
├── game.json                                  // 游戏运行时配置
├── project.config.json                        // 项目配置
└── project.private.config.json                // 项目个人配置
game.json文件

该文件为小游戏的配置文件,在其中可以配置“deviceOrientation”、“showStatusBar”等属性,如下所示:

{
  "deviceOrientation": "portrait",  // 设定屏幕方向
  "showStatusBar": false // 是否显示系统状态栏
}

JS 是官方指定的小游戏开发语言,微信内置了一个JS VM,这是一个与浏览器、Node.js类似的宿主环境。不同于浏览器,JS VM没有BOM API和DOM API,只有微信提供的wx API。这些wx API是运行小游戏的关键。wx API在小游戏开发中肩负着创建画布,绘制图形、显示图片、以及如何响应用户交互等基础功能。

四、小游戏开发的基础知识

创建画布

在小游戏中,创建画布使用的是wx.createCanvas这个接口,第一个被创建的是上屏画布,尺寸默认与设备当前的屏幕尺寸相同。在小程序运行时,首次调用wx.createCanvas()接口创建的画布就是上屏画布。在这个画布上绘制的内容都将显示在屏幕上。第二次,第三次以及后面创建的画布则是离屏画布,离屏画布上绘制的内容默认不会显示在屏幕上。离屏画布不能显示,但可以获取属性。

// let var 声明变量关键字
let canvas  = wx.createCanvas()
console.log(canvas.height,canvas.width)
绘制矩形

我们可以使用canvas.getContext('2d') 获取2D渲染上下文对象Rendering-Context ,使用Rendering-Context对象的fillRect方法绘制几何图形。如下面的代码所示:

// 绘制矩形
let context = canvas.getContext("2d") // 获取2D渲染上下文对象Rendering-Context 
context.fillStyle = "red"  // 填充颜色为红色
context.fillRect(0,0,100,100) // 绘制矩形

使用以上的代码,我们可以在画布上坐标为(0,0)的位置绘制出一个填充色为红色,尺寸为100*100的矩形。

1746846648241.png

小游戏中的作用域

在上面的示例代码中,canvas和context是两个变量,这两个变量在game.js文件中的任何位置都可以访问,它们是当前文件作用域下的文件变量。 在小游戏中,共有六种作用域,它们分别是:

  1. 区块作用域 : 在花括号内定义的作用域,相关变量称为区块变量。
  2. 函数/方法作用域:在一个函数之内皆可访问的作用域,相关变量称为函数变量
  3. 类作用域:在一个类中使用,只要使用this修饰符皆可访问的作用域,相关变量称为类变量。
  4. 文件作用域:当前文件之内皆可访问的作用域,相关变量称为文件变量,例如上面的canvas和context。
  5. 全局作用域:在当前项目内的任何文件内皆可访问的作用域,相关变量称为全局变量。
  6. 开放数据域:只能在指定目录下的JS文件中才能访问的作用域。开放数据域是微信小程序和小游戏独有的,是一个封闭的,独立的JS作用域。

前五个作用域的可访问范围是从小到大依次排列的,这是HTML5和小游戏都具有的作用域。最后一个开放作用域是小游戏/小程序专有的,微信为避免微信好友关系链数据被不法商家滥用,专门创造了一个开放数据域的概念,微信好友关系链数据只能在这个开放数据域下拉取和展示,无法传出及向第三方数据库转存。

在小游戏中,如果想定义全局变量,可以使用GameGlobal的全局对象。示例代码如下:

GameGlobal.canvas = wx.createCanvas()
GameGlobal.context = canvas.getContext("2d")

上面的canvas和context均为全局变量,在小游戏项目中任何JS文件中均可以访问到。

清空画布

在小游戏中,调用Rendering-Context的clearRect方法可以清空画布,重新设置画布的宽和高也可以清空画布。

首先看一下重置画布宽高的方法,示例代码如下:

canvas.width = canvas.width
canvas.height = canvas.height

重置画布宽高后,重新编译,会发现刚才创建的红色矩形不见了,这就是因为画布发生了重置而清空了画布。

再来看一下使用RenderingContext的clearRect方法清空画布,示例代码如下:

context.clearRect(0,0,canvas.width,canvas.height)

使用这种方法也可以达到清空画布的效果。

绘制网络图片

使用接口wx.createImage创建图像对象,并用这个图像对象加载网络图片,网络图片的加载需要一定的时间,因此我们给image添加一个onload回调,当图片加载完成时回调,在该回调里使用RenderingContext的drawImage方法将图像转绘到画布上。

let image = wx.createImage()
image.src = "https://wx3.sinaimg.cn/mw690/88e90961ly1hwvqdknjo4j20u0140tav.jpg"
// onload回调监听,当图像加载完成回调,在回调里绘制图片
image.onload = function(){
  context.drawImage(image,0,0)
}

一般在小游戏/小程序中,对普通HTTPS请求(wx.request)、上传文件(wx.uploadFile)、下载文件(wx.downloadFile)和 WebSocket通信(wx.connectSocket)都有域名检验,对于未在后台配置的域名则不允许访问,但使用图像组件(Image)加载网络图片不受域名校验限制。

src属性也可以加载本地图片,把src属性设置为本地图片路径即可。

实现动画

动画其实就是静态图片的快速叠加和切换,在小游戏中通过以下一系列方法实现动画效果:

  • setInterval : 设置间隔定时器
  • setTimeout : 设置延时定时器
  • requestAnimationFrame : 开启帧重绘函数
  • clearInterval : 清除间隔定时器
  • clearTimeout : 清除延时定时器
  • cancelAnimationFrame : 取消帧重绘

使用requestAnimationFrame创建动画,效率上优于setInterval和setTimeout,此外,在小游戏中使用wx.setPreferredFramesPerSecond接口可以修改帧频。使用requestAnimationFrame创建一个逐渐增加图片Y坐标的动画,每次执行前都是先清屏,擦去已经绘制的旧图片,再将图片绘制在画布上。

let image = wx.createImage()
image.src = "https://wx3.sinaimg.cn/mw690/88e90961ly1hwvqdknjo4j20u0140tav.jpg"
// onload回调监听,当图像加载完成回调,在回调里绘制图片
image.onload = function(){
  context.drawImage(image,0,0)
  moveDownImage()
}

let imagePositionY = 0
function moveDownImage(){
  // 清屏
  context.clearRect(0,0,canvas.width,canvas.height)
  // 重绘 每次都将图片的y坐标 + 1
  context.drawImage(image,0,imagePositionY++)
  // 循环
  requestAnimationFrame(moveDownImage)
}
实现人机交互

在小游戏中,使用wx.onTouchMove API监听触摸移动事件,并通过Touch对象的screenX、screenY属性获取触摸点坐标信息。我们通过监听触摸事件,并在回调事件中擦拭与重绘画布,就可以实现界面交互。

在小游戏中,监听触摸事件的方法有以下几个:

  • wx.onTouchStart : 监听触摸开始
  • wx.onTouchMove: 监听触摸移动
  • wx.onTouchEnd : 监听触摸结束
  • wx.onTouchCancel: 监听触摸取消

小游戏的触摸事件是多指触控,e.touches返回的是一个Touch对象数组,如下面的代码所示:

let image = wx.createImage()
image.src = "https://wx3.sinaimg.cn/mw690/88e90961ly1hwvqdknjo4j20u0140tav.jpg"
// onload回调监听,当图像加载完成回调,在回调里绘制图片
image.onload = function(){
  context.drawImage(image,0,0)
}

wx.onTouchMove((result) => {
  let touch = result.touches[0]
  context.clearRect(0,0,canvas.width,canvas.height)
  context.drawImage(image,touch.clientX,touch.clientY)
})

我们取Touch对象数组的第一个元素,取其clientX,clientY属性,这两个属性代表触摸点的本地坐标,使用该坐标重绘图片,就实现了图片跟随手指移动的效果。