背景

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

一进公司他们使用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. python调用tushare港股通每月成交统计

    接口:ggt_monthly 描述:港股通每月成交信息,数据从2014年开始 限量:单次最大1000 积分:用户积5000积分可调取,请自行提高积分,具体请参阅本文最下方积分获取办法 注:tushar ...

  2. Optparse 简介

    optparse 这个库的主要作用是可以用为脚本提供传递命令参数功能 一个简单的例子 def main(): parser = OptionParser(usage = "usage: %p ...

  3. Error (10170): Verilog HDL syntax error at passwd.v(21) near text "if"; expecting an identifier ("if" is a reserved keyword ), or "endmodule", or a parallel statement

    你得加上时序啊笨蛋

  4. 2018-5-28-WPF-popup置顶

    title author date CreateTime categories WPF popup置顶 lindexi 2018-05-28 09:58:53 +0800 2018-2-13 17:2 ...

  5. WiFi基础知识

    自从只需少量的话费就可以将笔记本.平板电脑连接到互联网,WiFi已成为我们熟知的网络,并无处不在.Wi-Fi对于一些物联网应用十分有用,比如楼宇自动化.内部能源管理.WiFi的重要性对于我们的日常生活 ...

  6. centos7-关闭 rpcbind 服务

    1.关闭 rpcbind 服务 sudo systemctl disable rpcbind 2.关闭开机自启动 sudo  systemctl disable rpcbind 3.立即执行关闭 sy ...

  7. Java虚拟机(一)

    一.Java发展历程 Java之父,James Gosling博士 时间 事件 1991年4月 James Gosling博士领导的Green Project启动,java语言前身Oak启动 1995 ...

  8. Delphi 滚动条的使用

    DELPHI的滚动条默认发送消息格式: function TControl.Perform( Msg: Cardinal; WParam: WPARAM; LParam: LPARAM): LRESU ...

  9. 批量新增数据(BuckCopy)

    批量新增数据(BuckCopy) 使用webService传输数据时要注意,Datatable中的数据类型,以及科学计数 /// <summary> /// 批量新增数据 /// < ...

  10. WPF ListBox 横向排列

    WPF ListBox 横向排列   如果只是单纯的让ListBox可以横向配列,这样很简单,只需要更改ListBox的ItemsPanel模板就可以,例如: <ListBox><L ...