根據項目的需要,對已經完成的Unity三維模型以及游戲要使用Winform進行包裝,也就是使用Winform做一層外殼。因此在展示Unity的時候使用到了UnityWebPlayer這個插件,對於此插件就不多說了,無論是想把Unity嵌在網頁中還是winform中都要使用到。
網上很多資料是在Web中使用Unity的,很自然的把Unity發布成Web類型,在此如何在Web中使用Unity也就不多說了,重點是解決在winform中使用Unity出現的插件自帶的右鍵問題以及Logo問題。
一、winform中使用Unity
在winform中使用Unity,同樣是像網頁形式把做好的Unity發布成Web類型,然后直接使用文件格式為.unity3d的文件。把Unity文件的路徑賦值給UnityWebplayer的src屬性即可,對於動態賦值,從網上找到如下方法:
/// <summary> /// 實例化UnitywebPlayer控件並添加到界面上 /// </summary> /// <param name="panel">承載unity的控件</param> /// <param name="unityfileServerpath">服務端路徑</param> public void BindUnity(Panel panel,string unityfileServerpath) { if (panel.Controls.Count > 0) { panel.Controls[0].Dispose(); } panel.Controls.Clear(); ///指定空的Unity3D,用來做外殼 string unityfilepath = Application.StartupPath + unityfileServerpath;//"/U3D/LoadAsset.unity3d"; unityex = new UnityWebPlayerEx(); ((System.ComponentModel.ISupportInitialize)(unityex)).BeginInit(); this.Controls.Add(unityex); ((System.ComponentModel.ISupportInitialize)(unityex)).EndInit(); unityex.src = unityfilepath; AxHost.State state = unityex.OcxState; unityex.Dispose(); unityex = new UnityWebPlayerEx(); ((System.ComponentModel.ISupportInitialize)(unityex)).BeginInit(); this.SuspendLayout(); unityex.Dock = DockStyle.Fill; unityex.Name = "Unityex"; unityex.OcxState = state; unityex.TabIndex = 0; unityex.DisableContextMenu = true; unityex.OnExternalCall += new AxUnityWebPlayerAXLib._DUnityWebPlayerAXEvents_OnExternalCallEventHandler(unityex_OnExternalCall); panel.Controls.Add(unityex); ((System.ComponentModel.ISupportInitialize)(unityex)).EndInit(); this.ResumeLayout(false); }
二、屏蔽UnityWebPlayer控件的右鍵問題
實現的代碼如下:

class UnityWebPlayerEx : AxUnityWebPlayerAXLib.AxUnityWebPlayer { #region MyRegion //private const int WM_RBUTTONDOWN = 0x204; //private const int WM_RBUTTONUP = 0x205; //private const int WM_RBUTTONBLCLK = 0x206; //public override bool PreProcessMessage(ref Message msg) //{ // switch (msg.Msg) // { // case 0x204://鼠標右鍵按下消息 // this.SendMessage("ThiredViewCamera", "RightMouseButtonDown", null); // this.SendMessage("FirstViewCamera", "RightMouseButtonDown", null); // this.SendMessage("Main Camera", "RightMouseButtonDown", null); // this.Focus(); // return true; // case 0x205://鼠標右鍵抬起消息 // this.SendMessage("ThiredViewCamera", "RightMouseButtonUp", null); // this.SendMessage("FirstViewCamera", "RightMouseButtonUp", null); // this.SendMessage("Main Camera", "RightMouseButtonUp", null); // return true; // case 0x206://鼠標右鍵點擊消息 // return true; // } // return base.PreProcessMessage(ref msg); //} #endregion public UnityWebPlayerEx() { } [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern int MoveWindow(IntPtr hwnd, int x, int y, int nWidth, int nHeight, bool bRepaint); [DllImport("user32")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); private const int WM_PARENTNOTIFY = 0x210; protected override void WndProc(ref Message m) { _menuHided = false; switch (m.Msg) { case WM_PARENTNOTIFY: HideContextMenu(m); break; } base.WndProc(ref m); } /// <summary> /// 是否隱藏右鍵菜單,默認還是要顯示的,new出來后要設置一下 /// </summary> public bool DisableContextMenu{ get; set; } private bool _menuHided { get; set; } private void HideContextMenu(Message m) { if (_menuHided) return; if (DisableContextMenu == false) return; if (m.ToString().Contains("WM_RBUTTONDOWN")) { if (_menuHided == false) { new Thread(() => { while (_menuHided == false) { HideContextMenu(); } }).Start(); } } } private void HideContextMenu() { //Unity.ContextSubmenu 為右鍵快鍵菜單的Form IntPtr handle = FindWindow("Unity.ContextSubmenu", null); if (handle != IntPtr.Zero) { //把快捷菜單Form移到左上角並設置其大小為0 MoveWindow(handle, 0, 0, 10, 10, true); MoveWindow(handle, 0, 0, 0, 0, true); _menuHided = true; } } }
需要注意的是在關閉使用的窗體的時候需要釋放Unitywebplayer所占用的資源,否則在第二次進來的點擊的第一次右鍵還是會彈出快捷菜單。
三、遮住unitywebplayer的Logo
在網上找了很多資料,基本都是網頁形式通過修改param參數來更換Logo的,但是winform中直接使用Unity文件,也就沒有使用到其一起發布的js文件,所以此方式的可能性不大。一開始也還是抱着可行的態度嘗試了使用C#調用js的方式,然並沒有解決。在網上是在找不到方法的時候想到了一種“投機取巧”的方法:先遮住UnityWebPlayer,等加載完成后在顯示出來。於是在初始化UnityWebPlayer的時候先在其上邊添加一個遮擋物,遮擋物可以自定義,比如使用Panel或者自定義一個用戶控件,把界面做得好看些。
//實例化遮擋物 shadeuc = new ShadeUC(); shadeuc.Name = "shadeuc1"; shadeuc.Dock = DockStyle.Fill; //把遮罩層添加到界面 this.splitContainerEx1.Panel1.Controls.Add(shadeuc); //遮罩層置頂以遮住底層 shadeuc.BringToFront();
接下來的一個問題是何時移除遮擋物,根據自己的項目我是在UnityWebPlayer的OnExternalCall事件中接收到Unity返回的消息時移除的,這種方式得到的效果還可以。還有一種不是太靠譜的方式是使用計時器,自定義一個時長移除遮擋物。
this.splitContainerEx1.Panel1.Controls.Remove(shadeuc);