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