背景

最近刚换了工作,新公司不是做手游的,一开始有点抵触,总觉得不是做游戏自己就是跨行了,认为自己不对口,但是慢慢发现在这可以学的东西面很广,所以感觉又到了打怪升级的时候了,老子就在这进阶了。

一进公司他们使用H5开发,做一款地形信息系统的软件,基于Unity开发,但是所有页面都是Js写的,所以我第一件事要做的是实现Unity嵌入网页,并实现交互。

在这里,领导说之前做过类似的即用的Embedded Browser2.1.0这个插件,让我研究下做个简单Demo。

实现方案

使用插件Embedded Browser2.1.0实现unity与网页交互

具体步骤

1.Unity中导入插件

2.新建Canvas,在Canvas下创建一GameObject,平铺在Canvas上

3.将网页映射到GameObject上

这一步需要给创建的BrowserGUI挂载插件脚本

首先是Brower脚本,此脚本是设置嵌入网页的URL以及一些幕布大小等参数,在这里说下,有两种嵌入方式

,1.可以直接嵌入浏览器网页2.可以将html文件放入与Assets文件夹同级的BrowserAssets(必须一致,必须是这个文件夹,因为若放Assets下面,会自动默认为代码为UnityScript而不是JavaScript),加载嵌入,这种方式相对快一些。

再一个就是挂载GUI Brower UI脚本,这脚本是构建UI的一个作用,请求的网页会显示出来是因为这个脚本,并且会自动添加上Raw Image组件

Unity通过插件与网页的交互

1.Unity接收网页操作做出响应

C#监听代码:

js代码:

Tips:Unity接收网页推送事件RegisterFunction(“MethodName”,CallBack);

即:网页进行一系列操作,unity中监听到并响应执行事件

2.Unity做出相应操作通知网页并更新网页显示

案例:此为unity方5秒倒计时,每轮计时结束时间重置,目标数+=3;通知网页端并显示的Demo

c# 代码:

Js代码:

Tips:网页监听Unity操作:browser.CallFunction("MethodName",params).Down();

即:unity进行一系列操作,unity通知网页自身变化并调用网页更新函数

完整代码

场景1:网页点击按钮,Unity接收参数:

c#:

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using ZenFulcrum.EmbeddedBrowser;
using UnityEngine.SceneManagement;
/// <summary>
/// Unity使用插件控制脚本
/// </summary>
public class DemoTexMgr : MonoBehaviour
{
/// <summary>
/// 插件组件
/// </summary>
Browser browser;
/// <summary>
/// 监听H5操作作出响应物体
/// </summary>
public Transform targetScle; /// <summary>
/// 嵌入网页地址
/// </summary>
string URL = "file:///C:/Users/lenovo/Desktop/工作/自测需要/测试Js脚本/TextTool.html";
/// <summary>
/// 目标位置(显示同步到H5)
/// </summary>
private Vector3 targetPos;
public Vector3 TargetPos { get; set; } private void Awake()
{
//获取插件Browser组件(Unity方使用插件基础一步)
browser = transform.Find("BrowserGUI").GetComponent<Browser>();
}
void Start()
{
InitData();
}
public void Update()
{ }
/// <summary>
/// 初始化函数(初始化嵌入页面)
/// </summary>
public void InitData()
{
//设置嵌入页面网址
browser.Url = URL;
//插件前往函数
browser.GoForward();
//browser.gameObject.GetComponent<RawImage>().raycastTarget = false; //改变背景深度(透明度)
browser.gameObject.GetComponent<RawImage>().color = new Color(browser.gameObject.GetComponent<RawImage>().color.r, browser.gameObject.GetComponent<RawImage>().color.b, browser.gameObject.GetComponent<RawImage>().color.g, ); //插件中监听函数,监听H5操作(点击缩小按钮,Unity做出缩小响应)
browser.RegisterFunction("displayDate", (JSONNode jk) =>
{
Debug.Log("yuanjun Unity Get H5 参数" + jk[].AsJSON + " 参数 " + jk[].AsJSON + " " + jk[].Value);
targetScle.transform.localScale = new Vector3(0.8f, 0.8f, 0.8f);
});
browser.RegisterFunction("GetUniMethodty", (JSONNode jk) =>
{
targetScle.transform.localScale = new Vector3(float.Parse(jk[].AsJSON), 0.8f, 0.8f);
Debug.Log("yuanjun Unity Get H5 GetUniMethodty 参数1" + jk[].AsJSON);
}); } //退出按钮
public void OnClickQuitBtn()
{
Application.Quit();
}
public void ChangeBtn()
{
SceneManager.LoadScene();
}
}

