专栏首页游戏开发之旅利用 three.js 开发微信小游戏的尝试

利用 three.js 开发微信小游戏的尝试

前言

这是一次利用 three.js 开发微信小游戏的尝试,并不能算作是教程,只能算是一篇笔记吧。

微信 WeChat 6.6.1 开始引入了微信小游戏,初期上线了一批质量相当不错的小游戏。我在查阅各处的文章时候,发现其中有几款是基于 three.js 开发的,目前火爆朋友圈的《跳一跳》就是其中之一。这引起了我的注意,想起几年前也做过不少 WebGL 的尝试,于是禁不住想要弄到微信小游戏平台上试试。

准备工作

  1. 最新版本的 three.js
  2. 首先应该具有一定的 three.js 开发经验,有之前写过的简单演示代码;
  3. 最新版本的“微信开发者工具”。

另外补充一点:需要足够的耐心,微信开发者工具问题多多,编辑器也各种问题,我是使用 WebStorm 来编写代码,您不妨也试试。遇到奇怪的问题的时候,可能需要多启动几次开发者工具,非常令人恼火。

找一个之前的 WebGL 演示

我随便找了一个很久以前做过的演示代码,如下:

可以拖动旋转,滚轮缩放

创建微信小游戏项目

好啦,现在可以进入开发者工具尝试移植了。

首先,创建一个标准的小游戏项目。

选择“小游戏”项目进行创建,并选择一个空的目录作为项目目录

点击“确定”就会打开一个模板项目,是一个射击游戏,大致的结构如下:

├── game.js
├── game.json
├── project.config.json
├── README.md
├── js
|   ├── databus.js
|   ├── main.js
|   ├── base
|   |   ├── animation.js
|   |   └── ...
|   ├── libs
|   |   ├── symbol.js
|   |   └── weapp-adapter.js
|   ├── npc
|   |   └── enemy.js
|   ├── player
|   |   ├── bullet.js
|   |   └── ...
|   └── runtime
|       ├── background.js
|       └── ...
├── audio
|   ├── bgm.mp3
|   └── ...
└── images
    ├── Common.png
    └── ...

基于这个模板,我们可以将不需要的内容暂时删除,以便跑我们自己的项目。其中,射击游戏相关的内容都可以移除了,但是我们要保留一些关键的代码和配置文件,清理以后,大概会是这个样子:

├── game.js
├── game.json
├── project.config.json
├── README.md
├── js
|   ├── main.js
|   └── libs
|       ├── symbol.js
|       └── weapp-adapter.js
└── images
  1. 其中,images 目录里面放置我们需要使用到的图片,在这个例子中,我放了粒子图片和 indienova Logo 图片在里面;
  2. 将我们必然会用到的 three.js(使用 three.min.js 也可以,但是后面需要修改这个文件,所以建议使用没有 minified 的版本)放入 js/libs
  3. 如果有其它资源,比如音频文件什么的,也可以自建目录放进去;
  4. 然后需要修改一下配置文件,简单的说,只要修改 project.config.json 中的 projectname 即可;
  5. 保留 game.js 不变,这个是入口,会引入 main.js 并执行;
  6. main.js 清空,我们的新代码会在这里完成。

我们还保留了两个 js 文件,libs 中的 symbol.jsweapp-adapter.js。这里需要注意的是 weapp-adapter.js 很重要,官方解释如下:

小游戏的运行环境在 iOS 上是 JavaScriptCore,在 Android 上是 V8,都是没有 BOM 和 DOM 的运行环境,没有全局的 document 和 window 对象。因此当你希望使用 DOM API 来创建 Canvas 和 Image 等元素的时候,会引发错误。 ………… 这些使用 wx API 模拟 BOM 和 DOM 的代码组成的库称之为 Adapter。顾名思义,这是对基于浏览器环境的游戏引擎在小游戏运行环境下的一层适配层,使游戏引擎在调用 DOM API 和访问 DOM 属性时不会产生错误。Adapter 是一个抽象的代码层,并不特指某一个适配小游戏的第三方库,每位开发者都可以根据自己的项目需要实现相应的 Adapter。官方实现了一个 Adapter 名为 weapp-adapter, 并提供了完整的源码,供开发者使用和参考。 ………… 除此之外 weapp-adapter 还模拟了以下对象和方法:

  • document.createElement
  • canvas.addEventListener
  • localStorage
  • Audio
  • Image
  • WebSocket
  • XMLHttpRequest
  • 等等...

需要强调的是,weapp-adapter 对浏览器环境的模拟远不完整的,仅仅只针对游戏引擎可能访问的属性和调用的方法进行了模拟,也不保证所有游戏引擎都能通过 weapp-adapter 顺利无缝接入小游戏。直接将 weapp-adapter 提供给开发者,更多地是作为参考,开发者可以根据需要在 weapp-adapter 的基础上进行扩展,以适配自己项目使用的游戏引擎。 原文请参阅:这里

可见,微信团队已经为我们开发游戏做好了一些准备,比如露出的 canvas,我们到时候直接拿来使用就是。

将之前的代码移植到项目中

开始将之前写好的代码移植过来,注意由于要使用 ES 6(EMCAScript 6)标准,所以之前的代码可能要做相应的调整,不过大部分都是语法的调整,有一些方法的使用需要增加 bind(this),具体的还请大家参阅我们提供的链接地址,就算不看书,随便尝试一下也能很快有所了解。

