阅读 230

Unity模块嵌入React项目

本文旨在说明怎样将Unity项目打包成WebGL资源引入React项目并实现通信

Unity打包为WebGL

image.png

  1. 在Unity的主菜单中选择File -> Build Settings... 打开打包弹窗????

image.png

Unity 默认不安装打包为 WebGL 的插件,需要自己在 Unity Hub 按照提示安装插件

  1. 点击????弹窗左下角的 Player Settings... 按钮,打开打包配置弹窗,这一步最重要的就是将 Publishing Settings 配置中的 Compression Format 压缩方式改为 Disabled 不压缩,其他配置可参考文档进行配置也可直接使用默认条件

image.png

image.png

  1. 点击 Build Settings 弹窗右下角的 Build / Build And Run 按钮,区别在于 Build And Run 按钮不仅会打包还会自动开启一个本地服务器运行打包好的 WebGl 项目。这一步需要注意的是,点击打包后需要选择打包项目存放的文件夹,一定要放在本项目的根目录下,即与Assets文件夹同级。

  2. 打包得到index.html入口文件和Build、TemplateData两个文件夹,index.html对后续引入无用。

image.png

React项目引入

本项目使用 create-react-app 创建一个单页的React项目,官方文档:zh-hans.reactjs.org/docs/create…

本项目使用第三方插件 react-unity-webgl 在 React 项目中加载由 Unity 项目打包得到的 WebGL 资源,官方文档:github.com/jeffreylant…

插件安装

$ npm install react-unity-webgl@8.x  # For Unity 2020 and 2021 (Current) 复制代码

使用npm安装,因本项目使用的Unity版本为2020,因此需安装8.x版本

模块引入与显示

  1. 将打包得到的 Build、TemplateData 文件放在React项目的public文件夹下

image.png

  1. 在组件中使用资源,示例代码:

// App.js import React from "react"; import Unity, { UnityContext } from "react-unity-webgl"; const unityContext = new UnityContext({   loaderUrl: "Build/beidou3Dweb.loader.js", // public下目录   dataUrl: "Build/beidou3Dweb.data",   frameworkUrl: "Build/beidou3Dweb.framework.js",   codeUrl: "Build/beidou3Dweb.wasm", }); function App() {   // 一定要给Unity组件设置width和height属性,否则Canvas将无限增大最终导致浏览器卡死   return <Unity style={{'width': '100%', 'height': '100%'}} unityContext={unityContext} />; } export default App; 复制代码

此时页面中会显示一个Canvas,Canvas中即是Unity项目的Game页面。

React到Unity的通信

通信是通过调用 UnityContext 实例的 send 方法实现的,该 send 方法可以指定 Unity 项目中需要调用的 GameObject 名称以及该 GameObject 上绑定的需要执行函数的名称,此外还可以传递一个 number / string / boolean 类型的参数,注意只能传一个(或不传)。在 React 触发 send 后,Unity 中的对应函数将执行,从而完成一次通信。

  • React中的代码:

// React App.js import React, { useState, useEffect }  from "react"; import Unity, { UnityContext } from "react-unity-webgl"; import { Button } from 'antd'; import './index.less'; const unityContext = new UnityContext({   loaderUrl: "Build/beidou3Dweb.loader.js",   dataUrl: "Build/beidou3Dweb.data",   frameworkUrl: "Build/beidou3Dweb.framework.js",   codeUrl: "Build/beidou3Dweb.wasm", }); function App() {   function spawnEnemies() {     unityContext.send("ConnectObject", "SpawnEnemies", "Some Message"); // 调用send函数     // ConnectObject为游戏对象名称(全局唯一)     // SpawnEnemies为ConnectObject上的回调函数名     // "Some Message"为需要传递的参数,此处为string类型   return (     <div className="container">       <Unity style={{'width': '100%', 'height': '100%'}} unityContext={unityContext} />       <Button type="primary" onClick={spawnEnemies}>To Unity</Button>     </div>   ); } export default App; 复制代码

  • Unity中的代码:

// Unity中的 CummunicateTest.cs 文件,一般放在Script文件夹下 // 绑定在名为 ConnectObject 的 Panel 游戏对象上 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class CummunicateTest : MonoBehaviour {     public Text text; // 绑定为Panel下的一个Text     public void SpawnEnemies (string amount) { // 该方法必须是公共的       text.text = amount; // 根据传参改变Text的文字     } } 复制代码

image.png

Unity到React的通信

通信是通过在Unity中的C#文件引入并调用中间层.jslib文件中的函数触发事件并携带需要传递的参数,而后在React中的UnityContext实例上通过on监听该事件并执行回调函数拿到传递参数实现的。

需要注意的是.jslib文件必须放在 Assets/Plugins/WebGL 目录下,如果默认没有这个目录就自己建!

image.png

关于怎么创建.jslib,使用mac的同学直接改后缀即可,使用Windows的同学就自己加油Google吧~

  • Unity 中的文件

// MyPlugin.jslib mergeInto(LibraryManager.library, {   GameOver: function (userName, score) {     ReactUnityWebGL.GameOver(Pointer_stringify(userName), score);   }, }); 复制代码

// Unity中的 CummunicateTest.cs 文件,一般放在Script文件夹下 // 绑定在名为 ConnectObject 的 Panel 游戏对象上 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System.Runtime.InteropServices; public class CummunicateTest : MonoBehaviour {     public Button btn;     public Text text;     [DllImport("__Internal")] // 引入并声明.jslib中定义的GameOver函数     private static extern void GameOver(string userName, int score);     // Start is called before the first frame update     void Start()     {         btn.onClick.AddListener(() => { // 点击按钮时调用GameOver函数传参             GameOver("xinghui", 100);         });     }     public void SpawnEnemies (string amount) {       text.text = amount;     } } 复制代码

  • React中的文件

import React, { useState, useEffect }  from "react"; import Unity, { UnityContext } from "react-unity-webgl"; import { Button } from 'antd'; import './index.less'; import fullScreenIconImage from '../../images/threeShow/fullScreenIcon.png'; const unityContext = new UnityContext({   loaderUrl: "Build/beidou3Dweb.loader.js",   dataUrl: "Build/beidou3Dweb.data",   frameworkUrl: "Build/beidou3Dweb.framework.js",   codeUrl: "Build/beidou3Dweb.wasm", }); function App() {   const [isGameOver, setIsGameOver] = useState(false);   const [userName, setUserName] = useState("");   const [score, setScore] = useState(0);   useEffect(function () {     unityContext.on("GameOver", function (userName, score) { // 监听GameOver事件       setIsGameOver(true);       setUserName(userName);       setScore(score);     });   }, []);   function spawnEnemies() {     unityContext.send("ConnectObject", "SpawnEnemies", "Some Message");   }   function setUnityFullScreen() {     unityContext.setFullscreen(true); // 设置Unity的Canvas全屏展示   }   return (     <div className="three-show-container">       <img className="full-screen-icon" src={fullScreenIconImage} alt="全屏" onClick={setUnityFullScreen} />       <Unity style={{'width': '100%', 'height': '100%'}} unityContext={unityContext} />       {isGameOver === true && <p>{`From Unity ${userName} ${score}`}</p>}       <Button type="primary" onClick={spawnEnemies}>To Unity</Button>     </div>   ); } export default App; 复制代码

最终实现效果是点击React中的按钮,Unity中的文字变为“Some Message”;点击Unity中的按钮,React中显示“From Unity xinghui 100”,双向通信实现。


作者:星惠-CG
链接:https://juejin.cn/post/7028100780364152846


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