WinForm内嵌Unity3D

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

 

一、为了能够动态设置axUnityWebPlayer的Src,我使用用户控件来封装。看下面的代码。
[csharp] view plain copy
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;  
        #endregion  
  
        public 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;      
            }              
        }  
        #endregion  
  
        void _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);  
        }  
        #endregion  
  
        private 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控件需要在工具箱中添加,如下图。

二、窗体界面的代码
[csharp] view plain copy
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#脚本
[csharp] view plain copy
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 initialization  
    void Start()  
    {  
  
    }  
  
    // Update is called once per frame  
    void 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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值