e.设计变量缓存器,方便我们在不同的类中访问和修改变量
在DataStore.js文件中写入代码:
export class DataStore {
static getInstance() { //单例模式
if (!DataStore.instance) {
DataStore.instance = new DataStore();
}
return DataStore.instance;
}
constructor() { //构造函数,创建一个map来储存变量
this.map = new Map();
}
put(key, value) {
if (typeof value === 'function') { //这个方法可将原本new BackGround() 形式获取对象的写法
value = new value(); //变为BackGround,使代码更美观
}
this.map.set(key, value); //将键值对存入map中
return this;
}
get(key) { //根据key获取map中对应的value值
return this.map.get(key);
}
destroy() { //遍历map,销毁对应的value(也就是Image实例)
for (let value of this.map.values()) {
value = null;
}
}
}
f.设计背景图片的样式
在BackGround.js文件中写入代码:
import {Sprite} from "../base/Sprite.js";
import {DataStore} from "../base/DataStore.js";
export class BackGround extends Sprite {
constructor() {
const image = Sprite.getImage('background'); //获取背景图片的实例
super(image, //设置背景图片格式
0, 0,
image.width, image.height,
0, 0,
DataStore.getInstance().canvas.width, DataStore.getInstance().canvas.height);
}
}
g.设计不断移动的陆地类
在Land.js文件中写入代码:
//不断移动的陆地
import {Sprite} from "../base/Sprite.js";
import {Director} from "../Director.js";
import {DataStore} from "../base/DataStore.js";
export class Land extends Sprite { //继承精灵基类
constructor() {
const image = Sprite.getImage('land');
super(image, 0, 0, //设置陆地图片的样式
image.width, image.height,
0, DataStore.getInstance().canvas.height - image.height, //设置陆地图片在画布中渲染的位置
image.width, image.height);
//地板的水平变化坐标
this.landX = 0;
//地板的移动速度
this.landSpeed = Director.getInstance().moveSpeed;
}
draw() { //设计成循环渲染模式
this.landX = this.landX + this.landSpeed; //每次渲染的位置都向左移动一点
if (this.landX > (this.img.width - DataStore.getInstance().canvas.width)) {
this.landX = 0; //这个是防止穿帮,保证陆地图片铺满整个画布
}
super.draw(this.img,
this.srcX,
this.srcY,
this.srcW,
this.srcH,
-this.landX, //模拟地面向右移动
this.y,
this.width,
this.height)
}
}
h.设计铅笔基类,在Pencil.js文件中写入代码:
import { Sprite } from "../base/Sprite.js";
import {DataStore} from "../base/DataStore.js";
export class Pencil extends Sprite { //铅笔基类也继承精灵类
constructor(image, top) { //重写构造方法,加入参数top
super(image, //继承构造方法,设置铅笔图片的默认值
0, 0,
image.width, image.height,
//刚好在右侧看不到的位置
DataStore.getInstance().canvas.width, 0,
image.width, image.height);
this.top = top;
this.moveSpeed = 2;
}
draw() {
this.x = this.x - this.moveSpeed; //跟陆地图片一样,每次渲染向右移动
super.draw(this.img,
0, 0,
this.width, this.height,
this.x, this.y,
this.width, this.height)
}
}
i.设计上半部分铅笔实例类,在UpPencil.js文件中写入代码:
//上半部分铅笔
import {Pencil} from "./Pencil.js";
import {Sprite} from "../base/Sprite.js";
export class UpPencil extends Pencil {
constructor(top) { //top表示裁剪高度
const image = Sprite.getImage('pencilUp'); //获取上半部分铅笔图片实例
super(image, top);
}
draw() {
this.y = this.top - this.height; //设置上半部分铅笔图片从画布上方开始渲染
super.draw(); //this.y为负数
}
}
j.设计下半部分铅笔实例类,同时中间要留出一定的间距,
在DownPencil.js文件中写入代码:
//下半部分铅笔
import {Pencil} from "./Pencil.js";
import {Sprite} from "../base/Sprite.js";
import {DataStore} from "../base/DataStore.js";
export class DownPencil extends Pencil {
constructor(top) {
const image = Sprite.getImage('pencilDown'); //获取下半部分铅笔图片实例
super(image, top);
}
draw() {
let gap = DataStore.getInstance().canvas.height / 5; //gap表示上下半部分铅笔之前的间隔,高度为画布高度的5分之1
this.y = this.top + gap;
super.draw();
}
}
k.设计小鸟类,在Birds.js文件中写入代码:
//小鸟类
//是循环渲染三只小鸟
//其实是循环渲染图片的三个部分
import {Sprite} from "../base/Sprite.js";
import {DataStore} from "../base/DataStore.js";
export class Birds extends Sprite {
constructor() {
const image = Sprite.getImage('birds');
super(image, 0, 0, image.width, image.height,
0, 0, image.width, image.height);
//小鸟的三种状态需要一个数组去存储
//小鸟的宽是34,小鸟的高度是24,上下边距是10,小鸟左右边距是9
this.clippingX = [ //裁剪图片的起始X坐标
9,
9 + 34 + 18,
9 + 34 + 18 + 34 + 18
];
this.clippingY = [10, 10, 10]; //裁剪图片的起始Y坐标
this.clippingWidth = [34, 34, 34]; //裁剪宽度和高度
this.clippingHeight = [24, 24, 24];
const birdX = DataStore.getInstance().canvas.width / 4; //在画布上的起始渲染X和Y坐标
this.birdsX = [birdX, birdX, birdX];
const birdY = DataStore.getInstance().canvas.height / 2;
this.birdsY = [birdY, birdY, birdY];
const birdWidth = 34;
this.birdsWidth = [birdWidth, birdWidth, birdWidth]; //在画布中渲染的小鸟图片的宽度和高度
const birdHeight = 24;
this.birdsHeight = [birdHeight, birdHeight, birdHeight];
this.y = [birdY, birdY, birdY]; //负责存储触摸小鸟类后渲染的起始Y坐标
this.index = 0; //存储当前渲染的小鸟图片的索引
this.count = 0; //当前切换小鸟图片的速度
this.time = 0; //小鸟下落的时间
}
draw() { //循环渲染小鸟图片
//切换三只小鸟的速度
const speed = 0.2;
this.count = this.count + speed;
//0,1,2
if (this.index >= 2) { //当小鸟图片渲染到第3张
this.count = 0; //设置下一张渲染的小鸟图片为第1张,以此循环
}
//减速器的作用
this.index = Math.floor(this.count); //这个函数的作用是将小数四舍五入,取整数
//模拟重力加速度
const g = 0.98 / 2.4;
//向上移动一丢丢的偏移量
const offsetUp = 30;
//小鸟的位移
const offsetY = (g * this.time * (this.time - offsetUp)) / 2; //效果是小鸟会先向上位移一段,再下落
for (let i = 0; i <= 2; i++) {
this.birdsY[i] = this.y[i] + offsetY; //每次渲染都更新小鸟的Y坐标
}
this.time++; //小鸟的下落时间
super.draw( //绘制小鸟图片,模拟小鸟飞行的动画效果
this.img,
this.clippingX[this.index], this.clippingY[this.index],
this.clippingWidth[this.index], this.clippingHeight[this.index],
this.birdsX[this.index], this.birdsY[this.index],
this.birdsWidth[this.index], this.birdsHeight[this.index]
);
}
}
l.设计开始按钮类,在StartButton.js文件中写入代码:
//开始按钮类
import {Sprite} from "../base/Sprite.js";
import {DataStore} from "../base/DataStore.js";
export class StartButton extends Sprite { //渲染开始按钮图片
constructor() {
const image = Sprite.getImage('startButton');
super(image,
0, 0,
image.width, image.height,
(DataStore.getInstance().canvas.width - image.width) / 2, //设置开始按钮的渲染位置为屏幕中央
(DataStore.getInstance().canvas.height - image.height) / 2.5,
image.width, image.height
);
}
}
m.设计计分器类,在Score.js文件中写入代码:
//计分器类
import {DataStore} from "../base/DataStore.js";
export class Score {
constructor() {
this.ctx = DataStore.getInstance().ctx; //获取当前画布实例
this.scoreNumber = 0;
//因为canvas刷新的很快,所以需要一个变量控制加分,只加一次
this.isScore = true;
}
draw() {
this.ctx.font = '25px Arial'; //设置画布的字体大小和类型,Arial为万能字体
this.ctx.fillStyle = '#ffcbeb'; //设置画布的字体颜色
this.ctx.fillText( //设置计分器在画布上的显示内容和位置
this.scoreNumber, //显示内容,分数
DataStore.getInstance().canvas.width / 2, //显示位置
DataStore.getInstance().canvas.height / 18,
1000
);
}
}
总结:小程序小游戏的核心架构是Game.js为小程序的入口,Main.js负责资源和数据的初始化,而Director.js负责游戏的主逻辑,在编码时最好采用面向对象的方法,将用到的资源或数据都分类整理成各个模块,方便维护。
本文暂时没有评论,来添加一个吧(●'◡'●)