首页 > 其他分享 >Unity 小游戏转换(一)—— WebGL+XLua导出

Unity 小游戏转换(一)—— WebGL+XLua导出

时间:2024-06-23 15:11:40浏览次数:25  
标签:ab .. WebGL XLua Unity 小游戏 加载

转载或者引用本文内容请注明来源及原作者

一、前言

  • 小游戏的红海赛道,给游戏市场带来了新的活力。小游戏依托微信、抖音等第三方平台,因为买量成本较低、开箱既玩的特性,使得许多开发厂商开始布局小游戏平台。同时Unity引擎也花费了大量的精力(团结引擎),慢慢更改开发者对于Unity庞大繁重,不适合开发微信小游戏的刻板印象,目前市面上已经有多款Unity引擎开发的游戏经受了市场的检验。当Unity引擎解决了这个核心的缺点,Unity引擎在统一公司开发栈、可编程渲染管线、活跃的社区平台、良好的插件生态等方面,具有别的引擎系统无法比拟的优势。
  • 可以想象,当游戏开发初期,可以通过Windows、Android等平台,快速验证游戏玩法,确定游戏原型。后期可以根据公司策略,快速导出不同平台进行发布。同时Unity在表现力上有更高的上限,也能够保证美术效果的还原。
  • 当然,Unity通向小游戏的路上,最重要的一点就是导出WebGL工程。当整个工程能够导出WebGL工程并运行,后续的小游戏处理工作,大部分只需要对接不同平台的SDK即可。

二、WebGL导出

本文不讨论WebGL的导出流程,我们聚焦于Web平台 + XLua构建遇到一些棘手的问题。详细的导出教程推荐构建和运行 WebGL 项目(Unity官方文档)Unity WebGL 开发指北(完全篇)等等

1. 如何引入XLua

  • 步骤1:将WebGLPlugins放到工程的Assets同级目录下

    • 注意:官方使用的Xlua版本为Lua5.3,如果使用低版本或者LuaJit需要注意业务语法是否支持。
      • LuaJit中会处理迭代安全(列表遍历移除自身),而Lua5.3中则不会
      • string.format("%p", value)在标准Lua5.3中不可用,是LuaJit的拓展方法
      • Lua5.3不支持math.pow,通过拓展math方法进行解决
  • 步骤2:在Assets/Plugins/WebGL下创建一个Include文件,用来声明用到的lua库文件。这里我取名叫xlua_webgl.cpp,将第一步骤下的WebGLPlugins内的lua文件加到这个声明文件中(当然也可以包含自己写的C文件),逻辑代码如下:

    • extern "C" {
      #include "../../../WebGLPlugins/lapi.c"
      #include "../../../WebGLPlugins/lauxlib.c"
          等等...
      #include "../../../WebGLPlugins/perflib.c"
      #include "../../../WebGLPlugins/xlua.c"
      }
      

2. 脚本编码格式问题

  • 问题:

    • 当你导出的WebGL工程运行起来遇到这个问题:unexpected symbol near '<\239>',意味着你遇到了编码格式的问题。最常见的原因是你的文件中包含了UTF-8的BOM(Byte Order Mark,字节顺序标记)。BOM是一个可选的字符,用于标记文件大端还是小端。它的二进制表示为 "11101111 10111011 10111111",转换为十六进制就是 "\xEF\xBB\xBF"。很多文本编辑器在保存UTF-8文件时会自动添加BOM,但是一些语言处理器(如Lua、PHP和JavaScript等)不识别BOM,它们会把BOM当成一个不可识别的字符而报错。

  • 解决方法:

    • 通过命令行快速的处理: grep -r -i -l $'^\xEF\xBB\xBF' . | xargs sed -i 's/^\xEF\xBB\xBF//g' ,就是递归地在当前目录下删除所有文件中的BOM。
  • 原因:

    • 为什么在App中不需要关心字符编码,但是网页端却需要呢?原因在Web开发中,字符编码的设置非常关键,因为它直接决定了用户看到的网页内容是否会出现乱码。因此,开发者需要在网页的头部明确指定字符编码,这样浏览器才能正确地解析和显示网页。但是,如果服务器发送的字符编码和网页头部的字符编码设置不一致,或者文本中包含了某些特殊字符(如BOM),就可能会导致显示问题。
    • 而App的开发和Web开发不同,编码问题相对要少一些,这主要是因为App中的字符串和文本通常都是开发者直接控制的,而且很多编程语言都默认支持UTF-8,并且能够处理一些特殊字符。另外,App的界面也不依赖浏览器去渲染,而是由操作系统直接绘制,因此它们不太可能因为字符编码的问题出现显示错误。

