- Home /
Unity as a simulation environment - how to delay the Update() loop while big calculation is performed
Dear community,
I am quite new to Unity and i am currently using it as a tool for designing a simple simulated environment for my pilot research study. Here is a simplified explanation:
The main character (agent) scans the environment and sends the state (as a JSON object) via TCP socket to a python server.
On the python server side a big calculation is performed based on the the state. The result is an action that is being sent back via TCP to Unity.
The character needs to perform this action in Unity and then again scan the environment. The new state is sent again to the python server....
This process is being repeated 'till infinity (unless the client or server is stopped) eventually leading to the agent self-developing a behavior based on its learning.
I finished creating the environment in unity as well as programmed the learning algorithm in python. Moreover, i managed to establish TCP connection between the two. However, i stumbled across the problem of the main Update() loop in Unity.
Namely, if i simplify the process to Unity sending ping (being the state) and python sending pong (being the action) i need the following process to be repeated.
freeze simulation
ping
calculation
pong
unfreeze simulation
So in the Unity Start()
method i setup the socket and send the initial ping. What i would like in the main Update()
loop is to make Unity wait for python's pong answer before updating the frame. I created a script containing a toy example and tried to simulate the calculation-time in python by adding 2 seconds of delay before sending the pong to Unity.
Here is the code for the Unity script (just attach it to the Main Camera):
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;
}
}
...and here is the python server code:
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
I first run the python server and then the simulation (via Unity editor). This results with the following console screenshot:
This proves that the main Update()
loop is running while i want it to pause and update only when "pong" is received from the server. Any ideas how to achieve this?
I searched the forum for answers but always stumbled upon questions that ask for the opposite - how to make Unity not to freeze - and answers that suggest using Coroutines or Threads.
Any help will be much appreciated.
Thanks in advance!!!
Answer by anilhdas · Mar 06, 2017 at 07:06 AM
As I read through your problem, you want to freeze simulation in the client app until your server responds with the necessary action.
You can freeze the Unity app by setting Time.timescale = 0 and resume it when you recieve the response from server by setting timescale back to 1.
But I suggest you to use IEnumerators instead of Update function, since freezing the execution of default functions like Update and FixedUpdate isn't a recommended way to do things.
What I recommend is you can define the task to perform (finding the status, or whatever your client app is supposed to do) in an IEnumerator function and yield a return once your server responds and finally start the coroutine recursively.
Thanks for the quick reply. However, your suggestion ignores the fact that the Unity simulated environment should wait for the server response before continuing. By using a coroutine the environment keeps changing while the calculation on the python server is taking place. This way the loop including: "scan the environment - pause and send state via TCP to python algorithm - do calculation - send the action back to Unity - unpause" is broken. The coroutine will never interrupt the Update function.
Great. What do you mean by the "simulated environment keeps changing". I would see if I can help if you give me further details of how're you simulating the environment in your client app.
Converted your answer to a comment @thecritter. If your client update routines check Time.timescale and return immediately if == 0, what else about the environment would change? Rigidbodies, or animations, for example, will not be processed when timescale == 0.
Your answer
![](https://koobas.hobune.stream/wayback/20220612112305im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Unity tcp_client only working on localhost 1 Answer
Combining python and Unity 3D 1 Answer
How to enable each 3D object to run an instance of python based code 0 Answers
Creating Simulator Quick and Fast 1 Answer
Interactive Cloth - Mobile? 1 Answer