我是Unity的新手,我目前正在将其用作为我的试点研究设计简单模拟环境的工具 . 这是一个简化的解释:
主角(代理)扫描环境并通过TCP套接字将状态(作为JSON对象)发送到python服务器 .
在python服务器端,根据状态执行大的计算 . 结果是通过TCP发送回Unity的操作 .
角色需要在Unity中执行此操作,然后再次扫描环境 . 新状态再次发送到python服务器....
这个过程正在重复“直到无限(除非客户端或服务器停止),最终导致代理根据其学习自行开发行为 .
我完成了团结环境的创建,并在python中编写了学习算法 . 而且,我设法在两者之间 Build TCP连接 . 但是,我偶然发现了Unity中主要的Update()循环问题 .
也就是说,如果我简化Unity发送ping(作为状态)和python发送pong(作为动作)的过程,我需要重复以下过程 .
-
冻结帧
-
ping
-
计算
-
pong
-
下一帧
所以在Unity Start()
方法中我设置套接字并发送初始ping . 我想在主 Update()
循环中让Unity在更新帧之前等待python的乒乓答案 . 我创建了一个包含玩具示例的脚本,并尝试通过在将pong发送到Unity之前添加2秒的延迟来模拟python中的计算时间 .
以下是Unity脚本的代码(只需将其附加到主摄像头):
using UnityEngine;
using System;
using System.IO;
using System.Net.Sockets;
public class networkSocketPingPong : MonoBehaviour
{
public String host = "localhost";
public Int32 port = 50000;
internal Boolean socket_ready = false;
internal String input_buffer = "";
TcpClient tcp_socket;
NetworkStream net_stream;
StreamWriter socket_writer;
StreamReader socket_reader;
private void Start()
{
setupSocket();
writeSocket("ping");
}
void Update()
{
string received_data = readSocket();
switch (received_data)
{
case "pong":
Debug.Log("Python controller sent: " + (string)received_data);
writeSocket("ping");
break;
default:
Debug.Log("Nothing received from Python");
break;
}
}
void OnApplicationQuit()
{
closeSocket();
}
// Helper methods for:
//...setting up the communication
public void setupSocket()
{
try
{
tcp_socket = new TcpClient(host, port);
net_stream = tcp_socket.GetStream();
socket_writer = new StreamWriter(net_stream);
socket_reader = new StreamReader(net_stream);
socket_ready = true;
}
catch (Exception e)
{
// Something went wrong
Debug.Log("Socket error: " + e);
}
}
//... writing to a socket...
public void writeSocket(string line)
{
if (!socket_ready)
return;
socket_writer.Write(line);
socket_writer.Flush();
}
//... reading from a socket...
public String readSocket()
{
if (!socket_ready)
{
Debug.Log("Socket is not ready");
return "";
}
if (net_stream.DataAvailable)
return socket_reader.ReadLine();
return "";
}
//... closing a socket...
public void closeSocket()
{
if (!socket_ready)
return;
socket_writer.Close();
socket_reader.Close();
tcp_socket.Close();
socket_ready = false;
}
}
...这里是python服务器代码:
import socket
import time
host = 'localhost'
port = 50000
backlog = 5
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))
s.listen(backlog)
while 1:
client, address = s.accept()
print "Client connected."
while 1:
data = client.recv(size)
if data == "ping":
time.sleep(2)
print ("Unity Sent: " + str(data))
client.send("pong\n")
else:
client.send("Bye!")
print ("Unity Sent Something Else: " + str(data))
client.close()
break
我首先运行python服务器然后运行模拟(通过Unity编辑器) . 这导致以下控制台屏幕截图:
这证明主Update()循环正在运行,而我希望它只在从服务器收到“pong”时才暂停和更新 . 任何想法如何实现这一目标?
我在论坛上搜索了答案,但总是偶然发现了相反的问题 - 如何让Unity不要冻结 - 以及建议使用Coroutines或Threads的答案 .
任何帮助都感激不尽 .
提前致谢!!!
4 回答
您可以使用Coroutine创建Thread:
添加到列表消息:
如果有任何变化,请检查lateupdate:
如果我理解正确你想挂起Unity的内部绘图机制,直到你从服务器收到新数据?
如果是这种情况,那么只需在
Update
或LateUpdate
方法中等待它:但这不是你应该如何使用
Unity
引擎 .如果这不是你想要的东西然后把评论,我会删除这个答案:)
删除Update()函数并将代码添加到WriteSocket()函数的回调函数中 .
那就对了 . 在您的公告如下之后,这也是我最初的想法:
冻结帧
ping
计算
pong
下一帧
转化为代码将是:
这在许多方面都是错误的 . 这将在等待或从python接收数据时冻结Unity . 这可能是你想要的东西,但它在任何方面都不好 .
You must do this in a Thread . 这是因为您使用的是阻止版本的receive函数 .
如果你想从另一个Thread或上面的代码中使用Unity的API,你应该看看这个post .
Do not use read from socket from the main Thread like you are currently doing . 一个例外是使用
async
函数但在这种情况下不是 .这有很多原因,最糟糕的是你的UI没有响应,直到你从python代码收到一些东西 .
至于暂停你的游戏,你可以简单地使用enum和if语句来完成它 .
然后在你发挥作用的每个函数中,你可以做这样的事情:
当您想要从上面的那个线程暂停游戏时,您只需执行以下操作:
要取消使用:
现在,您不会冻结您的游戏或UI .