小程序开发教程学习(三)

发布一下 0 0

九、V2EX微信小程序开发

1.组件模块化设计

a.为什么要对小程序进行组件模块化设计?

微信小程序有代码大小限制

提高代码的复用率

b.如何进行组件模块化设计?

通过WXML的import和include来使用文件模板

使用WXSS的@import来引用WXSS文件

使用JS的require来引用JS文件


2.wx.request方法使用详解

a.wx.request接口实现和服务端的交互(GET,POST,PUT,DELETE等)

b.setData()参数格式:需要先定义that = this,不然页面结构会出错。



十、ThinkPHP5后台接口微信小程序

1.总体架构

a.服务端(处理客户端发送的数据):

ThinkPHP5+MySQL构建REST API

b.客户端(面向用户):

向服务端请求数据,完成自身行为逻辑

c.CMS(本质是对数据库的增删改查):

向服务端请求数据,实现相关功能


2.开发环境安装

a.安装xampp(百度搜索下载)

使用xampp来安装PHP,Apache和mySql

b.安装ThinkPHP5(百度搜索下载)

c.安装PHPStorm


十一、微信小游戏FlyBirds开发

1.小游戏的特点

a.快速体验,短生命周期,转化率高

b.体验优于手机网页

c.不需要像App一样下载注册


2.小游戏的展望

a.是一个趋势,替代过重的APP和体验差的手机网页

b.快速引流,引导用户向APP过渡

c.将作为一种开发理念在更多互联网入口平台流行

3.小游戏的模块分解

game.js:是小游戏全局的入口文件,是小游戏必须有的一个文件

main.js:程序主类,主要用来初始化canvas和一些全局对象,各个精灵和绑定点击事件

Director.js:程序导演类,用来控制游戏的逻辑和精灵的创建与销毁,控制游戏主循环

DataStore.js:存储游戏需要长期保存的变量和需要定时销毁的变量

Resources.js:游戏的资源

ResourceLoader.js:资源加载器,保证游戏是在图片加载完成后开始主循环

Sprite.js:游戏精灵的基类,背景,陆地,铅笔,小鸟等都是它的子类

Background.js:背景类

Land.js:陆地类

UpPencil.js:上半部分铅笔类

DownPencil.js:下半部分铅笔类

Birds.js:小鸟类

Score.js:计分器类

StartButton.js:重新开始按钮类


4.小游戏的编程步骤详解

a.先将小游戏的图片素材导入项目中,并建立一个数组来映射它们

Resources.js中写入如下代码:

export const Resources = [

['background', 'res/background.png'],

['land', 'res/land.png'],

['pencilUp', 'res/pie_up.png'],

['pencilDown', 'res/pie_down.png'],

['birds', 'res/birds.png'],

['startButton', 'res/start_button.png']

];

b.设计资源加载器功能,在ResourceLoader.js中写如下代码:

//资源文件加载器,确保canvas在图片资源加载完成后才进行渲染

import {Resources} from "./Resources.js"; //导入图片数组


export class ResourceLoader {

constructor() { //构造函数

this.map = new Map(Resources); //将Resources中的数组赋给变量map

for (let [key, value] of this.map) { //for循环,注意ES6的写法

const image = wx.createImage(); //创建image实例

image.src = value; //将image实例的src地址设为数组的value值

this.map.set(key, image); //将map的格式设为每个key对应的value值是image实例

}

}

onLoaded(callback) { //加载函数

let loadedCount = 0;

for (let value of this.map.values()) { //for循环遍历上面绑定的image实例

value.onload = () => { //这里使用了ES6的箭头写法,这样写的好处是清晰明了,不会错乱

loadedCount++; //每遍历一个image实例加一次

if (loadedCount >= this.map.size) { //当遍历完整个map时,返回加载成功

callback(this.map);

}

}

}

}

static create() { //这里使用了工厂模式,这个函数的作用是创建一个加载器实例

return new ResourceLoader();

}

}

c.设计初始化游戏的文件,作为游戏开始的入口,在main.js中写入以下代码:

(注意:main.js中的内容是在开发过程中不断更新的,不是一次就写好的)

//初始化整个游戏的精灵,作为游戏开始的入口

import {ResourceLoader} from "./js/base/ResourceLoader.js"; //导入加载器

import {BackGround} from "./js/runtime/BackGround.js";

import {DataStore} from "./js/base/DataStore.js";

import {Director} from "./js/Director.js";

import {Land} from "./js/runtime/Land.js";

import {Birds} from "./js/player/Birds.js";

import {StartButton} from "./js/player/StartButton.js";

import {Score} from "./js/player/Score.js";

import {ApiExamples} from "./js/ApiExamples.js";


