Unity3d 不支持C#的线程直接调用Unity3D 主线程才能实现的功能。例如:给UGUI text 赋值、改变Color值等。怎样解决这个问题呢?使用一个Loom脚本。
按照惯例贴上代码。
首先Loom脚本
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Linq;
public class Loom : MonoBehaviour
{
public static int maxThreads = 8;
static int numThreads;
private static Loom _current;
private int _count;
public static Loom Current
{
get
{
Initialize();
return _current;
}
}
void Awake()
{
_current = this;
initialized = true;
}
static bool initialized;
static void Initialize()
{
if (!initialized)
{
if (!Application.isPlaying)
return;
initialized = true;
var g = new GameObject("Loom");
_current = g.AddComponent<Loom>();
}
}
private List<System.Action> _actions = new List<System.Action>();
public struct DelayedQueueItem
{
public float time;
public System.Action action;
}
private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();
List<DelayedQueueItem> _currentDelayed = new List<DelayedQueueItem>();
public static void QueueOnMainThread(System.Action action)
{
QueueOnMainThread(action, 0f);
}
public static void QueueOnMainThread(System.Action action, float time)
{
if (time != 0)
{
lock (Current._delayed)
{
Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = action });
}
}
else
{
lock (Current._actions)
{
Current._actions.Add(action);
}
}
}
public static Thread RunAsync(System.Action a)
{
Initialize();
while (numThreads >= maxThreads)
{
Thread.Sleep(1);
}
Interlocked.Increment(ref numThreads);
ThreadPool.QueueUserWorkItem(RunAction, a);
return null;
}
private static void RunAction(object action)
{
try
{
((System.Action)action)();
}
catch
{
}
finally
{
Interlocked.Decrement(ref numThreads);
}
}
void OnDisable()
{
if (_current == this)
{
_current = null;
}
}
// Use this for initialization
void Start()
{
}
List<System.Action> _currentActions = new List<System.Action>();
// Update is called once per frame
void Update()
{
lock (_actions)
{
_currentActions.Clear();
_currentActions.AddRange(_actions);
_actions.Clear();
}
foreach (var a in _currentActions)
{
a();
}
lock (_delayed)
{
_currentDelayed.Clear();
_currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time));
foreach (var item in _currentDelayed)
_delayed.Remove(item);
}
foreach (var delayed in _currentDelayed)
{
delayed.action();
}
}
}
/*
* 调用案例
*/
//public class LoomUse
//{
// void ScaleMesh(Mesh mesh, float scale)
// {
//
// var vertices = mesh.vertices;
// //Run the action on a new thread
// Loom.RunAsync(() =>
// {
// //Loop through the vertices
// for (var i = 0; i < vertices.Length; i++)
// {
// //Scale the vertex
// vertices[i] = vertices[i] * scale;
// }
// //Run some code on the main thread
// //to update the mesh
// Loom.QueueOnMainThread(() =>
// {
// //Set the vertices
// mesh.vertices = vertices;
// //Recalculate the bounds
// mesh.RecalculateBounds();
// });
// });
// }
//}
其次: Socket脚本
using System;
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace ReceiveMessage
{
class ReceiveMessage : MonoBehaviour
{
public delegate void ReceiveMes(string str);
public static event ReceiveMes receiveMes;
//在内存中开辟一块1024缓存区域
private static byte[] result = new byte[1024];
//自定义一个端口
private static int myProt = 8009;
//定义服务器 Socket 对象
private static Socket serverSocket;
private static int SencenNum = 0;
public Button mListenButton;
public Text mMainMessagetext;
private Thread MainThread;
public GameObject[] obj;
public string getInfo;
public object Wait { get; private set; }
void Start()
{
mListenButton.onClick.AddListener(ListenFunction);
}
//private void Update()
//{
// mMainMessagetext.text = getInfo;
//}
void ListenFunction()
{
DontDestroyOnLoad(this.gameObject);
IPAddress ip = IPAddress.Parse("192.168.2.176");
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(ip, myProt));
serverSocket.Listen(10);
Console.WriteLine("启动监听{0}成功", serverSocket.LocalEndPoint.ToString());
MainThread = new Thread(ListenClientConnect);
MainThread.Start();
}
private void ListenClientConnect()
{
while (true)
{
Socket clientSocket = serverSocket.Accept();
clientSocket.Send(Encoding.ASCII.GetBytes("Server Say Hello"));
Thread receiveThread = new Thread(ReceiveMessage1);
receiveThread.Start(clientSocket);
}
}
private void ReceiveMessage1(object clientSocket)
{
Socket myClientSocket = (Socket)clientSocket;
Boolean b = true;
while (b)
{
try
{
int receiveNumber = myClientSocket.Receive(result);
string str = Encoding.UTF8.GetString(result, 0, receiveNumber);
if (str.Equals(""))
{
b = false;
}
else
{
Loom.RunAsync(() =>
{
//处理普通数据 例如:1+1,
Loom.QueueOnMainThread(() =>
{
receiveMes(str);// 调到 unity3d 主线程上
});
});
}
}
catch (Exception ex)
{
Debug.Log(ex.Message);
myClientSocket.Shutdown(SocketShutdown.Both);
myClientSocket.Close();
break;
}
}
}
}
}
最后,UGUI 页面
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
namespace ReceiveMessage
{
public class Test : MonoBehaviour
{
public Text mText;
private void OnEnable()
{
ReceiveMessage.receiveMes += ReceiveMes;
}
private void Start()
{
if (mText == null)
{
mText = GetComponent<Text>();
}
}
private void OnDisable()
{
ReceiveMessage.receiveMes -= ReceiveMes;
}
private void OnDestroy()
{
ReceiveMessage.receiveMes -= ReceiveMes;
}
public void ReceiveMes(string str)
{
if (mText)
{
mText.text = str;
}
}
}
}
总结,Loom是一个单例脚本,必须挂在场景中一个空物体上,不然,Loom不起作用
原文地址:https://www.cnblogs.com/WinnerYu/p/12074477.html