微信小游戏入门(四)

在本系列的上一篇文章中,我们介绍了在小游戏中使用 requestAnimationFrame 函数来控制界面更新频率的方法。本文将要使用该技术让游戏背景动起来。

构造可视基类 - Sprite

在多数的GUI系统中都会构造一个可视基类,用来封装可视对象的基本行为和属性。在案例中,构造了一个 Sprite 作为可视基类。

在 js 目录下新建名为 base 的目录,在 base 目录中新建一个名为: sprite.js 的文件。 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export default class Sprite {

constructor(imgSrc = '', width = 0, height = 0, x = 0, y = 0) {
this.img = new Image()
this.img.src = imgSrc

this.width = width
this.height = height

this.x = x
this.y = y

this.visible = true
}

}

可以看到,我们使用了 ES6 的 class 关键字来构建了一个名为: Sprite 的类,因为在游戏中,每个可视化的对象都有一张对应的图片,都具有一定的大小(width, height)和位置(x, y), 因此我们将这些公共的属性都定义在 Sprite 类中。

构造背景图类

在 js/runtime 目录中新建一个名为: background.js 的文件,用来保存背景图像类。

定义上背景图类: BackGround,我们让背景图类继承于 Sprite, 对应的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const BG_IMG_SRC = 'images/bg.jpg'
const BG_WIDTH = 512
const BG_HEIGHT = 512

export default class BackGround extends Sprite {

constructor(ctx) {
super(BG_IMG_SRC, BG_WIDTH, BG_HEIGHT)

this.top = 0

....
}
}

在 BackGround 中增加了一个 top 属性,用来记录显示时的起始纵坐标, 并将用于画图的 Context 对象作为参数传给 BackGround。

按照 上一篇文章 中介绍的框架,我们将属性的更新和对象的显示分别封装在 update() 和 render 方法中,因此在 BackGround 中实现这两个方法如下:

1
2
3
4
5
6
7
update() {
this.top += 2

if (this.top >= screenHeight) {
this.top = 0
}
}

update 方法用来在刷新周期中计算新的 y 坐标,以是的背景有不断向前移动的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
render(ctx) {

ctx.drawImage(
this.img,
0,
0,
this.width,
this.height,
0,
-screenHeight + this.top,
screenWidth,
screenHeight
)

ctx.drawImage(
this.img,
0,
0,
this.width,
this.height,
0,
this.top,
screenWidth,
screenHeight
)
}

在 render 方法中,连续画了两次背景图,但 y 坐标不同,主要时实现背景无限滚动向前的效果。

完整的 background.js 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import Sprite from '../base/sprite.js'


const screenWidth = window.innerWidth
const screenHeight = window.innerHeight

const BG_IMG_SRC = 'images/bg.jpg'
const BG_WIDTH = 512
const BG_HEIGHT = 512


export default class BackGround extends Sprite {

constructor(ctx) {
super(BG_IMG_SRC, BG_WIDTH, BG_HEIGHT)

this.top = 0

this.render(ctx)
}

update() {
this.top += 2

if (this.top >= screenHeight) {
this.top = 0
}
}

render(ctx) {

ctx.drawImage(
this.img,
0,
0,
this.width,
this.height,
0,
-screenHeight + this.top,
screenWidth,
screenHeight
)

ctx.drawImage(
this.img,
0,
0,
this.width,
this.height,

让背景动起来

为了让背景动起来,我们将写好的 BackGround 类加入到主程序 main.js 中。

首先,在 Main 中增加一个属性:

1
this.bg = new BackGround(ctx)

然后在 update 方法中调用背景对象的 update 方法类更新背景属性:

1
this.bg.update()

再在 render 方法中画背景:

1
this.bg.render(ctx)

现在,保存程序就可以看到一个不断滚动的背景了。

完整的 main.js 程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import BackGround from './runtime/background'

let ctx = canvas.getContext('2d')

/**
* 游戏主函数
*/
export default class Main {
constructor() {
this.aniId = 0

this.bg = new BackGround(ctx)

this.bindLoop = this.loop.bind(this)

this.restart()
}

restart() {
window.cancelAnimationFrame(this.aniId);

this.aniId = window.requestAnimationFrame(
this.bindLoop,
canvas
)
}


render() {
ctx.clearRect(0, 0, canvas.width, canvas.height)

this.bg.render(ctx)
}

update() {

this.bg.update()
}

// 实现游戏帧循环
loop() {

// console.log('loop, aniId = ' + this.aniId)

this.update()
this.render()

this.aniId = window.requestAnimationFrame(
this.bindLoop,
canvas
)

}
}

思考题

现在看起来背景滚动的速度很快,如果要想让背景滚动的速度降到现在的 1/3 或 1/2, 要改程序中的什么地方呢? :)

本文标题:微信小游戏入门(四)

文章作者:晨星

发布时间:2020年03月16日 - 10:03

最后更新:2020年05月28日 - 16:05

原始链接:https://www.mls-tech.info/weapp/wegame-getting-start-04/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。