3. 禁止使用任何 .NET 网络类

  • 问题:
    • 当你在App上通过Socket与服务端建立连接的逻辑,在WebGL上会发现连握手都握不上
  • 解决方法:
  • 原因:
    • JavaScript 代码无法直接访问互联网协议 (IP) 套接字来实现网络连接。具体来说,WebGL 不支持System.Net命名空间内的任何 .NET 类

4. 禁止使用阻塞代码

  • 问题:

    • 使用类似while(!www.isDone()) {}来等待业务完成,会导致WebGL工程直接卡死
  • 解决方法:

    • 通过协程,配合yield等待来完成下载。可以继承CustomYieldInstruction封装一些自己的业务加载器。类似的代码:

      public class CoroutineLoader : CustomYieldInstruction
      {
          private bool _keepWaiting;
          private string assetName;
          public override bool keepWaiting => _keepWaiting;
      
          public object asset;
      
          public CoroutineLoader(string assetName)
          {
              this.assetName = assetName;
              asset = null;
              _keepWaiting = true;
              AssetUtil.LoadAssetAsync(assetName, (cacheAsset) =>
              {
                  asset = cacheAsset;
                  _keepWaiting = false;
              });
          }
      }
      
  • 原因:

    • WebGL 是单线程执行,所以没有子线程去修改等待的变量的值,这将导致你的阻塞代码无法跳出循环,最终卡死

5. 资源同步加载

  • 问题:
    • WebGL不支持资源同步加载,以及ab文件流的异步加载,所有的ab文件都在云端存储上,需要通过UnityWebRequest进行请求
  • 解决方法:
    • 业务上所有的资源加载都通过异步加载进行,Lua上的异步封装可以参考我之前的文章Lua中优化的异步封装。如果必须使用同步接口进行加载,这边有两个解决方法:
      • 通过Resources.Load进行加载,将资源放到Resources文件夹下。WebGL在打包的时候。会将这部分的资源以二进制源文件的形式,一起编译到WASM中,使得逻辑代码可以正常同步加载
      • 通过提前加载ab文件,在确定资源所依赖的ab文件都在内存中,通过ab去加载资源,当然可以使用同步接口。项目在处理Lua文件的require接口,也是这样处理的。项目启动的时候,先将Lua所有的ab都加载到内存里面,然后在启动Lua虚拟机进行Lua的调用
  • 原因:
    • Web端是没有文件IO系统,并且因为Web开箱即用的特性,所有的资源必须在远端服务器上

6. Lua虚拟机 GC线程问题

  • 问题:

    • WebGL平台对线程支持不完善,在Lua虚拟机GC的时候,会看到Web端有个报错:ArgumentException: Destination array was not long enough. Check destIndex and length, and the array's lower bounds
  • 解决方法:

  • 原因:

    • 具体原因链接上有讨论,可以详细看一看

7. InputField在手机浏览器无法输入问题

  • 问题:
    • WebGL中无法识别InputField唤起键盘,进行输入
  • 解决方法:
    • 引入第三方库:WebGLInput,直接在挂载InputField的go上,添加WebGLInput即可
    • 这边需要注意微信小游戏平台问题,添加宏定义,小游戏平台有自己的支持方式,在使用WebInput会冲突。可以通过宏定义进行不同平台的兼容处理

8. iOS浏览器内存限制

  • 问题:
    • iOS浏览器下运行会崩溃,但是Android平台下正常运行
  • 解决方法:
    • 检查ab大小和依赖关系,尽量能够单资源单ab,减少单ab大小和ab之间的依赖关系。避免加载资源的时候,需要加载大量的ab包
    • 内存分析,看是否没有对无用资源进行内存卸载。需要严格控制运行时的运行内存
  • 原因:
    • iOS设备的浏览器内存限制取决于设备型号和操作系统版本。一般情清况下,iPhone和iPad浏览器的内存限制分别为256MB和512MB。这意味着当页面超出了内存限制时,浏览器将会崩溃。