js脚本:

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>类似于Jquery的JS下拉菜单</title>
6 <style type="text/css">
7 * { margin: 0; padding: 0; font-style: normal; font-family: 宋体; }
8 body { text-align: center; font-size: 12px; background:url(1.jpg) center center; }
9 #content { margin: 0 auto; width: 600px; }
10 #content #nav { height: 32px; margin-top: 60px; background-color: #464749;FILTER: alpha(opacity=80); opacity: 0.8; -moz-opacity: 0.8; }
11 #content #nav ul { list-style: none; }
12 #content #nav ul li { float: left; width: 100px; line-height: 32px; position: relative; }
13 #nav div { width: 100px;FILTER: alpha(opacity=80); opacity: 0.8; -moz-opacity: 0.8; position:absolute; left:0px; top:32px; z-index:1; padding-bottom: 0px; float: left; height: 0; overflow: hidden; background-color: #fff;color:#000; }
14 #content #nav li .a { text-decoration: none; color: #FFFFFF; line-height: 32px; display: block; border-right-width: 1px; border-right-style: solid; border-right-color: #393A3C; }
15 #nav div a { text-decoration: none; color: #000; line-height: 26px; display: block; z-index:100; }
16 #nav div a:hover { background-color: #ccc; }
17 </style>
18 </head>
19 <body>
20 <div id="content">
21 <div id="nav">
22 <ul id="supnav">
23 <li><a href="#" class="a">物体变大</a>
24 <div>
25 <button onclick="GetUniMethodty(5)">变大</button>
26 </div>
27 </li>
28 <li><a href="#" class="a">物体旋转</a>
29 <div>
30 <a href="#">物体旋转</a>
31 </div>
32 </li>
33 <li><a href="#" class="a">物体缩小</a>
34 <div>
35 <button onclick="displayDate(1,2)">缩小</button>
36 </div>
37 </li>
38 <li><a href="#" class="a">导航菜单</a>
39 <div>
40 <a href="#">导航菜单</a>
41 </div>
42 </li>
43 <li><a href="#" class="a">导航菜单</a>
44 <div>
45 <a href="#">导航菜单</a>
46 </div>
47 </li>
48 <li><a href="#" class="a">导航菜单</a>
49 <div>
50 <a href="#">导航菜单</a>
51 </div>
52 </li>
53 </ul>
54 </div>
55 </div>
56 <script type="text/javascript">
57 var supnav = document.getElementById("supnav");
58 var nav = document.getElementById("nav");
59 var btns = document.getElementsByTagName("li");
60 var subnavs = nav.getElementsByTagName("div");
61 var paddingbottom = 20;
62 var defaultHeight = 0;
63 function drop(obj, ivalue) {
64 var a = obj.offsetHeight;
65 var speed = (ivalue - obj.offsetHeight) / 8;
66 a += Math.floor(speed);
67 obj.style.height = a + "px";
68 }
69 window.onload = function() {
70 for (var i = 0; i < btns.length; i++) {
71 btns[i].index = i;
72 btns[i].onmouseover = function() {
73 var osubnav = subnavs[this.index];
74 var sublinks = osubnav.getElementsByTagName("a");
75 if (osubnav.firstChild.tagName == undefined) {
76 var itarheight = parseInt(osubnav.childNodes[1].offsetHeight) * sublinks.length + paddingbottom;
77 } else {
78 var itarheight = parseInt(osubnav.firstChild.offsetHeight) * sublinks.length + paddingbottom;
79 }
80 clearInterval(this.itimer);
81 this.itimer = setInterval(function() {
82 drop(osubnav, itarheight);
83 },
84 30);
85 }
86 btns[i].onmouseout = function() {
87 var osubnav = subnavs[this.index];
88 clearInterval(this.itimer);
89 this.itimer = setInterval(function() {
90 drop(osubnav, defaultHeight);
91 },
92 30);
93 }
94 }
95 }
96 </script>
97
98
99 <script>
100 function displayDate(a,b){
101 alert("DisPlayData " +a );
102 return a+b;
103 }
104 </script>
105
106 <script>
107 function GetUniMethodty(s){
108 alert("Data Come " +s);
109 return s;
110 }
111 </script>
112
113
114 <script>
115 function myFunction(){
116 alert("Welcome " + "Harry Potter ");
117 }
118 </script>
119
120 </body>
121 </html>

