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.pswp.cn/news/41017.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/41017.shtml
英文地址,請注明出處:http://en.pswp.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這個目錄下所有文件…

性能測試場景設計

性能測試場景設計&#xff0c;是性能測試中的重要概念&#xff0c;性能測試場景設計&#xff0c;目的是要描述如何執行性能測試。 通常來講&#xff0c;性能測試場景設計主要會涉及以下部分&#xff1a; 并發用戶數是多少&#xff1f; 測試剛開始時&#xff0c;以什么樣的速率…

Spring WebFlux 的詳細介紹

Spring WebFlux 是基于響應式編程的框架&#xff0c;用于構建異步、非阻塞的 Web 應用程序。它是Spring框架的一部分&#xff0c;專注于支持響應式編程范式&#xff0c;使應用程序能夠高效地處理大量的并發請求和事件。 以下是關于 Spring WebFlux 的詳細介紹&#xff1a; 1. *…

go入門實踐五-實現一個https服務

文章目錄 前言生成證書申請免費的證書使用Go語言生成自簽CA證書 https的客戶端和服務端服務端代碼客戶端代碼 tls的客戶端和服務端服務端客戶端 前言 在公網中&#xff0c;我想加密傳輸的數據。(1)很自然&#xff0c;我想到了把數據放到http的請求中&#xff0c;然后通過tls確…

2023年京東寵物食品行業數據分析(京東大數據)

寵物食品市場需求主要來自于養寵規模&#xff0c;近年來由于我國寵物數量及養寵人群的規模均在不斷擴大&#xff0c;寵物相關產業和市場規模也在蓬勃發展&#xff0c;寵物食品市場也同樣保持正向增長。 根據鯨參謀電商數據分析平臺的相關數據顯示&#xff0c;2023年1月-7月&am…

vue5種模糊查詢方式

在Vue中&#xff0c;有多種方式可以實現模糊查詢。以下是五種常見的模糊查詢方式&#xff1a; 使用JavaScript的filter()方法&#xff1a;使用filter()方法可以對數組進行篩選&#xff0c;根據指定的條件進行模糊查詢。例如&#xff1a; data() {return {items: [{ name: App…

接口自動化測試(添加課程接口調試,調試合同上傳接口,合同列表查詢接口,批量執行)

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;我訪問你使用的瀏覽器版本信息 可…

藍橋杯每日N題 (消滅老鼠)

大家好 我是寸鐵 希望這篇題解對你有用&#xff0c;麻煩動動手指點個贊或關注&#xff0c;感謝您的關注 不清楚藍橋杯考什么的點點下方&#x1f447; 考點秘籍 想背純享模版的伙伴們點點下方&#x1f447; 藍橋杯省一你一定不能錯過的模板大全(第一期) 藍橋杯省一你一定不…

【日常積累】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…