总结

  • 当你能够导出Web端运行时,并且在Web网页上正常运行,证明已经完成了微信小游戏适配70%以上的工作
  • 特别关注iOS下,游戏运行的内存限制。可以通过Unity导出带Debug信息,结合XCode工具进行调试。当iOS性能优化成功,Android基本不会有大问题

标签:ab,..,WebGL,XLua,Unity,小游戏,加载
From: https://www.cnblogs.com/fzuljz/p/18263464

相关文章

  • Unity贪吃蛇改编【详细版】
    Bigandsmallgreedysnakes游戏概述游戏亮点通过对称的美感,设置两条贪吃蛇吧,其中一条加倍成长以及加倍减少,另一条正常成长以及减少,最终实现两条蛇对整个界面的霸占效果。过程中不断记录两条蛇的得分情况,以及吃到毒药的记录,所谓一朝被蛇咬,十年怕井绳。游戏运行的硬件环......
  • 【Unity服务器01】之AssetBundle上传加载u3d模型
    首先打开一个项目导入一个简单的场景导入怪物资源,AssetBundle知识点:1.指定资源的AssetBundle属性标签  (1)找到AssetBundle属性标签(2)A标签代表:资源目录(决定打包之后在哪个文件夹里面)     B标签代表:后缀  (3)设置AB标签      AssetBundle的......
  • Unity 编辑拓展使用Attribute 实现面板按钮
    unity面板按钮工具(1)完成效果原效果代码部分namespaceColorzoreTools{usingSystem;usingUnityEngine;publicclassTestAttribute:MonoBehaviour{[Button("测试")]publicvoidTestBtn(){//这个方法会被......
  • Unity 面试题(后续或许会更新)
    C#相关请简述拆箱和装箱装箱操作:值类型隐式转换为object类型或由此值类型实现的任何接口类型的过程。1.在堆中开辟内存空间。2.将值类型的数据复制到堆中。3.返回堆中新分配对象的地址。拆箱操作:object类型显示转换为值类型或从接口类型到实现该接口值类型的过程。1.判断......
  • 【unity开发】 C#接口使用小结(持续更新)
    C#的接口(interface)早些时候我认识的接口仅仅只是作为一个方法签名来使用但是随着学习的深入,就我感觉而言,我所认识的接口又越来越像一个抽象类了1.最基本的使用作为一个接口提供公共方法用玩家的交互判断来举一个例子吧!接口也支持使用泛型再举一个手动实现拷贝方法的接口......
  • Unity 编辑器中获取选中的文件夹、文件路径
    编辑器中获取选中的文件夹、文件路径usingUnityEditor;usingUnityEngine;usingObject=UnityEngine.Object;publicclassMyEditorScript{[MenuItem("Assets/PrintSelectedFolderPath")]staticvoidPrintSelectedFolderPath(){//第一种方式......
  • Unity手写模拟DoTween中的To功能
    usingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassDT:MonoBehaviour{publicfloatbeginValue,endValue;publicfloatbeginTime,times;publicAction<float>action;publicAct......
  • Unity3D轮转图(有回正效果)
    注意:MainCamera需要挂载PhysicsRayCaster      Hierarchy中添加UI里面的EventSystem对象(用来相应拖拽事件)usingDG.Tweening;usingSystem.Collections.Generic;usingUnityEngine;usingUnityEngine.EventSystems;usingSystem.Linq;publicclassRotat......
  • Unity初始位置初始化设置
    一、Transform面板介绍参数说明:        Position:位置;        Rotation:角度;        Scale:   比例。二、在Transform面板填写参数,如图所示:三、编写代码转换物体位置、角度、比例   1、位置转换:代码说明:        将目前游戏......
  • Unity相机及物体的移动步骤
    一、在Scenes场景文件夹建立游戏场景 二、在游戏场景里面建立游戏对象并且初始化位置1、建立游戏对象  2、初始化位置 3、把相机拉到游戏对象上(Reset一下位置)【注:这一步是操作相机的移动,物品的操作不用此步骤。】  三、建立CharacterController组件1、有Ca......