概要
- UI 部分,由
HTML+CSS
实现 - 图形绘制部分,由
Unity
实现 - 【通信方向:
Web 应用
=>WebGL项目(iframe组件)
=>Unity
】下拉框切换方块颜色 - 【通信方向:
Unity
=>WebGL项目(iframe组件)
=>Web 应用
】场景加载完成通知、物体聚焦/失焦
Demo 预览
初始化 Unity 项目
新建项目
替换案例场景
添加物体至场景,并附上 tag
脚本绑定
相机
- 拖拽场景,相机基于方块物体,进行环绕运动
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public class MouseDragger : MonoBehaviour
{
public Transform target; // 获取跟随目标(围绕中心)
public float speed = 10; // 自动环绕速度
private void Update()
{
cameraRotate();
cameraZoom();
}
// 左键:手动环绕
private void cameraRotate() //摄像机围绕目标旋转操作
{
transform.RotateAround(target.position, Vector3.up, speed * Time.deltaTime); // 自动环绕目标
var mouse_x = Input.GetAxis("Mouse X"); // 获取鼠标 X 轴移动
var mouse_y = -Input.GetAxis("Mouse Y"); // 获取鼠标 Y 轴移动
if (Input.GetKey(KeyCode.Mouse0))
{
transform.RotateAround(target.transform.position, Vector3.up, mouse_x * 5);
transform.RotateAround(target.transform.position, transform.right, mouse_y * 5);
}
}
// 滚轮:缩放
private void cameraZoom()
{
if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
transform.Translate(Vector3.forward * 0.5f);
}
if (Input.GetAxis("Mouse ScrollWheel") < 0)
{
transform.Translate(Vector3.forward * -0.5f);
}
}
}
- 光线投射,判断物体是否获取焦点
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public class RayDetection : MonoBehaviour
{
// 事件:聚焦,射线命中对应 tag 的物体
[DllImport("__Internal")]
private static extern void FocusEventUnity(string objectName, string mousePosition);
// 事件:失焦
[DllImport("__Internal")]
private static extern void UnfocusEventUnity();
private UnityEngine.Ray ray;
private RaycastHit hit;
private string nameObject; // 用于节流,减少事件触发次数
private bool isFocus = false; // 用于节流,减少事件触发次数
private float widthScreen;
private float heightScreen;
private void Start()
{
getSizeScreen();
}
private void Update()
{
rayJudgment();
}
// 获取视窗尺寸
private void getSizeScreen()
{
widthScreen = UnityEngine.Screen.width;
heightScreen = UnityEngine.Screen.height;
}
// 获取鼠标位置
private string getMousePosition()
{
Vector3 mousePosition = Input.mousePosition;
string res = mousePosition.x + "," + (heightScreen - mousePosition.y);
return res;
}
// 鼠标悬浮:光线投射到场景,判断是否穿过物体
private void rayJudgment()
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 100) && hit.collider.tag == "target")
{
if (nameObject != hit.collider.name)
{
isFocus = true;
nameObject = hit.collider.name;
string mousePosition = getMousePosition();
Debug.Log(mousePosition);
#if UNITY_WEBGL
FocusEventUnity(hit.collider.name, mousePosition);
#endif
}
}
else
{
if (isFocus)
{
isFocus = false;
nameObject = null;
#if UNITY_WEBGL
UnfocusEventUnity();
#endif
}
}
}
}
- 判断 Unity 是否加载完成
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public class LoadDetection : MonoBehaviour
{
// 事件:场景加载完成
[DllImport("__Internal")]
private static extern void LoadedEventUnity();
void Start()
{
#if UNITY_WEBGL
LoadedEventUnity();
#endif
}
}
方块(切换颜色)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ChangeMaterial : MonoBehaviour
{
private void ChangeMaterialColor(string colorKey)
{
Dictionary colorDictionary = new Dictionary();
colorDictionary.Add("red", Color.red);
colorDictionary.Add("green", Color.green);
colorDictionary.Add("blue", Color.blue);
gameObject.GetComponent().material.color = colorDictionary[colorKey];
}
}
新建 Plugins 目录,定义 jslib
作用:提供内部接口,便于 Unity 调用 JavaScript 接口
var param = {
LoadedEventUnity: function () {
window.LoadedEventUnity();
},
FocusEventUnity: function (objectName, mousePosition) {
window.FocusEventUnity(Pointer_stringify(objectName), Pointer_stringify(mousePosition));
},
UnfocusEventUnity: function () {
window.UnfocusEventUnity();
}
}
mergeInto(LibraryManager.library, param);
构建 WebGL 项目
创建构建目录
- Dist:Unity 构建输出
- index.css:
Web 应用
样式 - index.html:
Web 应用
入口 - JSBridge.js:
Unity
与WebGL项目(iframe组件)
的通信接口定义 - unityWebGL.css:
WebGL项目(iframe组件)
样式
输出构建内容
清理无用文件(TemplateData 目录)
编辑代码 WebGL项目(iframe组件)
入口(Dist/index.html)
Unity WebGL Player | VueUnityCommunication
样式(unityWebGL.css)
body {
margin: 0;
}
#unityContainer {
background: none !important;
visibility: hidden;
}
JSBridge.js
const unityInstance = UnityLoader.instantiate("unityContainer", "Build/Dist.json")
const parentWindow = window.parent
// 隐藏 Unity 个人版欢迎 Brand(也可以在加载期间,显示自定义的 html loading 组件)
window.LoadedEventUnity = () => {
document.querySelector('#unityContainer').style.visibility = 'visible'
}
// 调用父级页面 showObjectInfo 函数,显示物体信息
window.FocusEventUnity = (objectName, mousePosition) => {
parentWindow.showObjectInfoCard(objectName, mousePosition)
}
// 调用父级页面 hideObjectInfo 函数,隐藏物体信息
window.UnfocusEventUnity = () => {
parentWindow.hideObjectInfoCard()
}
window.ChangeMaterialColor = colorKey => {
unityInstance.SendMessage('Cube', 'ChangeMaterialColor', colorKey)
}
编辑代码 Web 应用
入口(index.html)
Document
样式(index.css)
body {
position: relative;
}
#iframeUnity {
background-color: #ccc;
}
#colorPicker {
margin: 16px;
position: absolute;
top: 0;
left: 0;
}
#infoCard {
padding: 16px;
position: absolute;
background-color: #ccc;
visibility: hidden;
}
运行 Demo
此处使用基于 nodejs 的静态服务器启动工具
anywhere
cd VueUnityCommunication/Build
anywhere