如何使Unity中的C#与Python通信

时间:2019-07-17 16:10:24

标签: c# python unity3d

我正在为Unity游戏制作Q-Learning机器人,该机器人使用Python,而游戏使用c#,如何使两个程序交换任何类型的数据(即整数字符串数组等)? 使Python和Unity的c#进行通信的任何方法都可以解决我的问题, 将任何内容集成到我的代码中都没有问题。

编辑:另一个问题与我的类似,但是答案并没有从Python方面解释要做什么。

我的Python版本是3.6。

2 个答案:

答案 0 :(得分:0)

我假设机器人和游戏是分开的,并且可能是远程进程。对于双向通信,您可以考虑使用某些消息传递中间件或Web服务。

我怀疑更大的问题将在事物的统一性方面。像大多数专有平台一样,Unity具有其自己的网络API。我不确定在Unity中使用独立的基于http或tcp的服务有多复杂。

Unity文档中的

This page涵盖了与非统一应用程序的集成。如果您想采用Web服务方式,Webhooks将是您最好的选择。

RabbitMQ显然有一个Unity3d client,您也许可以找到其他类似的开源项目。

答案 1 :(得分:0)

这是我在unity和python之间进行通信的方式。来自不同来源/教程的混合。

(它对我有用,但是一个已知的问题是,当python中出现错误时Unity会冻结。我已经编写了一个try / catch方法,该方法返回一个空字节数组,但似乎不起作用。)< / p>

C#脚本

using UnityEngine;
//using System.Net;
using System.Net.Sockets;
using System;

public class SocketFloat : MonoBehaviour
{
    public string ip = "127.0.0.1";
    public int port = 60000;
    private Socket client;
    [SerializeField]
    private float[] dataOut, dataIn; //debugging

    /// <summary>
    /// Helper function for sending and receiving.
    /// </summary>
    /// <param name="dataOut">Data to send</param>
    /// <returns></returns>
    protected float[] ServerRequest(float[] dataOut)
    {
        //print("request");
        this.dataOut = dataOut; //debugging
        this.dataIn = SendAndReceive(dataOut); //debugging
        return this.dataIn;
    }

    /// <summary> 
    /// Send data to port, receive data from port.
    /// </summary>
    /// <param name="dataOut">Data to send</param>
    /// <returns></returns>
    private float[] SendAndReceive(float[] dataOut)
    {
        //initialize socket
        float[] floatsReceived;
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        client.Connect(ip, port);
        if (!client.Connected) {
            Debug.LogError("Connection Failed");
            return null; 
        }

        //convert floats to bytes, send to port
        var byteArray = new byte[dataOut.Length * 4];
        Buffer.BlockCopy(dataOut, 0, byteArray, 0, byteArray.Length);
        client.Send(byteArray);

        //allocate and receive bytes
        byte[] bytes = new byte[4000];
        int idxUsedBytes = client.Receive(bytes);
        //print(idxUsedBytes + " new bytes received.");

        //convert bytes to floats
        floatsReceived = new float[idxUsedBytes/4];
        Buffer.BlockCopy(bytes, 0, floatsReceived, 0, idxUsedBytes);

        client.Close();
        return floatsReceived;
    }
}

Python代码

import socket
import struct
import traceback
import logging
import time

def sending_and_reciveing():
    s = socket.socket()
    socket.setdefaulttimeout(None)
    print('socket created ')
    port = 60000
    s.bind(('127.0.0.1', port)) #local host
    s.listen(30) #listening for connection for 30 sec?
    print('socket listensing ... ')
    while True:
        try:
            c, addr = s.accept() #when port connected
            bytes_received = c.recv(4000) #received bytes
            array_received = np.frombuffer(bytes_received, dtype=np.float32) #converting into float array

            nn_output = return_prediction(array_received) #NN prediction (e.g. model.predict())

            bytes_to_send = struct.pack('%sf' % len(nn_output), *nn_output) #converting float to byte
            c.sendall(bytes_to_send) #sending back
            c.close()
        except Exception as e:
            logging.error(traceback.format_exc())
            print("error")
            c.sendall(bytearray([]))
            c.close()
            break

sending_and_reciveing() 

如果要发出请求,请让您的Unity脚本(正在使用的脚本)从SocketFloat派生:

public class Turing : SocketFloat

调用ServerRequest返回来自Python的预测。

float[] prediction = ServerRequest(myArray)