场景2:Unity中Cube移动位置,网页上位置信息更新

c#:

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using ZenFulcrum.EmbeddedBrowser;
using UnityEngine.SceneManagement;
public class DemoTesxMgrOne : MonoBehaviour
{
/// <summary>
/// 插件组件
/// </summary>
Browser browser;
/// <summary>
/// 监听H5操作作出响应物体
/// </summary>
public Transform targetScle; /// <summary>
/// 嵌入网页地址
/// </summary>
string URL = "file:///C:/Users/lenovo/Desktop/工作/自测需要/测试Js脚本/demo.html";
/// <summary>
/// 目标位置(显示同步到H5)
/// </summary>
public delegate void del(Vector3 v);
public del _del;
public Vector3 oldv;
private Vector3 targetPos;
public Vector3 TargetPos {
get {
return targetPos;
}
set
{
targetPos = value;
if (oldv!=targetPos)
{
_del(targetPos);
oldv=targetPos;
}
} } public int TextValue = ;
public float timer = ; private void Awake()
{
//获取插件Browser组件(Unity方使用插件基础一步)
browser = transform.Find("BrowserGUI").GetComponent<Browser>();
_del += calH5;
// oldv = targetScle.transform.localPosition;
}
void Start()
{
InitData();
}
public void Update()
{
TargetPos = targetScle.transform.localPosition;
//if (timer > 0)
//{
// timer -= Time.deltaTime;
//}
//else
//{
// TextValue += 3;
// timer = 5;
// browser.CallFunction("selall", TextValue).Done();
//} }
public void calH5(Vector3 v)
{
browser.CallFunction("selall", v.ToString()).Done();
}
/// <summary>
/// 初始化函数(初始化嵌入页面)
/// </summary>
public void InitData()
{
//设置嵌入页面网址
browser.Url = URL;
//插件前往函数
browser.GoForward();
//browser.gameObject.GetComponent<RawImage>().raycastTarget = false; //改变背景深度(透明度)
browser.gameObject.GetComponent<RawImage>().color = new Color(browser.gameObject.GetComponent<RawImage>().color.r, browser.gameObject.GetComponent<RawImage>().color.b, browser.gameObject.GetComponent<RawImage>().color.g, ); //插件中监听函数,监听H5操作(点击缩小按钮,Unity做出缩小响应)
//browser.RegisterFunction("displayDate", (JSONNode jk) =>
//{
// Debug.Log("yuanjun Unity Get H5 参数" + jk[0].AsJSON + " 参数 " + jk[1].AsJSON + " " + jk[0].Value);
// targetScle.transform.localScale = new Vector3(0.8f, 0.8f, 0.8f);
//});
//browser.RegisterFunction("GetUniMethodty", (JSONNode jk) =>
//{
// targetScle.transform.localScale = new Vector3(float.Parse(jk[0].AsJSON), 0.8f, 0.8f);
// Debug.Log("yuanjun Unity Get H5 GetUniMethodty 参数1" + jk[0].AsJSON);
//}); } //unity调试
public void OnClickJsData()
{//调用页面中任何可用的js(自上而下)
// browser.EvalJS("displayDate(7,5)").Then(Result =>
// { Debug.Log(Result.Value); }
//).Done();
// //查询页面中的数据,可以查看返回值(测试多返回值时好像只返回最后一个值)
//browser.CallFunction("displayDate", 1, 2).Then(Result =>
//{
// Debug.Log(" displayDate " + Result.Value);
//}); // browser.CallFunction("selall", 100).Done(); } //退出按钮
public void OnClickQuitBtn()
{
Application.Quit();
}
public void ChangeBtn()
{
SceneManager.LoadScene();
}
}

js:

1 <body>
2 <!-- 我记得复选框不是这样写的? 那个是 下拉选择框 -->
3 <input type="checkbox" id="cb1" onclick="fun0()"/>全选/全不选
4 </br>
5 <input type="checkbox" name="love">篮球<br/>
6 <input type="checkbox" name="love">足球<br/>
7 <input type="checkbox" name="love">排球<br/>
8 <input type="checkbox" name="love">冰球<br/>
9
10 <input type="button" value="全选" onclick="selall()"/>
11 <input type="button" value="全不选" onclick="selno()"/>
12 <input type="button" value="反选" onclick="selother()"/>
13 <script type="text/javascript">
14 function fun0(){
15 var cb = document.getElementById("cb1");
16 if(cb.checked==true){
17 selall();
18 }else{
19 selno();
20 }
21 }
22 function selall(a){
23 alert(a);
24 var nodes = document.getElementsByName("love");
25 for(var i = 0; i < nodes.length; i++){ //遍历节点
26 var node1 = nodes[i];
27 node1.checked = true; //把节点的checked属性设置为 true
28 }
29 }
30 function selno(){
31 var nodes = document.getElementsByName("love");
32 for(var j = 0; j < nodes.length; j++){ //遍历节点
33 //var node2 = nodes[j];
34 //node2.checked = false;
35 nodes[j].checked = false; //把节点的checked属性设置为 false
36 }
37 }
38 </script>
39 </body>

Tips:注意以上有不少冗余代码,为什么用两个场景两个网页测试,归根结底是因为我不懂Js,我想要的事件一个无法满足还不会扩展,所以,重点看方法不看代码。

我也只是跑通了,里面还有很多方法函数,我这里只是先实现了互通,理解可能不准确或者不对,热烈欢迎指出并交流。

最近:最近在做demo时,具体遇到了这么几点:

1.上面在嵌入网页时需要挂在GUI Brower UI脚本,但是在我做demo时发现,这个脚本在这个版本还可以用,但是已被编辑为过时[Obsolete("Use PointerUIGUI and CursorRendererOS instead.")],应用PointerUIGUI脚本替代。

2.

js代码:

 <!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <title>Ventilation UI</title> <style>
html {
height: 100%;
} body
{
font-family: Monospace;
font-weight: bold;
background-color: #ccccff00;
margin: 0px;
height: 100%;
overflow: hidden;
}
</style> </head>
<body>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> <div class="container">
<div class="btn-toolbar " role="toolbar" aria-label="Toolbar">
<div class="btn-group mr-2" role="group" aria-label="First Group">
<button id="createLaneway" type="button" class="btn btn-success">新建</button>
<button id="editLaneway" type="button" class="btn btn-success">编辑</button>
<button id="drawAirDuct" type="button" class="btn btn-success">绘制</button>
<button id="drawAirDoor" type="button" class="btn btn-success">绘制</button>
<button id="drawLine" type="button" class="btn btn-success">画线</button>
<button id="drawFace" type="button" class="btn btn-success">画面</button>
</div>
<div class="btn-group mr-2" role="group" aria-label="Second Group">
<button type="button" class="btn btn-success">平移</button>
<button type="button" class="btn btn-success">旋转</button>
<button type="button" class="btn btn-success">缩放</button>
</div>
<div class="btn-group" role="group" aria-label="Fourth group">
<button id="undo" type="button" class="btn btn-success">撤销</button>
<button id="redo" type="button" class="btn btn-success">重做</button>
<button id="none" type="button" class="btn btn-success">退出编辑</button>
<button id="exit" type="button" class="btn btn-success">退出程序</button>
</div>
</div>
</div> <script>
$('#createLaneway').on('click', function () { onCreateLane(); });
$('#editLaneway').on('click', function () { onEditLane(); });
$('#drawAirDuct').on('click', function () { onDrawDuct(); });
$('#drawAirDoor').on('click', function () { onDrawDoor(); });
$('#drawLine').on('click', function () { onDrawLine(); });
$('#drawFace').on('click', function () { onDrawFace(); });
$('#undo').on('click', function () { onUndo(); });
$('#redo').on('click', function () { onRedo(); });
$('#none').on('click', function () { onExitEdit(); });
$('#exit').on('click', function () { onExit(); }); function onCreateLane(e) { console.log('新建'); } function onEditLane(e) { console.log('编辑'); } function onDrawDuct(e) { console.log('绘制'); } function onDrawDoor(e) { console.log('绘制'); } // 画线事件响应
function onDrawLine(e) { console.log('画线'); } // 画面事件响应
function onDrawFace(e) { console.log('画面'); } // 撤销事件响应
function onUndo(e) { console.log('撤销'); } // 重做事件响应
function onRedo(e) { console.log('重做'); } function onExitEdit() {
console.log('退出编辑');
} function onExit() {
console.log('退出');
} //加载结束
function loadEnd() {
console.log("Load end");
} window.onload = function () { loadEnd(); } </script> </body>
</html>

这种注册按钮的方式,按着我之前说的那中监听方式会监听不到,

如:  $('#createLaneway').on('click', function () { onCreateLaneway(); });这句注册按钮代码,如果写成  $('#createLaneway').on('click',  onCreateLaneway() );就会监听不到,所以外面套了个function () { },就可以了。

3.比如你要加载完H5页面再执行逻辑,browser.WhenLoaded(StartApp());使用browser.WhenLoaded()函数,里面传Action参数,在里面可以处理写加载完页面后你想处理的事件。

4.请求地址可以在最后面写:browser.WhenReady(SetRequestURL());使用browser.WhenReady()这个函数,里面传Action参数,在里面写请求地址。如:

   private Action SetRequestURL()
{
return delegate ()
{
// 设置Url地址
browser.Url = "localGame://index.html";
};
}

Unity中嵌入网页插件Embedded Browser2.1.0的更多相关文章

  1. Unity中的 原生插件/平台交互 原理

    http://blog.csdn.net/u010019717/article/details/78451660 声明:  内容摘录自:  http://gad.qq.com/article/deta ...

  2. App中嵌入网页浏览器

    TOWebViewController 插件 NSURL *url =[NSURL URLWithString:@"http://192.168.1.134:8180/Home/IndexP ...

  3. django中嵌入百度editor插件

    一.安装和配置步骤: 1.先下载百度ueditor插件,并安装pip install DjangoUeditor 2.把下载好的ueditor插件放到自己的项目中 3.配置setting INSTAL ...

  4. C#开发ActiveX插件-aspx中嵌入

    刚到新的公司,第一周让我熟悉一下他们用的silverlight和arcgis.这周,也就是昨天分配了我一个小小的任务! 哪个项目的不知道,是让我实现一个在aspx中嵌入activeX插件! 在网上找了 ...

  5. Unity3d:使用uWebKit插件嵌入网页,网页中的flv视频无法播放

    问题描述:unity3d程序,使用uWebKit插件嵌入网页,用来播放FLV视频,有的电脑可以正常播放,有的电脑在网页中播放不了ps:网页中的播放器用的是player.swf解决方案:是由于网页中的播 ...

  6. 使用CKplayer插件在网页中嵌入视频的方法(常用笔记2)

    在做网站中有时候我们需要在网页中嵌入视频,一般视频嵌入有以下几种方法: 1. 优酷代码嵌入 优点:简单,方便,可靠. 缺点:有广告,现在的网站非常注重用户体验,如果打开一个在线视频是有长广告的一定会崩 ...

  7. 【CKplayer】使用CKplayer插件在网页中嵌入视频的方法

    在做网站中有时候我们需要在网页中嵌入视频,一般视频嵌入有以下几种方法: 1. 优酷代码嵌入 优点:简单,方便,可靠. 缺点:有广告,现在的网站非常注重用户体验,如果打开一个在线视频是有长广告的一定会崩 ...

  8. Unity中内嵌网页插件UniWebView

    一.常见Unity中内嵌网页实现方式: 1.UnityWebCore只支持windows 2.Unity-Webview支持Android,IOS 3.UniWebView支持mac os,Andro ...

  9. web网页中使用vlc插件播放相机rtsp流视频

    可参考: 使用vlc播放器做rtsp服务器 使用vlc播放器播放rtsp视频 使用vlc进行二次开发做自己的播放器 vlc功能还是很强大的,有很多的现成的二次开发接口,不需配置太多即可轻松做客户端播放 ...

随机推荐

  1. Fedora LVM磁盘大小调整

    umount /dev/fedora/swap e2fsck -f /dev/fedora/swap

  2. Zabbix Server 和 Zabbix Agentd 开机自动运行

    Zabbix Server 和 Zabbix Agentd 开机自动运行 请问:怎样 Zabbix Server 和 Zabbix Agentd 开机自动运行? 注:如果你的命令行写进了 /etc/r ...

  3. mac 密码重置

    首先请开机或重新启动系统,在电脑刚启动时,请按下键盘上的 command+S 组合键不动, 接下来会在屏幕上看到一串串的命令字符显示,当进入安全模式以后,会看到 一个 root 开始的命令行输入端口. ...

  4. python-函数-动态传参,作用域的问题,函数嵌套,global nonlocal

    ⼀. 函数参数--动态传参 之前我们说过了传参, 如果我们需要给⼀个函数传参, ⽽参数⼜是不确定的. 或者我给⼀个 函数传很多参数, 我的形参就要写很多, 很⿇烦, 怎么办呢. 我们可以考虑使⽤动态参 ...

  5. centos7上的h5ai折腾记

    过程: 安装php-fpm和nginx,且经验证二者在其他项目可以正常使用. 从debian8拷贝过来_h5ai的nginx配置如下: location ~ [^/]\.php(/|$) { fast ...

  6. 记录常用的linux命令

    原文链接:https://www.cnblogs.com/suger43894/p/11024594.html 系统信息相关 date 显示系统日期 cat /proc/mounts 显示已加载的文件 ...

  7. vue中的$nextTick的常用思路

    Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新. $nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextT ...

  8. jQuery, js 验证两次输了密码的一相同

    <div class="form-group"> <label class="col-sm-2 control-label font"> ...

  9. Yii2中的规则

    //Yii2中的规则,用户名的规则,1.用户名只能是字母 2.判断用户名已经存在 3.用户名的长度 4.用户名不能为空 [['username'], 'match', 'pattern' => ...

  10. linux IPC socket

    套接字是通讯端点的抽象 创建一个套接字 #include <sys/types.h> #include <sys/socket.h> int socket(int domain ...