V7投稿|如何在项目中开发并使用WebAssembly(WASM)来了

导读:本文主要是介绍下wasm的开发跟使用环境,后面关键说明如何使用Rust的wasm-pack打包出来的wasm程序,并在cocoscreator中导入并使用。

如果没了解过这一块的,建议从头开始读读,我分享了一些这半年来收集的相关资料。

如果您之前已经了解过Rust开发,并且能将wasm打包出来的,但还没在CocosCreator的环境运行起来的,可以直接跳过前面资料部分,看《在cocoscreator使用wasm的几个关键点》。

Wasmsupportplatform
wasm的环境支持,可以看上面这张图。大抵的意思就是旧的不行,新的基本上没问题,都支持。

在移动端除了 android 4.4 和 ios 10 下不支持外,其他版本都能提供支持。还需要注意的是 wasm 有可能占用大量内存,使用第三方包含 wasm 调用的组件需要注意内存占用防止闪退。

wasm模块 可以用多种语言来编译,包括 C/C++/C#、Rust、JAVA、Go。在这里使用 Rust 是因为它有严格的内存管理机制,从语法上尽量避免内存溢出,让工程师写出更安全的程序。
https://docs.cocos.com/creator/manual/zh/scripting/wasm-support.html

cocos官网文档对WebAssembly的描述,这里也表明了,一些旧的环境下,是不支持wasm的,所以要不要使用,还是可以看下上面的支持环境再做决定。

什么环境下才有必要使用wasm

  1. wasm可以使用二进制程序处理一些计算量大的处理。

  2. 加密代码,因为编译成二进制程序了,所以反编译出来,阅读困难程度还是超级加倍滴。

  3. 相反的,如果只是简单的隐藏调用的小部分代码,使用wasm时会有大量的js跟wasm的转换跟调用,反而会有点点影响效率。

  4. 如果想在微信小游戏环境下使用wasm来避过审核机制,这个是不行的,这个会在最后面微信小游戏的使用中说明为什么。

Rust主要四大模块

  1. 命令行工具:用来做一些项目的辅助工具非常方便,Rust有成熟的库(crate.io)编译出来的可执行文件又小,运行速度也相当滴快。

  2. WebAssembly:您懂的~

  3. 网络程序开发:无论是网络客户端还是服务器,转发端都是非常推荐的,独有的程序语言特点,让它拥有速度快,稳定性强,还有内存安全等特点。

  4. 嵌入式开发:还没多了解,有兴趣的话请自动查看下官方文档 https://www.rust-lang.org/what/embedded

Rust开发wasm相关的学习资源

Rust官网 https://www.rust-lang.org/

https://doc.rust-lang.org/book/
Rust的基础教程,主要是看看各种语法的使用,学习时请多关注下借用及所有权,这点在Rust语言中比较新鲜,刚学习时会有点不适,多练习就习惯了。

https://rustwasm.github.io/docs/book/
Rust开发wasm的基础教程,包括wasm-pack的安装使用

https://rustwasm.github.io/docs/wasm-bindgen/examples/index.html
Rust开发wasm的一些官方实例,特别注意下,这里展示的web_js库在浏览器是没问题的,但cocos的安卓版本中是没跑起来的,所以如果有原生的需求,请避开用这个库。

https://crates.io/
Rust的三方库,有很多高质量的轮子可以用,省去了很多功夫。

刷一遍上面的教程,基本上用来开发Rust是够够的。如果您的学习时间有限,也可以学下rust与wasm的基础教程即可,剩下的有需要的时候再找资料。

在cocoscreator使用wasm的几个关键点

  1. 打包,wasm-pack可以将wasm打包到不同的环境中(bundler, nodejs, web, no-modules)使用。由于我们要用在cocoscreator的web或原生端中,所以这里选择web环境。

  2. 打包时记得给命令增加一个–release的标记,打出来的程序会小一些。

  3. 打包命令里加上 --no-typescript 的标记,这里我们用不上这个ts的描述文件,直接使用js文件来运行wasm。并且,把生成的js文件,后缀名改成.ts,方便使用。

  4. 生成出来的wasm文件,在原生端里使用,要通过二进制的形式去加载,目前我找到的方式是把文件扩展名改成.bin。

  5. 在项目里写一个Component,然后声明一个BufferAsset,把上面生成的.bin文件挂进去

@property(BufferAsset) wasm_asset!: BufferAsset;
  1. 引用wasm-pack打包出来的js文件里的默认方法:
import { initSync } from "kkwasm";  // 这里kkwasm为您导出的js文件
  1. 找个方法把wasm引入并初始化。
start_init_api() {
 let wasm_buffer: ArrayBuffer | string = this.wasm_asset?.buffer();
​  initSync(wasm_buffer);
​}
  1. 至此,wasm的初始化就完成了。您在rust代码里实现的所有方法,结构体,都可以在这里完成后开始使用。

  2. 在微信小游戏环境中的使用。微信官方应该是对wasm的引入做了特殊处理,所以要用这样的方法来导入wasm。这也是上面说过不能用wasm来规避审核的原因。

  3. 这里的初始化就不能用二进制文件了,要保留wasm-pack生成的.wasm扩展名。
    可以走cocoscreator的build-templates方式,把.wasm的文件拷进去,这样每次发布微信小游戏的时候就不需要再手动去拷贝到项目里。

  4. 初始化的方法还是用第6步引入的方法initSync,这里还要对生成的js文件进行处理。

  5. 然后在cocos的项目代码里,特殊处理一下在微信小游戏环境中的引入:

 initSync("/kkwasm_bg.wasm");     
// 假设您生成的wasm程序文件名叫kkwasm_bg.wasm,这个文件要放在微信小游戏的工程目录下

测试过的运行环境

  1. web端,chrome及edge的浏览器都测试过,没发现有什么问题。

  2. 原生端,安卓测试过。ios环境没钱买设备,测不起测不起,盲猜应该是没问题的,因为跟安卓原生端用的同一套底层。

  3. 微信小游戏,按照上面的流程去设置,也是可以正常测试过的。具体的生产环境应该也是可以。

展望跟构想

  1. 目前整套流程是可以跑的,我还没应用到具体的生产环境中,所以如果在这方面发力的您,请多做测试之后再使用,避免开发到一半要推倒重来。

  2. 用js去调用wasm确实挺爽的,我自己写的时候,可以把一些底层代码隐藏起来,还能编译一些rust的库过来用。不用重复造轮子,还能得到更高的效率。

  3. wasm的使用还是有很大的意义的。像unity打包成webgl,甚至到微信小游戏,抖小等等环境,也是把底层打包成wasm。

  4. 我选择rust来写wasm,是因为它确实带来了很多方便的地方,虽然目前还没有百分百地如意,但能在项目中使用wasm,还是有机会能提升一部分的游戏性能的。

  5. 如果您喜欢这篇分享,帮忙点个赞呗,收藏下。谢谢~

rust开发wasm并在cocoscreator中使用的实例:

  1. 用RUST开发WASM实例:使用MD5
7赞

这次投搞很踊跃啊,大神们都来了

这是硬货啊

干货满满啊

其实用loadany也可以加载wasm文件loadany(“wasm资源uuid”, (err, buf:bufferAsset)=》{})或者自定义加载流程也行image

1赞

嗯,也是种方法,能提取到二进制。

好家伙,rust都用上了

wasm-pack 导出时,target是选择web还是no-modules呢?导出的js文件是怎么应用到工程上呢?

大佬再出个c++转wasm 在cocos中应用的吧

大佬牛逼,学废了

楼主在不今天看了看rust然后 写了一个简单的函数然后我用wasm-pack打包出了对应的.wasm .js .d.ts文件但是导入creator 3.8.2 要么报错找不到模块,要么报Unexpected export statement in CJS module 到底是哪里姿势不对!

导出web,js改扩展名为ts,然后放项目里就可以直接用。

不要导出.d.ts哈,最早在研究这个的时候,我也想把.d.ts文件也弄进去,智能提示会方便很多,最后发现不行。
可能是我对ts的引用理解有限,最后还是用了折中的办法。
按上面写的流程操作,就可以将rust导出的wasm,放到cocoscreator里面使用。

这个没研究过,C++转完还要转js的胶水代码,不知道有没现成的工具链可以处理。

我昨天已经搞定了,测试了一下循环做一亿次加法性能就js的一半 :joy:image

:smiley: 盲猜你是在js里面循环调用 1亿法wasm的方法? 如果是的话,可以试下把循环写到wasm再对比一下。

当然是wasm里面啊image

:astonished:这个真的很硬

image
image
参照你的代码试了一下1加到1亿,得到一样的结果,wasm耗时是1-2毫秒,js是100毫秒+

这么神奇吗,是不是编译有什么优化,为什么差距那么大
image
image

wasm-pack build --target web --out-dir pkg --release