export class Main { //程序主类

constructor() {

this.canvas = wx.createCanvas(); //创建画布

this.ctx = this.canvas.getContext('2d'); //设置画布的显示类型为2D

this.dataStore = DataStore.getInstance(); //创建变量缓存器实例

this.director = Director.getInstance(); //创建导演类实例

const loader = ResourceLoader.create(); //创建资源加载器实例

loader.onLoaded(map => this.onResourceFirstLoaded(map)); //调用加载器的加载资源函数

}

//创建背景音乐

createBackgroundMusic() {

const bgm = wx.createInnerAudioContext(); //微信的创建背景音乐Api

bgm.autoplay = true;

bgm.loop = true;

bgm.src = 'audios/bgm.mp3'; //背景音乐的路径,不宜过大

}

onResourceFirstLoaded(map) { //该函数的作用是当重新开始游戏时

//将资源重置成第一次加载的状态,避免资源重复加载

this.dataStore.canvas = this.canvas;

this.dataStore.ctx = this.ctx;

this.dataStore.res = map;

this.createBackgroundMusic(); //创建背景音乐

const examples = new ApiExamples();

// examples.getUserInfo();

// examples.login();

// examples.getSettings();

// examples.httpExample();

// examples.socketExample();

// examples.download();

this.init();

}

init() {

//首先重置游戏是没有结束的

this.director.isGameOver = false; //设置一个变量来标记游戏是否结束

this.dataStore

.put('pencils', []) //创建存储一组铅笔实例的数组

.put('background', BackGround) //创建背景类

.put('land', Land) //创建陆地类

.put('birds', Birds) //创建小鸟类

.put('score', Score) //创建计分器类

.put('startButton', StartButton); //创建开始按钮类

this.registerEvent();

//创建铅笔要在游戏逻辑运行之前

this.director.createPencil(); //运行前先创建一组铅笔

this.director.run(); //初始化各种资源后,开始运行游戏

}

registerEvent() { //这个事件是在浏览器中创建点击屏幕事件

// this.canvas.addEventListener('touchstart', e => {

// //屏蔽掉JS的事件冒泡

// e.preventDefault();

// if (this.director.isGameOver) {

// console.log('游戏开始');

// this.init();

// } else {

// this.director.birdsEvent();

// }

// });

wx.onTouchStart(() => { //微信小程序的触摸事件

if (this.director.isGameOver) { //判断游戏是否已结束

console.log('游戏开始'); //已结束则将资源初始化

this.init();

} else { //未结束则调用导演类的小鸟事件

this.director.birdsEvent(); //这个函数的作用是刷新小鸟的位置

}

});

}

}

d.设计导演类,控制游戏逻辑,导演类要设计成单例模式

(注意:导演类也是边开发边完善的,不是一次写好的)

在Director.js文件中写入代码:

//导演类,控制游戏的逻辑

import {DataStore} from "./base/DataStore.js";

import {UpPencil} from "./runtime/UpPencil.js";

import {DownPencil} from "./runtime/DownPencil.js";