新的 main.js 的主体代码看起来是这样:

import * as THREE from 'libs/three.js'

let ctx   = canvas.getContext('webgl')

let scene
let renderer

// ... 其它变量/常量 ...

/**
 * 游戏主函数
 */
export default class Main {
  constructor() {
    this.start()
  }

  start() {
    // 初始化
    scene     = new THREE.Scene()
    renderer  = new THREE.WebGLRenderer({ context: ctx })

    //... 其它代码块 ...

    // 开始循环
    this.loop()
  }

  // UPDATE 更新
  update() {
    // ... 数据更新代码块 ...
  }

  // RENDER 渲染
  render() {
    // ... 渲染代码块 ...
  }

  // 实现游戏帧循环
  loop() {
    this.update()
    this.render()

    window.requestAnimationFrame( this.loop.bind(this), canvas )
  }
}

一些要点:

由于微信已经为我们准备好了的 canvas,所以我们无需自己再进行创建,只需要取得的 canvascontext 就可以了,这里我们使用的不是 2d,而是 webgl

let ctx = canvas.getContext('webgl')

然后我们在创建 WebGLRenderer 的时候,直接使用这个 context 就可以了。

renderer  = new THREE.WebGLRenderer({ context: ctx })

这两点做到了,基本上就不会有太大问题了。

一切正常的话,开发者工具里面应该就能跑得起来了。

能跑起来并不算完,还需要真机测试

真机调试

真机调试不复杂,微信开发者工具提供了真机预览功能,只要点一下“预览”,就会上传代码,并生成二维码供测试。

开发者用微信扫描这个二维码,就可以打开测试。

如果您没有修改过 three.js 源文件,那么很有可能只看到一个黑屏。

还好,微信小游戏提供了一个调试开关,我们可以选择打开调试:

然后再次扫码进入,就可以查看调试信息了:

可以清晰的得知,createElementNS 不被支持,那么我们可以将所有 createElementNS 改为 createElement:(注意,这只是暂时解决方案,此方法并不是理想方案,我们以后应该会有更好的解决方法。通过修改 adapter 应该就可以减少 three.js 源文件的修改。)

document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
// 改为 ==>
document.createElement( 'canvas' );

不止这一处,而且也不止是针对 canvas 的创建,还有针对 img 的创建,可以都修改掉。

另外由于真机上跑的是 OpenGL ES 1.x/2.x/3.x,所以还有一句要处理:

var version = parseFloat( /^WebGL\ ([0-9])/.exec(gl.getParameter(gl.VERSION))[ 1 ] );
// 改为 ==>
var version = parseFloat( /^(WebGL|OpenGL ES)\ ([0-9])/.exec(gl.getParameter(gl.VERSION))[ 1 ] );

这样改过后,重新再尝试一下看,是不是已经可以了?

2018-01-08 更新

临时解决方案使用后,我后来尝试修改 weapp-adapter.js,就不需要再对 three.js 进行修改了:

createElementNS: function createElementNS(nameSpace, tagName) {
  return this.createElement(tagName)
}

方法很简单:我们在 document 的定义中添加 createElementNS,然后忽略掉 NameSpace 即可。

原文链接:https://indienova.com/indie-game-development/run-threejs-on-wechat-game-platform/

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 在微信小游戏中使用three.js显示3D图形

    笔者之前从未接触过微信小程序和WebGL的开发,但是却一直有留意相关技术的发展,大概听说原来微信小程序是不支持WebGL 3D技术的。这次借着微信大力推广小游戏...

    bering
  • CocosCreator + socketIO简易教程(更新至1.0)

    我们从已经安装了CocosCreator 懂得建立HelloWorld项目 有前台与后台交互基本思想 但是完全不知道node.js是啥 的前提开始讲 提醒...

    bering
  • Lua生成的LDoc文档注释规范

    函数参数@param 是不指明具体类型的, 若想指明的话可以用 @int, @string, @bool, @func, @tab, @thread 几个标签来...

    bering
  • 【专业技术】揭秘安卓浏览器如何注入javascript脚本

    Android中向webview注入js代码可以通过webview.loadUrl("javascript:xxx")来实现,然后就会执行javascript后...

    程序员互动联盟
  • RequireJS实例分析

      随着JS越来越庞大,已经不仅仅是以前复制粘贴做特效的时代了,JS越来越偏向于业务逻辑与应用。恰逢Node的流行,JS在web开发中占有越来越重要的地位。由...

    用户1154259
  • JavaScript常用对象&属性&事件-图标

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。

    奋飛
  • 如何动态加载js?

    第三方的js文件,自己写的js文件,js越来越多了怎么办? 提出问题: 1、js文件太多了,每个页面都写<script src="...">太麻烦。 2、如果路...

    用户1174620
  • 前端缓存

    https://juejin.im/post/5a098b5bf265da431a42b227

    城市中的游牧民族
  • 利用js文件反弹shell

    前两天在freebuf上看到一个利用Ink文件触发攻击链的文章,确实佩服作者的脑洞。

    洛米唯熊
  • webpack多入口多出口的实现

    对古老的网站进行维护, 短时间内用react或vue组件化重写全部页面不太现实,但用webpack做个打包, 还是可行性的, 配置好webpack多入口多出口,...

    zhaoolee

扫码关注云+社区

领取腾讯云代金券