最近在做一個任務的時候遇到這樣一個問題,我用c#腳本寫了一個socket服務端程式,是新開了一個執行緒寫的,已經能夠接受并且處理客戶端的資料并顯示在控制臺中。處理后的資訊為一組歐拉角或者一組四元數,但是我想把這組實時變換的資料賦值給場景中的一個Cube時,出錯,

報錯資訊顯示get_transform只能在主執行緒中呼叫,請問應怎樣辦,從網上查到是使用Loom類進行互動,可是這個類是寫在腳本里還是另起一個腳本或者。。。。新人求教,有償求助using UnityEngine;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System;
/// <summary>
/// scoket服務器監聽埠腳本
/// </summary>
public class SocketServer : MonoBehaviour
{
public class Oulajiao
{
public float oula1;
public float oula2;
public float oula3;
public void zhuanhuan(double xx,double yy,double zz)
{
oula1 = (float)xx;
oula2 = (float)yy;
oula2 = (float)zz;
}
}
public GameObject Cube;
public Thread thStartServer;//定義啟動socket的執行緒
//public string o;
void Start()
{
Debug.Log("111");
thStartServer = new Thread(StartServer);
thStartServer.Start();//啟動該執行緒
}
void Update()
{
}
public void StartServer()
{
const int bufferSize = 8792;//快取大小,8192位元組
IPAddress ip = IPAddress.Parse("192.168.1.101");
TcpListener tlistener = new TcpListener(ip, 8080);
tlistener.Start();
Debug.Log("Socket服務器監聽啟動......");
TcpClient remoteClient = tlistener.AcceptTcpClient();//接收已連接的客戶端,阻塞方法
Debug.Log("客戶端已連接!local:" + remoteClient.Client.LocalEndPoint + "<---Client:" + remoteClient.Client.RemoteEndPoint);
NetworkStream streamToClient = remoteClient.GetStream();//獲得來自客戶端的流
do
{
try //直接關掉客戶端,服務器端會拋出例外
{
//接收客戶端發送的資料部分
byte[] buffer = new byte[bufferSize];//定義一個快取buffer陣列
int byteRead = streamToClient.Read(buffer, 0, bufferSize);//將資料搞入快取中(有朋友說read()是阻塞方法,測驗中未發現程式阻塞)
if (byteRead == 0)//連接斷開,或者在TCPClient上呼叫了Close()方法,或者在流上呼叫了Dispose()方法。
{
Debug.Log("客戶端連接斷開......");
break;
}
string msg = Encoding.UTF8 .GetString(buffer, 0, byteRead);//從二進制轉換為字串對應的客戶端會有從字串轉換為二進制的方法
if (msg[0] == 0 || msg.Equals(null) || msg.Equals(";") || msg.Length < 50)
{
return;
}
else
{
string[] s = msg.Split(';'); //將受到的資料化為字串陣列
int stringlength = s.Length;
for (int i = 0; i < stringlength; i++)//
{
if (s[i].Length > 54) //獲取完整的四元素
{
if (s[i][0].Equals('N') && s[i][1].Equals('0'))
{
// if (t[i][0].Equals('N') && t[i][1].Equals('0'))
// {
// string t = o as string;
string[] seven = s[i].Split(' ');
double x = double.Parse(seven[1]);
double y = double.Parse(seven[2]);
double z = double.Parse(seven[3]);
double w = double.Parse(seven[4]);
double a = double.Parse(seven[5]);
double b = double.Parse(seven[6]);
double c = double.Parse(seven[7]);
double Roll = Math.Atan2(2 * (x * y + y * w), (1 - 2 * y * y + z * z));//橫滾角
double Pitch = Math.Asin(2 * (x * z - y * w));//俯仰角
double Yaw = Math.Atan2(2 * (x * z + y * w), (1 - 2 * z * z + w * w));//偏行角
// Debug.Log("接收資料:" + str + ".資料長度:[" + byteRead + "byte]");
Oulajiao oulajiao = new Oulajiao();
oulajiao.zhuanhuan(Roll * 180 / Math.PI, Pitch * 180 / Math.PI, Yaw * 180 / Math.PI);
//oula11 = Roll * 180 / Math.PI;
// oulajiao.oula2 = Pitch * 180 / Math.PI;
//oulajiao. oula3 = Yaw * 180 / Math.PI;
// Debug.Log("歐拉角為:" + " " + oulajiao.oula1 + " " + oulajiao.oula2 + " " + oulajiao.oula3);
Cube.transform.Rotate(new Vector3(oulajiao.oula1, oulajiao.oula2, oulajiao.oula3), Space.Self);
Debug.Log("四元數為;"+ x+" " +y+" "+z+" "+ w);
// Debug.Log("歐拉角為:" + Roll * 180 / Math.PI + Pitch * 180 / Math.PI + Yaw * 180 / Math.PI);
//Thread t = new Thread(Speedline);
//t.IsBackground = true;
//t.Start();
// }
}
else
{
continue;
}
}
}
}
// Debug.Log("接收資料:" + str + ".資料長度:[" + byteRead + "byte]");
}
catch (Exception ex)
{
Debug.Log("客戶端例外:" + ex.Message);
break;
}
}
while (true);
}
void OnApplicationQuit()
{
thStartServer.Abort();//在程式結束時殺掉執行緒,完事一定要記得自己擦,系統不會給你擦,經測驗不擦第二次啟動unity會無回應
}
}
uj5u.com熱心網友回復:
錯報告述你了,只能在主執行緒中操作。。。。。。這個就是服務器發送資料給客戶段,在開發中常用的是新鍵一個Queue,用來存放服務器發送來的資料,新建一個腳本監聽Queue,如果有資料在lateUpdate中處理。這個原因就是unity不支持在分執行緒中操作unity的資料(位置,旋轉、縮放),只要是unity都不支持2018版以前的。2018聽說支持多執行緒,但是我自己沒用過uj5u.com熱心網友回復:
是用Loom類解決就行。。 你創建一個gameobject 把loom類掛到該gameobject上 并設定該gameobject為DontDestroyOnLoad(gameObject);即可。。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/35675.html
標籤:Unity3D
