微信小程序 | 游戏开发之接宝石箱子游戏

1、什么是微信小游戏

微信小游戏是小程序的一个类目,小游戏是微信开放给小程序的更多的能力,让小程序开发者有了开发游戏的能力。微信小游戏是在小程序的基础上添加了游戏库API。微信小游戏只能运行在小程序环境中,微信小游戏没有小程序中WXSS、WXML、多页面等内容,所以微信小游戏开发时小程序的组件就无法使用;但增加了一些渲染、文件系统以及后台多线程的功能。

小游戏提供了CommonJS风格的模块API,可以将一些公共的代码抽离成为一个单独的JS文件,作为一个模块。可以通过module.exports或者exports导出模块,通过require引入模块。

2、接宝石箱子游戏

接宝石箱子小游戏运行后底部出现主角工人,屏幕上方不断掉落宝石箱子,主角工人每接住一个箱子积分增加1分,玩家通过触碰屏幕左侧或者右侧控制工人移动方向。本游戏运行界面如图1所示。

 ■ 图1  接宝石箱子小游戏运行效果

// common.js
function sayHello(name) {
  console.log('Hello' + name + '!')
}
function sayGoodbye(name) {
  console.log('Goodbye'+ name+'!')
}
module.exports.sayHello = sayHello //提供对外的接口
module.exports.sayGoodbye = sayGoodbye //提供对外的接口

 在game.js中require common.js,就可以调用common模块导出的接口。所有输出接口都会成为输入对象的属性。

var common = require('./js/libs/common.js')
common.sayHello('xmj')
common.sayGoodbye('xmj')

在模块化时,也可以使用export default命令和import命令。

使用import命令是用户需要知道所加载的变量或者函数名,否则无法加载,为了方便用户,使其不用预先知道就能加载模块,这是可以使用export default为模块指定默认输出。

// common2.js
export default function test() { //当然也可以是一个类
  console.log("大家好");
};

 导入时可以如下:

import t from './js/libs/common2.js'
t('xmj')

 这时使用import导入时可以使用任意名称指定模块js文件的导出方法test()。本质上export default就是输出一个叫做Default的方法,只是系统容许为它任意取名。微信小游戏支持ES6,所以开发时可以使用export default class定义各种类模块,例如Bullet子弹类,Sprite精灵类,Enemy敌人类模块,使用import导入类模块。

import Player from './player/index'
import Enemy from './npc/enemy'

 小游戏并不能调用所有小程序的API,但是能调用到大部分的API。例如像wx.request,wx.chooseImage,wx.showToast等API,小游戏都可以调用到。更详细的API能力见微信官方API文档。

03、程序设计的步骤

使用微信开发者工具新建项目,左侧类别选择小游戏,右侧的项目名称输入“接宝石箱子游戏”,单击“新建”按钮,就新建一个新的小游戏。

在图2界面中的中间部分,为文件结构区域。右键文件结构区域上方+号,下拉菜单中选择“目录”,建立文件夹test/images结构,放入相关游戏图片(箱子,工人)。

 ■ 图2  放入相关游戏图片

准备工作完成后,修改game.js文件。本游戏不使用Adapter(适配器),使用微信wx API自行开发。

/*import './js/libs/weapp-adapter'
import './js/libs/symbol'
import Main from './js/main'
new Main()
*/
const DROP_SPEED = 8   //箱子下移速度
const MOVE_SPEED = 4   //人物左右移速度
const canvas = wx.createCanvas()
const context = canvas.getContext('2d')
context.fillStyle = "#ffff00"
context.font = "40px Arial"

 加载工人图片,并设置设置位置坐标(imgX,imgY)。

const image = wx.createImage() //人物图片
let imgX = canvas.width / 2 - 18 //人物位置
let imgY = canvas.height - 80
image.onload = function () {
  context.drawImage(image, imgX, imgY)
}
image.src = 'test/images/player.png'

 drawRect(x, y)函数清空屏幕,重绘宝石箱子、人物和积分文字。

let score = 0
const { windowWidth, windowHeight } = wx.getSystemInfoSync() //屏幕宽度和高度
function drawRect(x, y) {
  context.clearRect(0, 0, windowWidth, windowHeight) //重绘清空屏幕
  context.drawImage(boxImage, x, y) //画宝石箱子
  context.drawImage(image, imgX, imgY) //画人物
  context.fillText("积分" + score, 30, 50) //绘制积分文字
}

 设置宝石箱子坐标初始位置(imgX,imgY)为屏幕顶端中央。调用box(rectX, rectY)在指定位置(rectX, rectY)绘制箱子。

let rectX = canvas.width / 2 – 30    //宝石箱子坐标
let rectY = 0
const boxImage = wx.createImage() //宝石箱子图片
box(rectX, rectY) //调用box((rectX, rectY)在指定位置(rectX, rectY)绘制箱子

function box(x, y) {
  // Math.ceil(); 只要有小数总是向上取整数; 例如Math.ceil(1.1) 输出为2
  let number = Math.ceil(Math.random() * 7) //随机产生1-7数字
  let box_src = 'test/images/box' + number + '.png'
  boxImage.onload = function () {
    context.drawImage(boxImage, x, y)
  }
  boxImage.src = box_src
}

 以下触摸(碰)事件处理。判断触碰位置在人物的左侧则移动方向direction值为-1,这样x坐标可以不断减少。触碰位置在人物的右侧则移动方向direction值为1,这样x坐标可以不断增加。

var direction = 0
var touchX = imgX
var touchY = imgY
wx.onTouchStart(function (res) {//触碰事件
  touchX = res.changedTouches[0].clientX - 18
  if (touchX < imgX) { //触碰位置在人物的左侧
    direction = -1       //向左移动
    console.log("left")
  } else { //触碰位置在人物的右侧
    direction = 1        //向右移动
    console.log("right")
  }
})

loop()是用来实现游戏帧循环达到动画效果。首先判断工人达到屏幕两侧边界,如果判断工人的位置到达屏幕最左侧,则改向右;到达屏幕最右侧,则改向左。箱子Y坐标不断,显示出下落效果,工人位置坐标根据移动方向不断修改,同时重新绘制箱子,工人,积分。

如果箱子到达底部区域,则判断与工人之间距离,如果小于50则认为碰撞(就是工人接到宝石箱子),进行加分处理。如果箱子出了屏幕底部,重新设置箱子图片并设置位于顶部。最后调用requestAnimationFrame(loop);起到循环渲染效果。

function loop() {
  if (imgX <= 10) { //人物位置到达屏幕最左侧,改向右
    direction = 1
  } else if (imgX >= canvas.width - 50) {//人物位置到达屏幕最右侧,改向左
    direction = -1
  }

  rectY += DROP_SPEED //箱子下移DROP_SPEED
  imgX += direction * MOVE_SPEED //改变人物位置坐标
  drawRect(rectX, rectY) //重新绘制箱子,人物,积分
  if (rectY > canvas.height - 100 && rectY <= canvas.height) {//达到底部
    let range = Math.abs(rectX - imgX) //与人物之间距离
    if (range <= 50) { //检测碰撞
      rectY = canvas.height
      score++ //加分
    }
  }
  if (rectY > canvas.height) {
    rectY = 0
    let spwanX = Math.floor(Math.random() * (canvas.width - 80))
    box(spwanX, rectY) //重新设置箱子位于顶部
    rectX = spwanX
  }
  requestAnimationFrame(loop); //循环渲染
}
loop()

猜你喜欢

转载自blog.csdn.net/qq_41640218/article/details/126826168