找回密码
 立即注册
查看: 5719|回复: 102

[其他] 编辑器

[复制链接]
发表于 2014-10-10 13:50 | 显示全部楼层 |阅读模式
资源信息 Tutorial Information
教程名称: WPF内嵌Unity并实现双向通讯(发帖教程)
适用引擎:   (适用引擎,为空默认为Unity)
教程语种: 中文
教程等级: 1
教程格式: 图文(请用IE9以上浏览器访问本版块)
教程作者: Lolofinil (如有问题请短消息联系作者或发表回复)
下载地址: (兑换积分)
点击查看原图
美丽分割线
博客原文:http://www.lolofinil.com/2014/10/10/wpf-unity-embed-pipes/

说明
需求是这样的 —— 一个编辑器。既能够方便得编辑各种静态数据表(Excel),又能够对表中指定的资源进行预览(Spine骨骼动画)。
问题在于适合做表编辑器的软件框架,如WPF、Winform等等,都没有相应的Spine渲染库;而支持Spine渲染的框架,如Unity3D、MonoGame、Cocos2D等,又或存在Excel库不好用或者缺少软件向控件的问题。
我们采取的方案是,使用WPF做它擅长的软件功能,而使用Unity作为“渲染控件”。
技术路线
为什么不用WPF嵌入UnityWebPlayer?
将Unity嵌入WPF(或Winform),比较常见的做法是通过ActiveX将UnityWebPlayer包装成一个真正的控件。但由于UnityWebPlayer运行在安全沙箱中,它至少有以下两个问题:
  • 没有System.IO的程序集,只能够加载assetbundle,无法加载未经管线预处理的Spine
  • 没法加载Excel文件
  • 如何将Unity Windows Standalone 嵌入WPF
    将Standalone作为一个控件,指定到WPF父窗口下。采用WindowsAPI来实现。
如何实现Standalone与WPF双向通信
需要能在WPF中设定Standalone的当前Spine,也要能在Standalone上操作由WPF维护的Excel。一个可行的方案是pipes。
这篇讨论中说Unity不初始化NamedPipelineServer。那么就拿它当NamedPipelineClient好了。
将Unity Windows Standalone 嵌入WPF
核心代码如下:
// 定义一个WPF用户控件,来定义Standalone的尺寸
ProcessStartInfo info = new ProcessStartInfo(“UnityControl.exe”);
info.UseShellExecute = true;
info.WindowStyle = ProcessWindowStyle.Minimized;
m_AppProcess = System.Diagnostics.Process.Start(info);
m_AppProcess.WaitForInputIdle();
this.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.ApplicationIdle,
appIdleEvent, this, null);
// Application Idle 事件处理WindowInteropHelper helper = new WindowInteropHelper(Window.GetWindow(this));IntPtr ptr = helper.Handle;SetParent(app.MainWindowHandle, helper.Handle);SetWindowLong(new HandleRef(this, app.MainWindowHandle), GWL_STYLE, WS_VISIBLE);MoveWindow(app.MainWindowHandle, (int)control.Margin.Left, (int)control.Margin.Top, (int)control.Width, (int)control.Height, true);实现Unity Windows Standalone与WPF通讯// WPFNamedPipeServerStream pipeServer = new NamedPipeServerStream(    "testpipe",     PipeDirection.InOut,    1);pipeServer.WaitForConnection();string str = "hello from server!";byte[] outBuffer = Encoding.Unicode.GetBytes(str);int len = outBuffer.Length;pipeServer.WriteByte((byte)(len / 256));pipeServer.WriteByte((byte)(len % 256));pipeServer.Write(outBuffer, 0, len);pipeServer.Flush();len = pipeServer.ReadByte() * 256;len += pipeServer.ReadByte();byte[] inBuffer = new byte[len];pipeServer.Read(inBuffer, 0, len);string remoteInfo = Encoding.Unicode.GetString(inBuffer);lbRemoteInfo.Content = remoteInfo;// Unity pipeClient = new NamedPipeClientStream(    ".", "testpipe",     PipeDirection.InOut);pipeClient.Connect(10000);int len = pipeClient.ReadByte() * 256;len += pipeClient.ReadByte();byte[] inBuffer = new byte[len];pipeClient.Read(inBuffer, 0, len);remoteInfo = Encoding.Unicode.GetString(inBuffer);pipeClient.Flush();string str = "hello from client!";byte[] outBuffer = Encoding.Unicode.GetBytes(str);len = outBuffer.Length;pipeClient.WriteByte((byte)(len / 256));pipeClient.WriteByte((byte)(len % 256));pipeClient.Write(outBuffer, 0, len);pipeClient.Flush();效果
做了一个简单的测试,看上去效果不错:
  • Unity(Client)被嵌入WPF(Server)窗口
  • WPF向Unity发送一条”hello from server!”,在Unity控件的左上角显示
  • Unity向WPF发送一条”hello from client!”,显示在一个WPF的Label上
说明和参考
Mono不支持管道安全级别
不用就可以了,NamedPipeServerStream构造函数里,不要填TokenImpersonationLevel
StackOverflow
Unity无法启动NamedPipelineServer
StackOverflow
在Unity中启用System.IO.Pipes命名空间
在Player Settings中,将.net版本设置为.net2.0,默认是.net2.0 subset
StackOverflow

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2016-6-20 17:57 | 显示全部楼层
这是什么,我看看。
发表于 2017-4-27 21:50 | 显示全部楼层
很不错
发表于 2017-4-27 21:30 | 显示全部楼层
顶顶多好
发表于 2017-4-27 21:56 | 显示全部楼层
真心顶
发表于 2017-4-27 22:13 | 显示全部楼层
说的非常好
发表于 2017-4-27 21:54 | 显示全部楼层
不错不错
发表于 2017-5-22 08:20 | 显示全部楼层
好帖就是要顶
发表于 2017-5-22 07:40 | 显示全部楼层
难得一见的好帖
发表于 2017-5-22 07:28 | 显示全部楼层
说的非常好
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-21 20:27 , Processed in 0.233636 second(s), 33 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表