export class Director {

static getInstance() {

if (!Director.instance) { //如果导演类不存在则创建

Director.instance = new Director(); //导演类只创建一个实例,这就是单例模式

}

return Director.instance; //存在则返回该导演类实例

}

constructor() {

this.dataStore = DataStore.getInstance();

this.moveSpeed = 2;

}

createPencil() { //创建一组铅笔

const minTop = DataStore.getInstance().canvas.height / 8; //这是铅笔的最小高度

const maxTop = DataStore.getInstance().canvas.height / 2; //这是铅笔的最大高度

const top = minTop + Math.random() * (maxTop - minTop); //铅笔的高度取最大高度和最小高度之前的随机值

this.dataStore.get('pencils').push(new UpPencil(top)); //创建UpPecil和DownPencil实例,将它们存入 dataStore中的pencils数组中

this.dataStore.get('pencils').push(new DownPencil(top));

}

birdsEvent() { //循环设置小鸟图片的渲染位置

for (let i = 0; i <= 2; i++) { //以此来达到用户点击屏幕小鸟会往上位移的效果

this.dataStore.get('birds').y[i] =

this.dataStore.get('birds').birdsY[i];

}

this.dataStore.get('birds').time = 0; //重置小鸟的下落时间,效果更好

}

//判断小鸟是否和铅笔撞击

static isStrike(bird, pencil) { //传入的参数为小鸟和铅笔的模型

let s = false;

if (bird.top > pencil.bottom || //小鸟和铅笔撞击的全部4种情况

bird.bottom < pencil.top || //即上下左右

bird.right < pencil.left ||

bird.left > pencil.right

) {

s = true; //满足其中一种则返回True

}

return !s; //否则返回False

}

//判断小鸟是否撞击地板和铅笔

check() {

const birds = this.dataStore.get('birds');

const land = this.dataStore.get('land');

const pencils = this.dataStore.get('pencils');

const score = this.dataStore.get('score');

//地板的撞击判断

if (birds.birdsY[0] + birds.birdsHeight[0] >= land.y) { //当小鸟的位置刚好碰到地板时

console.log('撞击地板啦');

this.isGameOver = true;

return;

}

//小鸟的边框模型

const birdsBorder = { //设置小鸟的边框模型

top: birds.y[0],

bottom: birds.birdsY[0] + birds.birdsHeight[0],

left: birds.birdsX[0],

right: birds.birdsX[0] + birds.birdsWidth[0]

};

const length = pencils.length;

for (let i = 0; i < length; i++) { //循环遍历铅笔数组

const pencil = pencils[i];

const pencilBorder = { //设置铅笔数组里所有的铅笔模型

top: pencil.y,

· bottom: pencil.y + pencil.height,

left: pencil.x,

right: pencil.x + pencil.width

};

if (Director.isStrike(birdsBorder, pencilBorder)) { //循环检测小鸟和每支铅笔是否有碰撞

console.log('撞到水管啦');

this.isGameOver = true; //为真则游戏结束

return;

}

}

//加分逻辑

if (birds.birdsX[0] > pencils[0].x + pencils[0].width //当小鸟刚好越过一组铅笔时

&& score.isScore) {

wx.vibrateShort({ //当小鸟每越过一组铅笔,调用微信的振动Api

success: function () { //让屏幕振动

console.log('振动成功');

}

});

score.isScore = false; //设计一个标志位,实现每触发一次记一次分

score.scoreNumber++; //计分器加一分

}

}

run() { //游戏运行函数,游戏主逻辑

this.check();

if (!this.isGameOver) { //判断isGameOver是否为False,为False表示游戏未结束,正常运行

this.dataStore.get('background').draw(); //先从dataStore中获取背景图片并渲染

const pencils = this.dataStore.get('pencils'); //接着从dataStore中获取铅笔数组

if (pencils[0].x + pencils[0].width <= 0 && //如果铅笔数组的第一组铅笔刚好到达画布的左侧

pencils.length === 4) { //并且铅笔数组目前有2组铅笔

pencils.shift(); //就将铅笔数组的第一组铅笔类剔除

pencils.shift(); //并且将第二组铅笔(3,4)变为第一组铅笔(1,2)

this.dataStore.get('score').isScore = true; //当一组铅笔销毁时,将计分器标志位设为True以计分

}

if (pencils[0].x <= (DataStore.getInstance().canvas.width - pencils[0].width) / 2 && //设计当第一组铅笔运行到画布靠左侧的时候

pencils.length === 2) { //并且数组中只有一组铅笔时

this.createPencil(); //创建一组新的铅笔

} //这样就实现了循环创建铅笔的功能并且将运行至画布外的铅笔销毁

this.dataStore.get('pencils').forEach(function (value) { //遍历铅笔数组,渲染铅笔图片

value.draw();

});

this.dataStore.get('land').draw(); //渲染陆地图片

this.dataStore.get('score').draw(); //渲染计分器

this.dataStore.get('birds').draw(); //渲染小鸟图片

let timer = requestAnimationFrame(() => this.run()); //这里调用了循环动画渲染Api,性能好

this.dataStore.put('timer', timer);

} else { //isGameOver为True则表示游戏结束了

console.log('游戏结束');

this.dataStore.get('startButton').draw(); //游戏结束时在屏幕中央绘制开始按钮图片

cancelAnimationFrame(this.dataStore.get('timer')); //销毁循环动画Api

this.dataStore.destroy(); //销毁资源

//触发微信小游戏垃圾回收

wx.triggerGC();

}

}

}

e.设计精灵的基类,在Sprite.js文件中写入代码:

//精灵的基类,负责初始化精灵加载的资源和大小以及位置

import {DataStore} from "./DataStore.js";

export class Sprite {

constructor(img = null,

srcX = 0,

srcY = 0,

srcW = 0,

srcH = 0,

x = 0, y = 0,

width = 0, height = 0) {

this.dataStore = DataStore.getInstance();

this.ctx = this.dataStore.ctx;

this.img = img;

this.srcX = srcX;

this.srcY = srcY;

this.srcW = srcW;

this.srcH = srcH;

this.x = x;

this.y = y;

this.width = width;

this.height = height;

}

static getImage(key){ //静态方法获取对应的图片对象

return DataStore.getInstance().res.get(key);

}

draw(img = this.img, //给这些参数一个初始值

srcX = this.srcX,

srcY = this.srcY,

srcW = this.srcW,

srcH = this.srcH,

x = this.x,

y = this.y,

width = this.width,

height = this.height) {

this.ctx.drawImage( //Canvas画布渲染图片的方法

img, //参数img表示传入的img对象

srcX, //要裁剪的起始X坐标

srcY, //要裁剪的起始Y坐标

srcW, //裁剪的宽度

srcH, //裁剪的高度

x, //放置的x坐标

y, //放置的y坐标

width, //要使用的宽度

height //要使用的高度

);

}

}

版权声明:内容来源于互联网和用户投稿 如有侵权请联系删除

本文地址:http://0561fc.cn/59336.html