WinForm内嵌Unity3D

Unity3D可以C#脚本进行开,使用vstu2013.msi插件,可以实现在VS2013中的调试。在开发完成后,由于项目需要,需要将Unity3D嵌入到WinForm中。WinForm中的UnityWebPlayer Control可以载入Unity3D。先看效果图。

一、为了能够动态设置axUnityWebPlayer的Src,我使用用户控件来封装。看下面的代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;namespace UnityHost
{public partial class U3DPlayer : UserControl, IMessageFilter{#region 属性private String _src;/// <summary>/// Unity3D文件的路径/// </summary>public String Src{get { return _src; }private set { _src = value; }}private bool _disableMouseRight = true;/// <summary>/// 禁用鼠标右键/// </summary>public bool DisableMouseRight{get { return _disableMouseRight; }set { _disableMouseRight = value; }}#endregion#region 自定义事件//委托public delegate void ExternalCallHandler(object sender, AxUnityWebPlayerAXLib._DUnityWebPlayerAXEvents_OnExternalCallEvent e);/// <summary>/// 接收Unity调用宿主函数的消息/// </summary>[Browsable(true), Description("接收Unity调用宿主(如WinForm)函数的消息")]public event ExternalCallHandler UnityCall;//方法public void OnUnityCall(object sender, AxUnityWebPlayerAXLib._DUnityWebPlayerAXEvents_OnExternalCallEvent e){if (UnityCall != null){UnityCall(sender, e);}}#endregion#region 内部变量private AxUnityWebPlayerAXLib.AxUnityWebPlayer _axUnityWebPlayer=null;private ProgressBar _progressBarLoad=null;#endregionpublic U3DPlayer(){InitializeComponent();InitProgressBar();}private void InitProgressBar(){if (_progressBarLoad == null){_progressBarLoad = new ProgressBar();_progressBarLoad.Height = 100;_progressBarLoad.Style = ProgressBarStyle.Marquee;_progressBarLoad.Top = (this.Height - _progressBarLoad.Height) / 2;Controls.Add(_progressBarLoad);}}#region InitUnity/// <summary>/// 初始化UnityWebPlayer/// </summary>/// <param name="src">Unity3D文件的路径</param>public void InitUnity(String src){Src = src;if (!File.Exists(Src)){return;}var unity = new AxUnityWebPlayerAXLib.AxUnityWebPlayer();((System.ComponentModel.ISupportInitialize)(unity)).BeginInit();Controls.Add(unity);((System.ComponentModel.ISupportInitialize)(unity)).EndInit();unity.src = Src;//Application.StartupPath + "\\u.unity3d";  //改成自己想要的路径AxHost.State state = unity.OcxState;Controls.Remove(unity);unity.Dispose();unity = new AxUnityWebPlayerAXLib.AxUnityWebPlayer();((System.ComponentModel.ISupportInitialize)(unity)).BeginInit();this.SuspendLayout();unity.Dock = DockStyle.Fill;//unity.Name = "Unity";unity.OcxState = state;unity.TabIndex = 0;this.Controls.Add(unity); //panel1是我用的一个容器,改成this.Controls也可以((System.ComponentModel.ISupportInitialize)(unity)).EndInit();this.ResumeLayout(false);_axUnityWebPlayer = unity;if (_axUnityWebPlayer == null){throw new Exception("_axUnityWebPlayer init fail");}else{_axUnityWebPlayer.OnExternalCall += _axUnityWebPlayer_OnExternalCall;_axUnityWebPlayer.Hide();ShowProgressBar();}}#endregion#region 进度条private void ShowProgressBar(){           _progressBarLoad.Visible = true;_progressBarLoad.Left = 0;_progressBarLoad.Width = this.Width;}private void HideProgressBar(){if (_progressBarLoad!=null){_progressBarLoad.Visible = false;    }            }#endregionvoid _axUnityWebPlayer_OnExternalCall(object sender, AxUnityWebPlayerAXLib._DUnityWebPlayerAXEvents_OnExternalCallEvent e){if (e.value.StartsWith("LOAD_COMPLETE")){if (!_axUnityWebPlayer.Visible){_axUnityWebPlayer.Width = this.Width;_axUnityWebPlayer.Height = this.Height;_axUnityWebPlayer.Show();HideProgressBar();}}OnUnityCall(sender, e);}private void U3DPlayer_Load(object sender, EventArgs e){Graphics g = this.CreateGraphics();g.Clear(this.BackColor);if (DisableMouseRight){Application.AddMessageFilter(this);this.Disposed += U3DPlayer_Disposed;}}void U3DPlayer_Disposed(object sender, EventArgs e){if (DisableMouseRight){Application.RemoveMessageFilter(this);}}#region SendMessage/// <summary>/// 发送消息给Unity/// </summary>/// <param name="unityObjName">Unity中的对象名称</param>/// <param name="unityScriptyMethod">Unity脚本中的方法</param>/// <param name="val">传送的值.仅限于int、float、string</param>public void SendMessage(string unityObjName, string unityScriptyMethod, object val){if (_axUnityWebPlayer == null){return;}_axUnityWebPlayer.SendMessage(unityObjName, unityScriptyMethod, val);}#endregionprivate void U3DPlayer_MouseDown(object sender, MouseEventArgs e){}/// <summary>/// 过滤鼠标右键/// </summary>/// <param name="m"></param>/// <returns></returns>public bool PreFilterMessage(ref System.Windows.Forms.Message m){if (_axUnityWebPlayer == null){return false;}const int WM_RBUTTONDOWN = 0x204;const int WM_RBUTTONUP = 0x205;const int WM_RBUTTONDBLCLK = 0x206;// 屏蔽右键消息区域。System.Drawing.Rectangle my_Area = new System.Drawing.Rectangle(_axUnityWebPlayer.Location, _axUnityWebPlayer.Size);if (my_Area.Contains(this.PointToClient(Control.MousePosition))){switch (m.Msg){case WM_RBUTTONDOWN:return true;case WM_RBUTTONUP:return true;case WM_RBUTTONDBLCLK:return true;default:return false;}}return false;}}
}

注:代码中还实现了其他的功能,如下

1.增加InitUnity方法,方便外层控件调用。这里最关键的是OcxState,必须使用AxUnityWebPlayer才能依据Src动态产生。

2.动态增加进度条。

3.在实始化后对_axUnityWebPlayer进行隐藏,同时启动进度条,并绑定Unity的回调事件OnExternalCall。在OnExternalCall事件中,监听Unity发来的LOAD_COMPLETE值,然后判断是否显示_axUnityWebPlayer.

4.为了能让外层也收到Unity发来的消息,使用委托二次实现了OnExternalCall,也就是OnUnityCall方法。

5.SendMessage的实现,第一个参数为Unity中的对象名称,第二个参数为Unity脚本中的方法,第三个参数是传送的值(仅限于int、string,其他的会失败或者异常)。

6.继承IMessageFilter接口,捕获消息,然后过滤_axUnityWebPlayer区域内产生的鼠标右键消息,同时增加DisableMouseRight属性来控制。

7.一定要将项目调成x86的模式,否则会报“没有注册类XXX”的信息。

8.axUnityWebPlayer控件需要在工具箱中添加,如下图。

二、窗体界面的代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;namespace UnityHost
{public partial class FormHost : Form{public FormHost(){InitializeComponent();}private void buttonSendToUnity_Click(object sender, EventArgs e){String info = textBoxSendMessage.Text;if (String.IsNullOrWhiteSpace(info)){MessageBox.Show("请输入内容");return;}u3DPlayer1.SendMessage("Main Camera", "CallUnity", info);}private void FormHost_Load(object sender, EventArgs e){String src = Application.StartupPath + "\\UnityWeb\\UnityWeb.unity3d";u3DPlayer1.InitUnity(src);}private void u3DPlayer1_UnityCall(object sender, AxUnityWebPlayerAXLib._DUnityWebPlayerAXEvents_OnExternalCallEvent e){this.Text = "收到Unity的消息:" + e.value;}}
}

三、Unity3D的C#脚本


using UnityEngine;
using System.Collections;
using System;public class Main : MonoBehaviour
{private string _messageReceive = string.Empty;private bool _isButtonClick = false;private int _notifyTimeAfterLoadComplete = 3;// Use this for initializationvoid Start(){}// Update is called once per framevoid Update(){}void OnGUI(){if (GUI.Button(new Rect(100, 10, 80, 20), "测试")){_isButtonClick = !_isButtonClick;}GUI.Label(new Rect(50, 30, 150, 30), _messageReceive);if (_isButtonClick){Application.ExternalCall("ToWinform", Guid.NewGuid().ToString());_isButtonClick = false;}if (_notifyTimeAfterLoadComplete>0){Application.ExternalCall("LOAD_COMPLETE", "");_notifyTimeAfterLoadComplete--;}}void CallUnity(object val){_messageReceive = string.Format("{0}", val);}
}

注:

1.CallUnity是响应WinForm发来消息的函数。

2.Application.ExternalCall是向WinForm发出消息,第一参数是函数的名称,第二个之后的参数是函数的参数。

四、Unity3D要在WebPlayer模式下编译

转载请注明出处

代码下载http://download.csdn.net/detail/xxdddail/9277447

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/41017.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【boost网络库从青铜到王者】第五篇:asio网络编程中的同步读写的客户端和服务器示例

文章目录 1、简介2、客户端设计3、服务器设计3.1、session函数3.2、StartListen函数3、总体设计 4、效果测试5、遇到的问题5.1、服务器遇到的问题5.1.1、不用显示调用bind绑定和listen监听函数5.1.2、出现 Error occured!Error code : 10009 .Message: 提供的文件句柄无效。 [s…

Failed to execute goal org.apache.maven.plugins

原因&#xff1a; 这个文件D:\java\maven\com\ruoyi\pg-student\maven-metadata-local.xml出了问题 解决&#xff1a; 最简单的直接删除D:\java\maven\com\ruoyi\pg-student\maven-metadata-local.xml重新打包 或者把D:\java\maven\com\ruoyi\pg-student这个目录下所有文件…

2023年京东宠物食品行业数据分析(京东大数据)

宠物食品市场需求主要来自于养宠规模&#xff0c;近年来由于我国宠物数量及养宠人群的规模均在不断扩大&#xff0c;宠物相关产业和市场规模也在蓬勃发展&#xff0c;宠物食品市场也同样保持正向增长。 根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;2023年1月-7月&am…

接口自动化测试(添加课程接口调试,调试合同上传接口,合同列表查询接口,批量执行)

1、我们把信息截取一下 1.1 添加一个新的请求 1.2 对整个请求进行保存&#xff0c;Ctrl S 2、这一次我们添加的是课程添加接口&#xff0c;以后一个接口完成&#xff0c;之后Ctrl S 就能够保存 2.1 选择方法 2.2 设置请求头&#xff0c;参数数据后期我们通过配置设置就行 3、…

收银一体化-亿发2023智慧门店新零售营销策略,实现全渠道运营

伴随着互联网电商行业的兴起&#xff0c;以及用户理念的改变&#xff0c;大量用户从线下涌入线上&#xff0c;传统的线下门店人流量急剧收缩&#xff0c;门店升级几乎成为了每一个零售企业的发展之路。智慧门店新零售收银解决方案是针对传统零售企业面临的诸多挑战和问题&#…

Mathematica 与 Matlab 常见复杂指令集汇编

Mathematica 常见指令汇编 Mathematica 常见指令 NDSolve 求解结果的保存 sol NDSolve[{y[x] x^2, y[0] 0, g[x] -y[x]^2, g[0] 1}, {y, g}, {x, 0, 1}]; numericSoly sol[[1, 1, 2]]; numericSolg sol[[1, 2, 2]]; data Table[{x, numericSoly[x], numericSolg[x]},…

JVM——类加载器

回顾一下类加载过程 类加载过程&#xff1a;加载->连接->初始化。连接过程又可分为三步:验证->准备->解析。 一个非数组类的加载阶段&#xff08;加载阶段获取类的二进制字节流的动作&#xff09;是可控性最强的阶段&#xff0c;这一步我们可以去完成还可以自定义…

【计算机网络篇】UDP协议

✅作者简介&#xff1a;大家好&#xff0c;我是小杨 &#x1f4c3;个人主页&#xff1a;「小杨」的csdn博客 &#x1f433;希望大家多多支持&#x1f970;一起进步呀&#xff01; UDP协议 1&#xff0c;UDP 简介 UDP&#xff08;User Datagram Protocol&#xff09;是一种无连…

Flink学习笔记(一)

流处理 批处理应用于有界数据流的处理&#xff0c;流处理则应用于无界数据流的处理。 有界数据流&#xff1a;输入数据有明确的开始和结束。 无界数据流&#xff1a;输入数据没有明确的开始和结束&#xff0c;或者说数据是无限的&#xff0c;数据通常会随着时间变化而更新。 在…

Kaptcha的基本应用

Kaptcha Kaptcha 是一个用于生成和验证验证码的 Java 库&#xff0c;提供了丰富的生成和验证功能&#xff0c;并支持自定义配置。它可以用于增加应用程序的安全性&#xff0c;防止机器人和恶意攻击。 Kaptcha 可以生成各种类型的验证码&#xff0c;包括数字、字母、数字字母组…

KDD 2023 获奖论文公布,港中文、港科大等获最佳论文奖

ACM SIGKDD&#xff08;国际数据挖掘与知识发现大会&#xff0c;KDD&#xff09;是数据挖掘领域历史最悠久、规模最大的国际顶级学术会议&#xff0c;也是首个引入大数据、数据科学、预测分析、众包等概念的会议。 今年&#xff0c;第29届 KDD 大会于上周在美国加州长滩圆满结…

HTTP--Request详解

请求消息数据格式 请求行 请求方式 请求url 请求协议/版本 GET /login.html HTTP/1.1 请求头 客户端浏览器告诉服务器一些信息 请求头名称: 请求头值 常见的请求头&#xff1a; User-Agent&#xff1a;浏览器告诉服务器&#xff0c;我访问你使用的浏览器版本信息 可…

【日常积累】HTTP和HTTPS的区别

背景 在运维面试中&#xff0c;经常会遇到面试官提问http和https的区别&#xff0c;今天咱们先来简单了解一下。 超文本传输协议HTTP被用于在Web浏览器和网站服务器之间传递信息&#xff0c;HTTP协议以明文方式发送内容&#xff0c;不提供任何方式的数据加密&#xff0c;如果…

09- DMA(DirectMemoryAccess直接存储器访问)

DMA 09 、DMA(DirectMemoryAccess直接存储器访问)DMA配置流程 09 、DMA(DirectMemoryAccess直接存储器访问) DMA配置流程 dma.c文件 main.c文件 详见《stm32中文参考手册》表57。

tsconfig.json和jsconfig.json配置

{// 编译选项"compilerOptions": {// 生成代码的语言版本&#xff1a;将我们写的 TS 代码编译成哪个版本的 JS 代码// 命令行&#xff1a; tsc --target es5 11-测试TS配置文件.ts"target": "es5",// 指定要包含在编译中的 library"lib&quo…

3年 Android 开发的面试心经(后悔当初没有拿 N+1)

作者&#xff1a;勇闯天涯 当某人顺利通过大厂面试时&#xff0c;总会有人认为这是运气比较好罢了&#xff0c;但他们不曾得知对方之前受过多少苦和委屈&#xff0c;又付出了多少努力一步步去突破这些困境。正是因为他们的努力付出&#xff0c;在合适的时间与地点&#xff0c;用…

AlphaZero能否从围棋和国际象棋飞跃到量子计算?

一项新的研究表明&#xff0c;DeepMind惊人的游戏算法AlphaZero可以帮助释放量子计算的力量和潜力。 自两年多前出现以来&#xff0c;AlphaZero一再证明了其快速学习能力&#xff0c;将自己提升到围棋&#xff0c;国际象棋和将棋&#xff08;日本象棋&#xff09;的特级大师级别…

VHDL记录

文章目录 使用function名称作为“常量”numeric_std包集中使用乘法的注意项variable的使用对于entity设置属性的方法在entity声明中嵌入function的定义VHDL仿真读写文件File declaration/File handingFile readingFile writing小例子 使用函数 模块中打印出调试信息 使用functi…

RTC实验

一、RTC简介 RTC(Real Time Clock)即实时时钟&#xff0c;它是一个可以为系统提供精确的时间基准的元器件&#xff0c;RTC一般采用精度较高的晶振作为时钟源&#xff0c;有些RTC为了在主电源掉电时还可以工作&#xff0c;需要外加电池供电BCD码&#xff0c;四位二进制表示一位…

Java Persistence APl(JPA)——JPA是啥? SpringBoot整合JPA JPA的增删改查 条件模糊查询 多对一查询

目录 引出Jpa是啥&#xff1f;Jpa的使用创建实体类写dao接口类写服务类 crud增删改查增加修改根据id删除全查询分页查询 条件查询模糊查询单条件查询多条件查询模糊查询排序查询 多对一查询定义实体类auto主键策略下新增进行全查询测试 全部代码application.yml配置类pom配置文…