微信小游戏推出已有几天了,这个功能对小程序和小游戏的推进影响不用多说,你们赶忙摩拳擦掌往上撸就能够了。关于如何开发官方文档已经说明了,这篇则是对官方的打飞机
demo一些小改造。json
微信开发者工具
(v1.02.1712280)HTML5
游戏轻松接入,官方提供了Adapter
。这个的做用就是提供HTML5
写法和wx
写法的全局转换层。使用无AppID
模式建立一个微信小游戏后能够看到官方demo,其中入口文件和配置文件:game.js
和game.json
。game.js
引入并初始化包含整个打飞机
的游戏场景、参与者(玩家飞机和敌方飞机)、游戏逻辑的主函数的main.js
。在main.js
中咱们能够发现因为Adapter
的存在,这里的代码和咱们日常的代码写法没什么差别了。游戏的主逻辑以下图:canvas
在loop中,玩家每隔20帧射一次,每隔60帧生成新的敌机。每帧检查玩家和敌机是否死亡,玩家死亡游戏结束,敌机死亡分数+1。只有玩家能够射击,且射击方式固定,经过躲避敌机生存。接下来咱们针对这些进行改造,提高游戏的可玩性和挑战性。小程序
首先用编辑器打开player/index.js
,将等级逻辑加入到玩家的类中。bash
export default class Player extends Sprite {
constructor() {
super(PLAYER_IMG_SRC, PLAYER_WIDTH, PLAYER_HEIGHT)
// 玩家默认处于屏幕底部居中位置
this.x = screenWidth / 2 - this.width / 2
this.y = screenHeight - this.height - 30
// 用于在手指移动的时候标识手指是否已经在飞机上了
this.touched = false
this.bullets = []
// 初始化事件监听
this.initEvent()
this.playerLevel = 1;
}
get level () {
return this.playerLevel;
}
set level (level) {
this.playerLevel = Math.min(level, 3);
}
复制代码
接下来在main.js
的update
函数加入升级逻辑。微信
// 其余代码...
update() {
this.bg.update();
databus.bullets.concat(databus.enemys).forEach(item => {
item.update();
});
this.enemyGenerate();
this.player.level = Math.max(1, Math.ceil(databus.score / 30));
this.collisionDetection();
}
// 其余代码...
复制代码
好的,到此玩家已经能够正常升级了。那么该给予玩家奖励品了。在player/index.js
的shoot
函数中咱们修改射击的逻辑。玩家1级时只有中间的射击口,2级有左边和中间的射击口,3级有左中右三个射击口。微信开发
// ...其余代码
/**
* 玩家射击操做
* 射击时机由外部决定
*/
shoot() {
for(let i = 0; i < this.level; i++) {
const bullet = databus.pool.getItemByClass('bullet', Bullet);
const middle = this.x + this.width / 2 - bullet.width / 2;
const x = !i ? middle : (i % 2 === 0 ? middle + 30 : middle - 30);
bullet.init(
x,
this.y - 10,
10
)
databus.bullets.push(bullet)
}
}
// ...其余代码
复制代码
武器的最终形态如图, 这时候的玩家已经能够随心所欲了<_<,实际上都不须要躲避了。。。:编辑器
为了对抗愚昧的玩家,不让他们随心所欲,最后没兴趣玩下去~~,敌机装备武器,反击开始。ide
首先敌机的子弹是向下,因此复制一份images/bullet.png
,并颠倒保存为images/bullet-down.png
, 而后咱们重用js/player/bullet.js
,在构造函数处增长敌机的子弹配置项,并修改敌人子弹更新逻辑。函数
const BULLET_IMG_SRC = 'images/bullet.png'
const BULLET_DOWN_IMG_SRC = 'images/bullet-down.png'
const BULLET_WIDTH = 16
const BULLET_HEIGHT = 30
const __ = {
speed: Symbol('speed')
}
let databus = new DataBus()
export default class Bullet extends Sprite {
constructor({ direction } = { direction: 'up' }) {
super(direction === 'up' ? BULLET_IMG_SRC : BULLET_DOWN_IMG_SRC, BULLET_WIDTH, BULLET_HEIGHT)
this.direction = direction;
// 其余代码...
// 每一帧更新子弹位置
update() {
if (this.direction === 'up') {
this.y -= this[__.speed]
// 超出屏幕外回收自身
if ( this.y < -this.height )
databus.removeBullets(this)
} else {
this.y += this[__.speed]
// 超出屏幕外回收自身
if ( this.y > window.innerHeight + this.height )
databus.removeBullets(this)
}
}
}
复制代码
接着在js/npc/enemy.js
结尾部分为敌人装备武器, 子弹速度为敌人自身速度+5
工具
import Animation from '../base/animation'
import DataBus from '../databus'
import Bullet from '../player/bullet';
const ENEMY_IMG_SRC = 'images/enemy.png'
// 其余代码...
update() {
this.y += this[__.speed]
// 对象回收
if ( this.y > window.innerHeight + this.height )
databus.removeEnemey(this)
}
/**
* 敌机射击操做
* 射击时机由外部决定
*/
shoot() {
const bullet = databus.pool.getItemByClass('bullet', Bullet);
bullet.init(
this.x + this.width / 2 - bullet.width / 2,
this.y + 10,
this[__.speed] + 5
);
databus.bullets.push(bullet);
}
}
复制代码
接下来,在js/main.js
中加入敌机的射击逻辑,敌机移动5次、60次时设计。
// 其余代码...
let ctx = canvas.getContext("2d");
let databus = new DataBus();
const ENEMY_SPEED = 6;
// 其余代码...
/**
* 随着帧数变化的敌机生成逻辑
* 帧数取模定义成生成的频率
*/
enemyGenerate(playerLevel) {
if (databus.frame % 60 === 0) {
let enemy = databus.pool.getItemByClass("enemy", Enemy);
enemy.init(ENEMY_SPEED);
databus.enemys.push(enemy);
}
}
// 其余代码...
// 实现游戏帧循环
loop() {
databus.frame++;
this.update();
this.render();
if (databus.frame % 20 === 0) {
this.player.shoot();
this.music.playShoot();
}
databus.enemys.forEach(enemy => {
const enemyShootPositions = [
-enemy.height + ENEMY_SPEED * 5,
-enemy.height + ENEMY_SPEED * 60
];
if (enemyShootPositions.indexOf(enemy.y) !== -1) {
enemy.shoot();
this.music.playShoot();
}
});
// 游戏结束中止帧循环
if (databus.gameOver) {
this.touchHandler = this.touchEventHandler.bind(this);
canvas.addEventListener("touchstart", this.touchHandler);
this.gameinfo.renderGameOver(ctx, databus.score);
return;
}
window.requestAnimationFrame(this.loop.bind(this), canvas);
}
复制代码
这时候咱们发现,因为不明宇宙的干扰射线的影响,玩家和敌机的子弹不受控制的乱飞。接下来咱们就来恢复世界的秩序吧 ;
经侦测发现是对象池pool
的获取逻辑问题致使子弹不受控问题,咱们须要区分获取玩家、每一个敌机的子弹
首先,对象获取咱们加入对象属性的判断,当有传入对象属性时,咱们获取全部属性值一致的已回收对象,若没有找到或者对象池为空时,则用属性建立新对象
/**
* 根据传入的对象标识符,查询对象池
* 对象池为空建立新的类,不然从对象池中取
*/
getItemByClass(name, className, properties) {
let pool = this.getPoolBySign(name)
if (pool.length === 0) return new className(properties);
if (!properties) return pool.shift();
const index = pool.findIndex(item => {
return Object.keys(properties).every(property => {
return item[property] === properties[property];
});
});
return index !== -1 ? pool.splice(index, 1)[0] : new className(properties)
}
复制代码
相应的咱们须要给每一个子弹设置归属,在js/player/bullet.js
中Bullet
类修改constructor
export default class Bullet extends Sprite {
constructor({ direction, owner } = { direction: 'up' }) {
super(direction === 'up' ? BULLET_IMG_SRC : BULLET_DOWN_IMG_SRC, BULLET_WIDTH, BULLET_HEIGHT)
this.direction = direction;
this.owner = owner;
}
复制代码
接着修改js/player/index.js
的shoot
,为其中建立的bullets
提供归属
/**
* 玩家射击操做
* 射击时机由外部决定
*/
shoot() {
for(let i = 0; i < this.level; i++) {
const bullet = databus.pool.getItemByClass('bullet', Bullet, { direction: 'up', owner: this });
复制代码
一样处理js/npc/enemy.js
的shoot
/**
* 敌机射击操做
* 射击时机由外部决定
*/
shoot() {
const bullet = databus.pool.getItemByClass('bullet', Bullet, { direction: 'down', owner: this });
复制代码
最后处理js/databus.js
中removeBullets
的回收逻辑
/**
* 回收子弹,进入对象池
* 此后不进入帧循环
*/
removeBullets(bullet) {
const index = this.bullets.findIndex(b => b === bullet);
bullet.visible = false
this.bullets.splice(index, 1);
this.pool.recover('bullet', bullet)
}
}
复制代码
这时候敌个人子弹就恢复正常了。不过这时候玩家中弹并不会死亡,如今来让玩家Go Die
吧。在js/main.js
的collisionDetection
咱们判断增长每一颗子弹若是是敌方的,就判断其是否打中玩家,是则游戏结束。玩家的子弹判断保持不变。
// 全局碰撞检测
collisionDetection() {
let that = this;
databus.bullets.forEach(bullet => {
for (let i = 0, il = databus.enemys.length; i < il; i++) {
let enemy = databus.enemys[i];
if (bullet.owner instanceof Enemy) {
databus.gameOver = this.player.isCollideWith(bullet);
} else if (!enemy.isPlaying && enemy.isCollideWith(bullet)) {
enemy.playAnimation();
that.music.playExplosion();
bullet.visible = false;
databus.score += 1;
break;
}
}
});
复制代码
到此整个简单改造计划就结束了,之后还能够添加武器系统,boss战等等。下面是改造后的游戏动图录屏
本文始发于本人的公众号:枫之叶。公众号二维码