[ShaderEditor3D Challenge] - 3D Plugin Integration

接着上一篇的内容

继续来挑战下一个难点:

自我入侵。

使用 Creaotr v3.x 开发的项目,作为 Creator v3.x 自己的插件,运行,并且和宿主进行交互

从某种意义上来说过,这个挑战要比上一个难度高上许多。

因为 Creator v3.x 的材质系统,一些基础概念,和 Creator v2.x 还是有很多相似的地方的。

但在框架设计上 Creator v3.xCreator v2.x 有很多不一样的地方,尤其是这次要挑战的和 启动相关的部分,更是如此。

话不多说,开始搞起来,还是要先说明下:

这只是一篇记录如何一步一步

推理 – 尝试 – 报错 – 排错 – 推理 – 尝试 – 报错 – 排错 – …

不停的循环,直到最后实现目标的流水账,没有什么太大的亮点,除了图片贼多 ~~~

Step.0

首先明确挑战的目标,需求是怎样的:

  1. 把上一次用 Creator v3.x 做的动态材质生成的项目,进行发布

  2. 将发布后的产物,包装为 Creator v3.x 标准格式的插件

  3. 确保插件可以被 Creator v3.x 的项目识别,加载并运行

Step.1

把上一次用 Creator v3.x 做的动态材质生成的项目,进行发布

这个没什么技术含量,直接发布项目为 Web-Desktop 即可

为了后续调试方便,这里发布选择了调试模式。

顺便测试下,发布的项目本身,是可以在浏览器中正常运行的。

Step.2

后续在实现功能排错的过程中,需要反复的把插件中的报错和这个网页版进行对比,或是同步调试,查看流程。

所以这里用 MAMP 单独给这个发布后的 Web-Desktop 开一个本地 Web服务器, 方便随时运行,断点调试。

Step.3

接着是:

将发布后的产物,包装为 Creator v3.x 标准格式的插件

首先是根据文档,凹一个空的插件项目出来:

扩展编辑器 · Cocos Creator

这里有详细的说明,照着做,不会有什么问题

我这里为了方便,直接就借用以前做过的 ssr-shaderfx-gallery 来快速开始:

然后就能在 扩展管理器 里面,刷到本地的插件项目了。

启用后,菜单栏里面,项目也就出现了。

Step.4

接着,来明确一下希望的实现的插件的项目架构是怎样的:

Editor / 编辑器 中有各种插件,引擎的,用户的。

这里的 MyPlugin 就是我们自己的插件。

正常情况下,在自己的插件中,可以使用各种 html + css + javascript 来进行插件的开发,也可以用一些框架 vue / react ...... 应该是怎么都行。

( 但是由于自己对这些技术都不熟悉,想要用 html + css + javascript 撸个简单的界面都要我老命,所以才有了这次挑战的出现。)

**借用 Creator v3.x 快速方便的进行可视化的界面功能,软件的调试编写,就像做游戏一样 **

将产物直接作为 Creator v3.x 自己的插件使用

这样在很大程度上降低了插件开发的学习成本,同时也在一定程度上提高了开发的效率

参照上图,这里的 Web App 其实对应的,就是前面发布出来的 Web-Desktop 项目。

这次挑战的主要点,就是让这个内置在插件中的 Web-Desktop 项目,可以被正确的加载和运行。

Step.5

明确了这个插件解决方案的结构,那就继续开干,先把 Web-Desktop 拷贝到插件项目里。

直接运行肯定是不会有任何效果的,也不会也任何报错,因为并没有人去理会这个 Web-Desktop 项目。

在网页中它能跑起来,是因为有 index.html 这个入口文件,把它给启动起来。

先来看看 index.html 这个的内容:

可以看到,和以前的 cocos2d-js / creator v2.x 的启动部分已经有了相当大的差异了,但是核心还是没变:

  1. 有个 canvas 用来渲染游戏
  2. 一些先导入的启动脚本 js
  3. 一句用于启动的代码 System.import

有了这几个点,游戏就被启动起来,并且渲染到网页中了。

Step.6

于是就照着上面的流程,来尝试修改下,在 Creator v3.x 插件系统中,相当于 index.html 地位的文件 index.js:

可以看到,3个部分正好和前面分析的 index.html 一一对上:

一堆 jsimport

一个最重要的 Canvas

一句用来启动的代码

index.html 有一句:

<script src="src/import-map.json" type="systemjs-importmap" charset="utf-8"> </script>

暂时不知道是什么鬼,就先不管它。

然后当然是运行看看:

界面什么都看不到加上一些报错,当然这也是很正常的事情,要是这么简单就能出来,那才见鬼了。

Step.7

只要有报错,那就一切好办,简单分析一下就行了。

首先这个是非常常见的一种错误,是由相对绝对路径/绝对路径造成的。

这里可以看到插件启动的时候 index.js 文件找到了 Cocos Creaator 编辑器 源码里去了。

知道问题那就好说,换换指定的文件路径试试:

再次运行:

不错,开始报别的错了,那就继续。

Step.8

看这报错,应该是开始启动加载资源报错了,那就没办法,是时候把之前准备好的网页版拿出来,跟着 System.import 大致的 Step 一下,看看有哪些流程了。

此处省略 ??? 字扒源码的流程 …

在看流程的同时,自然也就发现了前面报错相关的地方:

大致地方也找到了,那就用 同步调试 的方式,来进一步定位下可能是哪里的问题。

