杰瑞科技汇

Python如何赋能Unity3D开发?

Of course! Using Python with Unity is a powerful and increasingly popular workflow. Here’s a comprehensive guide covering the main methods, their pros and cons, and practical examples.

Python如何赋能Unity3D开发?-图1
(图片来源网络,侵删)

The Core Concept: How Python and Unity Interact

It's crucial to understand one fundamental thing: You cannot run Python scripts inside a standalone Unity build (like for PC, Mac, or mobile).

Unity is built on C#, and its engine is compiled to native code. Python is an interpreted language that requires its own runtime environment.

Therefore, the interaction between Python and Unity happens externally. Your Unity game acts as a "server," and your Python scripts act as "clients" that send and receive data. This is primarily achieved through Inter-Process Communication (IPC).

The most common and effective methods for this are:

Python如何赋能Unity3D开发?-图2
(图片来源网络,侵删)
  1. Unity-Python Bridge (UPB): A dedicated library designed for this purpose.
  2. gRPC: A high-performance, open-source framework for RPC (Remote Procedure Calls).
  3. Sockets: The low-level, traditional way to send data over a network (even if it's just on your local machine).
  4. Command-Line Arguments: For simple, one-way communication when the game starts.
  5. ML-Agents: A specialized use case for training AI/ML models with Python.

Let's break down the top methods.


Method 1: The Unity-Python Bridge (UPB) - Recommended for Beginners

This is the most straightforward method for getting started. It's a library that handles the complex serialization and communication for you.

How it Works: UPB provides C# scripts for Unity and Python libraries that communicate over a local network port (localhost).

Step-by-Step Guide:

Part A: Unity Setup

  1. Install the Package:

    • In the Unity Editor, go to Window > Package Manager.
    • Click the icon and select "Add package from git URL...".
    • Enter the URL: https://github.com/Kyle-Dorman/Unity-Python-Bridge.git and click "Add".
  2. Create a Communicator Object:

    • In your scene, create an empty GameObject. Call it PythonCommunicator.
    • Add the PythonCommunicator.cs script to this GameObject. You can find it in the package's folder or by dragging it from the Project window.
  3. Write C# Code to Send/Receive Data:

    • The PythonCommunicator has two main events: OnMessageReceived and OnObjectReceived.

    Example C# Script (PlayerController.cs):

    using UnityEngine;
    using UPB; // Make sure to include the UPB namespace
    public class PlayerController : MonoBehaviour
    {
        public PythonCommunicator communicator; // Drag the PythonCommunicator object here in the Inspector
        void Start()
        {
            // Subscribe to the event for receiving messages
            communicator.OnMessageReceived += HandleMessageFromPython;
            communicator.OnObjectReceived += HandleObjectFromPython;
        }
        void Update()
        {
            // Example: Send player position to Python every frame
            if (Input.GetKeyDown(KeyCode.Space))
            {
                string positionData = $"Player is at: {transform.position.x}, {transform.position.y}, {transform.position.z}";
                communicator.Send("unity_message", positionData); // Send a string
            }
        }
        private void HandleMessageFromPython(string message)
        {
            Debug.Log($"Received message from Python: {message}");
        }
        private void HandleObjectFromPython(object obj)
        {
            // This is for receiving serialized objects. You need to know the type.
            // For example, if you send a Vector3 from Python, you'd cast it here.
            if (obj is Vector3 receivedVector)
            {
                Debug.Log($"Received Vector3 from Python: {receivedVector}");
                transform.position = receivedVector;
            }
        }
    }

Part B: Python Setup

  1. Install the Python Library:

    • Open your terminal or command prompt and run:
      pip install upb-python
  2. Write Python Code to Send/Receive Data:

    Example Python Script (unity_connector.py):

    import upb
    import time
    import random
    # Connect to Unity on localhost, port 50001
    connector = upb.UnityConnector(host="localhost", port=50001)
    print("Connected to Unity. Waiting for messages...")
    # Define a function to handle messages from Unity
    def on_message_received(message):
        print(f"PYTHON: Received message from Unity: '{message.data}'")
    # Define a function to handle objects from Unity
    def on_object_received(obj):
        print(f"PYTHON: Received object from Unity of type: {type(obj)}")
    # Subscribe to the events
    connector.on_message = on_message_received
    connector.on_object = on_object_received
    try:
        # Main loop to send data to Unity
        while True:
            # Send a simple string message every 2 seconds
            connector.send("python_message", f"Hello from Python! Time: {time.time()}")
            # Send a Vector3 object every 3 seconds
            if int(time.time()) % 3 == 0:
                vector_to_send = Vector3(random.uniform(-5, 5), 1, random.uniform(-5, 5))
                connector.send("unity_object", vector_to_send) # Note: We send to 'unity_object' to be caught by OnObjectReceived in C#
            time.sleep(1)
    except KeyboardInterrupt:
        print("Disconnecting...")
        connector.disconnect()

    Note: You'll need to define the Vector3 class in your Python script or import it from a library like PyGame or NumPy.


Method 2: gRPC - For High Performance and Scalability

gRPC is a modern, high-performance RPC framework from Google. It's more complex to set up but is incredibly fast and robust, making it ideal for complex simulations, AI model inference, or multi-user applications.

How it Works:

  1. You define a service in a special language-agnostic file called Protocol Buffers (.proto).
  2. You use the protoc compiler to generate C# and Python code from this .proto file. This gives you strongly-typed client and server stubs.
  3. Your Unity game hosts the gRPC server.
  4. Your Python script acts as the client that calls functions on the Unity server.

Simplified Workflow:

  1. Define the Service (unity_service.proto):

    syntax = "proto3";
    service UnityService {
      rpc GetPlayerPosition (PlayerRequest) returns (PositionResponse) {}
      rpc MovePlayer (MoveRequest) returns (EmptyResponse) {}
    }
    message PlayerRequest {
      int32 player_id = 1;
    }
    message PositionResponse {
      float x = 1;
      float y = 2;
      float z = 3;
    }
    message MoveRequest {
      int32 player_id = 1;
      float x = 2;
      float y = 3;
      float z = 4;
    }
    message EmptyResponse {}
  2. Generate Code:

    • Install the protocol buffer compiler (protoc).
    • Run protoc with the C# and Python plugins to generate the service classes.
  3. Unity (Server):

    • You'll need a gRPC server library for Unity (e.g., Grpc.Core).
    • Implement the UnityServiceBase class and define the logic for GetPlayerPosition and MovePlayer.
  4. Python (Client):

    • Use the generated Python stubs to create a client.
    • Call stub.GetPlayerPosition(request) or stub.MovePlayer(request).

Method 3: Sockets - The "From Scratch" Approach

This gives you the most control but requires you to handle serialization (turning data into bytes) and message framing yourself.

How it Works:

  • Unity opens a TcpListener (server).
  • Python opens a TcpClient (client) and connects to Unity's IP and port.
  • They send data streams back and forth.

The Hard Part: Serialization You can't just send a string like "Hello World". You need to agree on a format. A common format is JSON.

Example C# (Server):

using UnityEngine;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
public class SocketServer : MonoBehaviour
{
    TcpListener listener;
    void Start()
    {
        listener = new TcpListener(System.Net.IPAddress.Loopback, 8080);
        listener.Start();
        Debug.Log("Socket server started. Waiting for a connection...");
        Task.Run(AcceptClients);
    }
    async void AcceptClients()
    {
        while (true)
        {
            using (TcpClient client = await listener.AcceptTcpClientAsync())
            using (NetworkStream stream = client.GetStream())
            {
                byte[] buffer = new byte[1024];
                int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                string data = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Debug.Log($"Received JSON: {data}");
                // You would use a JSON library like Newtonsoft.Json to parse this
                // For example: var myObject = JsonConvert.DeserializeObject<MyClass>(data);
            }
        }
    }
}

Example Python (Client):

import socket
import json
HOST = '127.0.0.1'  # The server's hostname or IP address
PORT = 8080        # The port used by the server
data_to_send = {"player_id": 1, "position": {"x": 10.5, "y": 0, "z": -5.2}}
json_string = json.dumps(data_to_send)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    s.sendall(json_string.encode('utf-8'))
    print(f"Sent JSON to Unity: {json_string}")

Method 4: Command-Line Arguments

This is the simplest method, but it's one-way (from OS to Unity) and only runs at startup.

How it Works: When you launch your Unity build from the command line, you can pass arguments. Unity's Application.argv array in C# will contain these arguments.

Example (Command Line):

# On Windows
YourGame.exe --level 2 --difficulty hard
# On macOS/Linux
./YourGame.app/Contents/MacOS/YourGame --level 2 --difficulty hard

Example C# (in Unity):

using UnityEngine;
public class StartupArgs : MonoBehaviour
{
    void Start()
    {
        for (int i = 0; i < Application.argv.Length; i++)
        {
            Debug.Log($"Arg {i}: {Application.argv[i]}");
        }
        // Example: Check for a specific argument
        if (System.Array.IndexOf(Application.argv, "--level") != -1)
        {
            int levelIndex = int.Parse(Application.argv[System.Array.IndexOf(Application.argv, "--level") + 1]);
            Debug.Log($"Loading level {levelIndex}...");
            // LoadScene(levelIndex);
        }
    }
}

Method 5: Unity ML-Agents

This is a specialized, official solution for training AI/ML models (like Reinforcement Learning models) in Python.

How it Works:

  • You create "Academies" and "Agents" in your Unity scene.
  • These agents observe the environment (e.g., camera images, game state) and take actions (e.g., move left/right).
  • The Unity environment sends this data to a Python training environment.
  • The Python environment (using libraries like PyTorch or TensorFlow) runs a learning algorithm and sends back decisions (actions) for the agents to take.
  • This loop continues until the AI is trained.

This is not for general-purpose scripting but is the industry standard for creating AI behaviors for games.


Summary and Recommendation

Method Best For Pros Cons
Unity-Python Bridge (UPB) Beginners, rapid prototyping, general-purpose communication Very easy to set up, handles serialization, good performance for most cases. Less performant than gRPC, less control than raw sockets.
gRPC High-performance, scalable applications, AI inference Extremely fast, strongly-typed, robust, supports streaming. Steeper learning curve, more complex setup (.proto files, code gen).
Sockets Full control, learning, custom protocols Maximum flexibility, no external libraries needed (beyond a JSON lib). Very complex to implement correctly (serialization, threading, error handling).
Command-Line Args One-time configuration at game launch Simple, built-in, no code needed in Python. One-way communication, only at startup.
ML-Agents Training AI/ML models for games Official, powerful, designed specifically for this task. Highly specialized, not for general scripting.

My Recommendation:

  • If you are new to this or want to quickly connect Unity and Python for data logging, AI control, or tools: Start with the Unity-Python Bridge (UPB). It's the fastest way to get results without getting bogged down in network details.
  • If you are building a system that requires high throughput and scalability, like a backend for a multiplayer game or a complex AI simulation: Invest the time to learn gRPC. It's the professional standard for a reason.
分享:
扫描分享到社交APP
上一篇
下一篇