我正在尝试为Unity3D中的Microsoft HoloLens构建应用程序。该应用程序将以JSON形式从python应用程序接收数据。 python发送的JSON如下:
{
"PC_Station": [{
"PLC_1": {
"DB1": {
"test123": 0
},
"STOP": false,
"START": false,
"Start_1": false,
"Stop_1": false,
"Led1": false,
"Led2": false,
"Led3": false,
"Counter": 0,
"Sliderval": 0
}
}]
}
应用程序的源代码在这里:
using UnityEngine;
using System;
using System.IO;
using System.Text;
using System.Linq;
using HoloToolkit.Unity;
using System.Collections.Generic;
using UnityEngine.UI;
using Newtonsoft.Json;
using System.Collections;
using Newtonsoft.Json.Linq;
using System.Text.RegularExpressions;
#if !UNITY_EDITOR
using Windows.Networking.Sockets;
using Windows.Networking.Connectivity;
using Windows.Networking;
#endif
public class UDPCommunication : Singleton<UDPCommunication>
{
// Connection variables
private string port = "8000";
private string externalIP = "172.16.24.251";
private string externalPort = "8001";
public static int size = 0;
public static List<Dictionary<string, string>> abc = new List<Dictionary<string, string>>();
public static List<string> varz;
public GameObject canvas;
public GameObject Panel;
public GameObject image;
public GameObject imagetext;
public GameObject numbertext;
public Image testimg;
private GameObject getImageTags;
private GameObject getNumberTags;
private GameObject[] canvases;
private GameObject[] panels;
private GameObject[] tiles;
private GameObject[] texts;
private float scaler = 0.0125f;
// UI/Text elements
const string TurnOn = "on";
private uint sliderVal;
// Sets up a Queue
private string receivedmsg;
public readonly static Queue<Action> ExecuteOnMainThread = new Queue<Action>();
private void Awake()
{
}
IEnumerator updateTags()
{
while (true)
{
Debug.Log("List count" + abc.Count);
for (int i = 0; i < abc.Count; i++)
{
foreach (KeyValuePair<string, string> item in abc[i])
{
testimg = GameObject.Find(item.Key).GetComponent<Image>();
if(item.Value == "True")
{
testimg.color = Color.green;
}
if(item.Value == "False")
{
testimg.color = Color.red;
}
}
}
yield return new WaitForSeconds(0.25f);
}
}
#if !UNITY_EDITOR
// Socket initialization
DatagramSocket socket;
#endif
#if !UNITY_EDITOR
IEnumerator initGUI()
{
while(true){
if(receivedmsg == null){
Debug.Log("None");
}
else{
Debug.Log(receivedmsg);
break;
}
}
yield return new WaitForSeconds(1.0f);
yield return StartCoroutine(createUserInterface(receivedmsg));
//yield return StartCoroutine(updateTags());
Debug.Log("left initgui");
}
// use this for initialization
async void Start()
{
/*StartCoroutine(SendSliderValue());
Button btn_on = led1_button_on.GetComponent<Button>();
Button btn_off = led1_button_off.GetComponent<Button>();
Button btn1_on = led3_button_on.GetComponent<Button>();
Button btn1_off = led3_button_off.GetComponent<Button>();
btn_on.onClick.AddListener(delegate {TaskWithParameters("Led1 on"); });
btn_off.onClick.AddListener(delegate {TaskWithParameters("Led1 off"); });
btn1_on.onClick.AddListener(delegate {TaskWithParameters("Led3 on"); });
btn1_off.onClick.AddListener(delegate {TaskWithParameters("Led3 off"); });*/
//string json = "{\"PC_Station\": [{\"PLC_0\": {\"DB1\": {\"test123\": 0}, \"STOP\": false,\"Frap\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}},{\"PLC_1\": {\"DB1\": {\"test123\": 55}, \"STOP\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}}]}";
Debug.Log("Waiting for a connection...");
socket = new DatagramSocket();
socket.MessageReceived += Socket_MessageReceived;
//createUserInterface(receivedmsg);
HostName IP = null;
try
{
var icp = NetworkInformation.GetInternetConnectionProfile();
IP = Windows.Networking.Connectivity.NetworkInformation.GetHostNames()
.SingleOrDefault(
hn =>
hn.IPInformation?.NetworkAdapter != null && hn.IPInformation.NetworkAdapter.NetworkAdapterId
== icp.NetworkAdapter.NetworkAdapterId);
await socket.BindEndpointAsync(IP, port);
}
catch (Exception e)
{
Debug.Log(e.ToString());
Debug.Log(SocketError.GetStatus(e.HResult).ToString());
return;
}
SendMessage("test");
StartCoroutine(updateTags());
StartCoroutine(initGUI());
}
void TaskWithParameters(string message)
{
Debug.Log("sending Message");
SendMessage(message);
}
private async System.Threading.Tasks.Task SendMessage(string message)
{
using (var stream = await socket.GetOutputStreamAsync(new Windows.Networking.HostName(externalIP), externalPort))
{
using (var writer = new Windows.Storage.Streams.DataWriter(stream))
{
var data = Encoding.UTF8.GetBytes(message);
writer.WriteBytes(data);
await writer.StoreAsync();
Debug.Log("Sent: " + message);
}
}
}
#else
// Use this for initialization.
void Start()
{
}
#endif
// Update is called once per frame.
void Update()
{
// Dequeues items until there are no more items on the queue.
while (ExecuteOnMainThread.Count > 0)
{
ExecuteOnMainThread.Dequeue().Invoke();
}
}
IEnumerator SendSliderValue()
{
Debug.Log("entered slider class");
GameObject theplayer = GameObject.Find("Hololens-Slider");
TubeSliderManager test = theplayer.GetComponent<TubeSliderManager>();
while (true)
{
sliderVal = test.CurrentValue;
string s = "Slidervalue" + sliderVal.ToString();
SendMessage(s);
yield return new WaitForSeconds(0.5f);
}
}
#if !UNITY_EDITOR
//this method gets called when a message is received
private async void Socket_MessageReceived(Windows.Networking.Sockets.DatagramSocket sender, Windows.Networking.Sockets.DatagramSocketMessageReceivedEventArgs args)
{
// Read the received message.
Stream streamIn = args.GetDataStream().AsStreamForRead();
StreamReader reader = new StreamReader(streamIn);
receivedmsg = await reader.ReadLineAsync();
//Debug.Log("MESSAGE: " + message);
// if the count is zero, the message will be relayed to the setStuff method, which processes the string continuously.
// The message contains a JSON string which is received from the server.
if (ExecuteOnMainThread.Count == 0)
{
ExecuteOnMainThread.Enqueue(() =>
{
//Debug.Log(receivedmsg);
//pass msg to function here
});
}
}
#endif
IEnumerator createUserInterface(string jsonstring)
{
Debug.Log("entered create UI");
var root = JToken.Parse(jsonstring);
StartCoroutine(IterateJtoken(root));
canvases = new GameObject[abc.Count];
panels = new GameObject[abc.Count];
for (int i = 0; i < abc.Count; i++)
{
canvases[i] = Instantiate(canvas, transform.position, transform.rotation);
canvases[i].name = "Canvas" + i;
canvases[i].transform.position += new Vector3(i * 14, 0, 30);
panels[i] = Instantiate(Panel, transform.position, transform.rotation);
panels[i].name = "Panel";
panels[i].transform.SetParent(canvases[i].transform, false);
for (int z = 0; z < abc[i].Count; z++)
{
tiles = new GameObject[abc[i].Count];
texts = new GameObject[abc[i].Count];
tiles[z] = Instantiate(image, transform.position, transform.rotation);
tiles[z].name = abc[i].ElementAt(z).Key;
tiles[z].transform.SetParent(panels[i].transform, false);
texts[z] = Instantiate(imagetext, transform.position, transform.rotation);
texts[z].name = abc[i].ElementAt(z).Key + "text";
texts[z].transform.SetParent(tiles[z].transform, false);
texts[z].GetComponent<Text>().text = abc[i].ElementAt(z).Key;
texts[z].transform.position += new Vector3(44 * scaler, -4 * scaler, 0);
if (Regex.IsMatch(abc[i].ElementAt(z).Value, @"^\d+$"))
{
numbertext = Instantiate(imagetext, transform.position, transform.rotation);
numbertext.name = abc[i].ElementAt(z).Key + "value";
numbertext.transform.SetParent(tiles[z].transform, false);
texts[z].transform.position += new Vector3(0, 19.5f * scaler, 0);
numbertext.transform.position += new Vector3(77 * scaler, -18.5f * scaler, 0);
}
}
}
yield return null;
}
IEnumerator IterateJtoken(JToken jtoken)
{
abc.Clear();
foreach (var value in jtoken)
{
foreach (JArray test in value)
{
for (int i = 0; i < test.Count; i++)
{
foreach (var item in test[i])
{
var itemproperties = item.Parent;
foreach (JToken token in itemproperties)
{
if (token is JProperty)
{
var prop = token as JProperty;
//Console.WriteLine(prop.Name); //PLC name
var plc = (JObject)prop.Value;
Dictionary<string, string> variables = new Dictionary<string, string>();
foreach (KeyValuePair<string, JToken> val in plc)
{
if (val.Value is JObject)
{
JObject nestedobj = (JObject)val.Value;
foreach (JProperty nestedvariables in nestedobj.Properties())
{
size++;
var nestedVariableName = nestedvariables.Name;
var nestedVariableValue = nestedvariables.Value;
variables.Add(nestedVariableName, nestedVariableValue.ToString());
//Console.WriteLine(nestedVariableName+" "+nestedVariableValue);
}
}
else
{
size++;
var variableName = val.Key;
var variableValue = val.Value;
variables.Add(variableName, variableValue.ToString());
//Console.WriteLine(variableName+" "+variableValue);
}
}
abc.Add(new Dictionary<string, string>(variables));
}
}
}
}
}
}
yield return new WaitForSeconds(0.5f);
}
}
使用函数Socket_MessageReceived接收消息。如您所见,我正在使用UDP套接字进行接收和发送(SendMessage函数)。 在异步void Start()函数中,我启动了一个协程,该协程使用名为initGUI()的函数来设置所有运动对象。 Socket_MessageReceived函数接收我上面提到的JSON字符串。接收到的消息将不断保存并更新为名为接收到的私人字符串。
当我初始化函数initGUI()时,该函数将等待直到字符串不为空,在收到消息后,另一个协程将启动。这个协程为HoloLens构建了用户界面,该函数称为createUserInterface。
在此函数中,接收到的字符串将转换为JToken,然后将启动另一个名为IterateJtoken的函数,该函数会将内容添加到词典列表中。填写词典列表后,createUserInterface函数将正确构建接口。
虽然我能够正确地构建用户界面,但是我希望能够在JSON字符串中的值更改时更新用户界面。例如,在我的JSON字符串中,我有一个名为“ Start”的变量,其值为false。在用户界面中,我有一个根据变量值更改的Unity UI /图像。所以true表示图片为绿色,false表示图片为红色。
我该如何使其动态更新?
每次尝试调用Iterate JToken时,我都尝试清空字典列表,但这不起作用。
答案 0 :(得分:1)
在问到您的问题
之前,我已经发现了一些问题:您的协程等待消息损坏:
IEnumerator initGUI()
{
while(true){
if(receivedmsg == null){
Debug.Log("None");
}
else{
Debug.Log(receivedmsg);
break;
}
}
如果receivedmsg
为空/空并且也没有yield指令,则此循环永远不会终止。您要等第二个 之后,循环才会终止,这没有任何意义。请改用WaitUntil(() => receivedmsg != null)
。
您可能还想添加isEmpty()
支票。
createUserInterface
不必是协程。您内部只有一个yield指令,之后没有任何代码。
IterateJtoken
同样适用,只是这次收益是持续一段时间而不是null(为什么?)。我怀疑这可能打算放在一个或多个for循环中。
现在,您的问题。您希望能够更新GUI,而不仅仅是构建它。我的建议是使用字典在字符串(JSON键)和在initGui
中创建的Unity GameObject之间映射。然后,当您对新的数据包数据进行更新时,可以查询字典而不是创建对象。