简单来说,就是 网页版插件版 同时运行,单步调试,对比两边的有一些数据变量,这里必然会有差异的地方,那基本就是出错的地方了。

一顿操作后,发现了可疑的地方:

插件版本中,到这里后,imports 是空的。

但是网页版,确有着明确的值。

这里看着 importMap 有点眼熟,突然想到了前面因为搞不懂用处,没有去管的代码:

<script src="src/import-map.json" type="systemjs-importmap" charset="utf-8"> </script>

看来和这个是有点关系了。

Step.9

继续推理,import-map.json 这文件是有的:

{
  "imports": {
    "cc": "./../cocos-js/cc.js",
    "wait-for-ammo-instantiation": "./../cocos-js/wait-for-ammo-instantiation.js"
  }
}

内容看着就很像上面报错相关的东西,显然这个东西不能不管。

实际的网页版中,用的是下面的代码:

<script src="src/import-map.json" type="systemjs-importmap" charset="utf-8"> </script>

这里因为实在不知道对应成代码应该是什么样的,于是尝试了:

require("../ssr-shaderfx-gallery/src/import-map.js");

但是,同样还是报错。

显然不能乱写。

type="systemjs-importmap"

这个部分还是很特别的,于是试着源码里找一找:

找到了地方,果然是有特殊的操作的。

于是继续跟一跟,主要想看下,这个到底是要 import 个啥。

最后发现,做的事情,其实差不多就是把 import-map.json 里配置好的代码,加载到这个 imports 的部分。

知道了怎么用,用来干嘛,那就直接尝试暴力赋值试一试,你(引擎)要什么,我就让你获取到什么 :

执行一看,果然不报错了:

但是再细看,发现遇到了更麻烦的问题,卡死

整个插件卡死了,界面卡死,DevTools 卡死,所以没有继续的输出了

原来不是搞定了 ~~~

Step.10

说实话,这个是比较麻烦的情况,你要有个报错,还可以看看堆栈,搞搞,啥都没有,这就不妙了。

不过推理还是可以继续的

出错的大致部分,可以肯定是在资源加载这段,既然是卡死了,那么八成就是死循环了。

既然如此,直接在引擎的几个启动文件中,搜索类似 do while 的部分即可。

听着很合理,那就开始查,往死里查 ~~~

此处省略 ??? 字断点调试的的流程 …

终于,找到了 凶手:

这段代码主要是 解析文件路径用的,具体功能不去深究, 正常情况下,这些输入的待解析路径是长这样的:

http://localhost:8888/3d/cocos-js/wait-for-ammo-instantiation.js

于是不停循环找前一个 / ,知道最后都没找到合适的话,就返回。

但是插件中,这里的路径是我写死的:

/Users/....../cocos-js/wait-for-ammo-instantiation.js

没想到的是,上面的 do while 在这 / 开头的字符串的情况下,就会死循环了…

知道了原因,那就改一下:

file:///Users/....../cocos-js/wait-for-ammo-instantiation.js

可以看到,死循环过了,插件没有被卡死,接着输出了下面的报错,很熟悉的报错不是什么大问题。

Step.11

经历了上面这些过程,这样的报错实在是太简单了,直接快速的定位解决:



这样一来,数据就读到了,那就跑起来继续走。

看到这里,因为有了过去 Creator v2.x 同样的解决方案研究的经历,其实就知道,启动加载的部分基本已经过去,至于是否正确,那得等到看到成功启动的插件内的界面才知道。

Step.12

继续定位上面的报错,非常简单:

为什么找不到呢,那肯定是因为发布的网页版项目和现在处于插件环境的项目,在 DOM 结构上是有区别的:

插件系统中,想要的 Canvas 在这里。

那么就简单了,改改代码:

Canvas 就到手了。

继续走,惊讶的发现,竟然已经可以看到 Splash 的部分了:

报错的内容,也还是熟悉的味道。

Step.13

再次定位错误:

这个好说,简单改一下:

继续走:

终于,看到想要看到的东西了。

Step.14

到这里其实基本就挑战成功了。顺便继续试试这个方案有没有之前 Creator v2.x 遇到的不足的地方。

首先是 float 状态缩放,界面是否能完美的实时适配:

不错,适配自动就是完美的。

接着试试,float 切换 dock 是否会有报错问题:

没有问题,float 切换 dock再切回来,全部都没有任何报错。

一点小问题是 dock 状态下,界面适配有点小瑕疵,不过这点小问题,后续肯定可以解决的,暂且忽略。


到这里,这次的挑战基本就结束了。

虽然期间有很多 Hard Code 的部分,不过这些知识为了快速进行可行性尝试而写的,后续在整理成框架和解决方案的时候,替换成变量就可以了。

因为有了之前 Creator v2.x 的转换插件的经验,这次的挑战少走了不少的弯路,否则估计也很难搞个半天就能够成功的实现想要的效果。


难点还有一个,蓝图框架的 Creator v3.x 化。

不过这个活其实就是一个 jsts 的事情,加上把一些用到的 v2/v3 有差别的组件进行翻译的过程。

难度应该不高,可惜自己 ts 完全不会,这个翻译估计又要趟不少坑,不知道是不是有什么工具,可以自动把之前全套 js 代码的结构,转换成 ts 风格的,内部调整当然我可以自己慢慢来。

不管怎样,下个挑战,继续 ~~~

牛蛙牛蛙,学不废了