Bootstrap

Unity for Python —— 强大的 Python 脚本支持提升 Unity 编辑器效率

内容将会持续更新,有错误的地方欢迎指正,谢谢!
 

Unity for Python —— 强大的 Python 脚本支持提升 Unity 编辑器效率
     
TechX 坚持将创新的科技带给世界!

拥有更好的学习体验 —— 不断努力,不断进步,不断探索
TechX —— 心探索、心进取!

助力快速掌握 关键词 学习

为初学者节省宝贵的学习时间,避免困惑!


前言:

  在 Unity 开发过程中,我们常常面临一些重复性、繁琐的任务,尤其是在编辑器开发和自动化工作流方面。为了提高效率和扩展 Unity 编辑器,Unity 官方推出了 Python for Unity,它允许开发者在 Unity 编辑器中运行 Python 脚本,从而增强工作流、自动化任务和数据处理。

  本文将详细介绍 Unity for Python 的功能、部署步骤、低级 API 和高级 API,举例说明如何在实际开发中使用它,并展示一些常见的应用案例,帮助你快速掌握如何利用 Python 在 Unity 中提高开发效率。

TechX 教程效果:

在这里插入图片描述



一、什么是 Unity for Python?


Unity for Python 是 Unity 编辑器的一个扩展,允许开发者通过 Python 脚本与 Unity 编辑器进行交互。它使得 Python 成为 Unity 编辑器的一部分,可以用于自动化开发流程、创建自定义工具、操作场景数据以及与外部系统进行交互。通过 Python,开发者可以利用 Python 在数据处理、科学计算、文件操作等方面的强大能力,从而提高开发效率。



二、Unity for Python 的功能和应用


Unity for Python 的主要功能包括:

  • 自动化任务:通过 Python 脚本自动化一些重复性任务,比如批量修改资源、更新游戏对象属性、批量处理场景元素等。
  • 自定义工具和编辑器扩展:使用 Python 脚本创建自定义工具,增强 Unity 编辑器功能,提供更多灵活的操作界面。
  • 数据导入与处理:通过 Python 导入外部数据(如 CSV、JSON 等),并在 Unity 中应用。
  • 与 Unity 编辑器和游戏对象的交互:Python 可以直接访问 Unity 编辑器 API,操作场景中的对象、资源以及材质等。


三、Unity for Python 使用条件与安装


1、使用条件


要使用 Unity for Python,你需要满足以下条件:

  • 系统要求:仅限 Windows 10+ 或 macOS High Sierra 10.13+,64 位版本。
  • Unity 版本:Unity 2021.2。我们建议通过 Unity Hub 安装最新版本的 Unity 2021.2;2020.2 是最小值。

2、安装


您可以通过 Package Manager 或项目的清单安装此包。

在 Unity 2022.1 及更高版本中:

  • 打开 Package Manager Project Settings。

  • 启用 Enable Pre-release packages 复选框。

  • 打开 Package Manager 窗口。

  • 单击 Packages 下拉列表,然后选择 Unity Registry。

  • 在包列表中找到并选择 Python for Unity,然后单击 Install。

在 Unity 2021.2 中:

  • 打开 Package Manager 窗口。

  • 单击 + 下拉列表,然后选择 Add package by name。

  • 输入 com.unity.scripting.python,然后单击 Add。

安装过程完成后,控制台中将显示“Python successfully installed”。

3、验证安装


安装和配置完成后,打开 Window > General > Python Console。如果 Python 控制台正常显示,且可以输入命令执行 Python 脚本,则说明安装成功。

在这里插入图片描述



四、Python for Unity 设置


在Unity中使用Python脚本时,可能需要安装额外的Python包。Python for Unity提供了多种方式来管理这些包:

1、使用requirements.txt文件


您可以在项目的ProjectSettings文件夹中创建一个名为requirements.txt的文件,列出所需的Python包及其版本。每次打开项目时,Unity会自动根据该文件安装或更新Python包。

请注意,只有在项目打开时才会应用requirements.txt中的更改,如果在Unity运行时修改了该文件,需要重新启动Unity以使更改生效。

2、手动安装Python包


您可以使用 pip 为您的项目安装 Python 包。它们将安装在项目的 Library/PythonInstall/Lib/site-packages 文件夹中。如果需要手动安装或更新Python包,可以按照以下步骤操作:

  • Windows:

    1. 在Project Settings > Python Scripting中,点击Launch Terminal按钮。

    2. 这将打开一个PowerShell窗口,其PATH 环境已配置为Unity的Python安装路径。

    3. 在该窗口中,使用pip3命令安装所需的包,例如:

      pip3 install numpy
      
    4. 安装完成后,运行以下命令将当前安装的包列表保存到requirements.txt:

      pip3 freeze > ProjectSettings/requirements.txt
      
  • macOS:

    1. 在Unity项目中,右键点击Assets文件夹,选择Reveal in Finder。

    2. 打开终端(Terminal),输入cd,然后将Library文件夹拖入终端窗口,按下回车。

    3. 接着输入:

      cd PythonInstall/bin
      
    4. 使用以下命令安装所需的包:

      ./pip3 install numpy
      
    5. 安装完成后,运行以下命令将当前安装的包列表保存到requirements.txt:

      ./pip3 freeze > ../../../ProjectSettings/requirements.txt
      

请注意,修改requirements.txt文件后,需要重新启动Unity以应用更改。



五、API 介绍


Unity for Python 提供了多种 API,主要包括低级 API、高级 API 以及交互 API(用于传参和返回结果)。

1、Low-level API


您可以直接使用 Python for .NET,它包装了 CPython API。使用 C# dynamic 类型,您可以编写类似于 Python 的 C#。

低级 API 通过 PythonEngine 进行 Python 环境的初始化和代码执行,允许更精细的控制和复杂交互。

示例:使用 PythonEngine 执行 Python 代码

using Python.Runtime;
using UnityEditor.Scripting.Python;

public class MyPythonScript
{
    [MenuItem("MyPythonScript/Run")]
    public static void Run()
    {
        PythonRunner.EnsureInitialized();
        using (Py.GIL()) {
            try {
                dynamic sys = Py.Import("sys");
                UnityEngine.Debug.Log($"python version: {sys.version}");
            } catch(PythonException e) {
                UnityEngine.Debug.LogException(e);
            }
        }
    }
}

通过调用 PythonRunner.EnsureInitialized() 确保 Python 已正确初始化。

始终获取 CPython 全局解释器锁 (GIL)。

您需要添加程序集引用,以便编译器知道在 Python.Runtime 中的何处可以找到低级 API。在项目视图中,右键单击并创建新的程序集引用:
在这里插入图片描述

然后添加对 com.unity.scripting.python.editor 的引用 :

在这里插入图片描述

2、High-level API


高级 API 提供了更简洁的接口,通过 PythonRunner.RunString 和 PythonRunner.RunFile 快速执行 Python 脚本,无需手动管理 Python 环境,非常适合自动化任务和编辑器扩展。

示例:使用 PythonRunner.RunString 执行内联 Python 代码

using UnityEditor;
using UnityEditor.Scripting.Python;
using UnityEngine;

public class HelloWorld
{
    [MenuItem("Python/Hello World")]
    static void PrintHelloWorldFromPython()
    {
        PythonRunner.RunString(@"
import UnityEngine
UnityEngine.Debug.Log('hello world')
        ");
    }
}

您可以使用 C# 中可用的任何程序集,只需使用 Python import 语句导入它 - 在示例中,我们展示了如何导入 UnityEngine。

示例:使用 PythonRunner.RunFile 执行 Python 脚本文件

您可以使用 PythonRunner.RunFile 方法执行整个 Python 脚本,而不是在 C# 脚本中内联 Python 代码。例如,此 Python 脚本循环访问场景中的所有 GameObject,并确保所有名称都以下划线结尾:

import UnityEngine

all_objects = UnityEngine.Object.FindObjectsOfType(UnityEngine.GameObject)
for go in all_objects:
    if go.name[-1] != '_':
        go.name = go.name + '_'

将此文件放在 Assets/ensure_naming.py 中。脚本文件可以位于文件系统上的任何位置,它们不需要位于项目中。您可以从 C# 运行此 Python 脚本,如下所示:

using UnityEditor.Scripting.Python;
using UnityEditor;
using UnityEngine;

public class EnsureNaming
{
    [MenuItem("Python/Ensure Naming")]
    static void RunEnsureNaming()
    {
        PythonRunner.RunFile($"{Application.dataPath}/ensure_naming.py");
    }
}

3、 API 交互 —— 带参调用与返回结果

Unity for Python 同样支持调用 Python 中的单个函数、传递参数、获取返回值,甚至支持复杂数据结构的返回。

示例一:C# 调用Python

将 Python 脚本保存为 calculate_sum.py:

# calculate_sum.py
import sys

def calculate_sum(a, b):
    return a + b

C# 调用代码如下:

using UnityEditor;
using UnityEditor.Scripting.Python;
using UnityEngine;

public class PythonWithParamsFromFile
{
    [MenuItem("Python/Calculate Sum From File")]
    static void CalculateSumFromFile()
    {
        PythonRunner.EnsureInitialized();
		using (Py.GIL())
		{
		    try
		    {
		        dynamic sys = Py.Import("calculate_sum");
		        dynamic sum = sys.calculate_sum(1,2);
		        Debug.Log($"python version: {sum}");
		    }
		    catch (PythonException e)
		    {
		        Debug.LogException(e);
		    }
		}
    }
}

在这里要特别注意,Python 的 import 机制会在 当前目录 或 sys.path 列表中的目录 查找模块。因此,确保 calculate_sum.py 放在 Unity 可被 Python 识别的目录。

在Project Settings=>Python Scripting设置的Package Directories中,将你的py脚本所在目录添加到这个列表中,这样才可以导入这个模块并执行里面的方法。

在这里插入图片描述

**示例二:Python 调用 C# **

C# 脚本也定义一个计算两个数和的函数,可以供Python调用。

C# 脚本 PlayerController.py:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace PlayerController
{
    public class PlayerController : MonoBehaviour
    {
        public int Sum(int a, int b)
        { 
            return a + b;
        }
    }
}

Python 调用如下:

import UnityEngine
import PlayerController

# 获取场景中的 Player
player = UnityEngine.GameObject.Find("Player")

# 获取 Player 的 PlayerController 组件
controller = player.GetComponent(PlayerController.PlayerController)

print(controller)

sum = controller.Sum(1,6)

print(sum)

在Python里面,所有的程序集已经自动加载,不在需要手动去加载

#手动加载,但是这里不在需要这样去加载
import clr
clr.AddReference("Assembly-CSharp")

但是我们需要导入模块,这里的模块指的是C#中的命名空间名称,像这样namespace PlayerController,如果写的脚本没有命名空间,直接去导入类的话会报错找不到模块,这块是需要注意的



六、实际应用案例


下面通过几个实际案例展示 Unity for Python 能够实现哪些功能,帮助你在项目中灵活应用这一工具。

案例 1:批量修改资源

通过 Python 脚本批量处理项目中资源,例如重命名 Prefab 文件。

import UnityEditor
import os

asset_paths = UnityEditor.AssetDatabase.GetAllAssetPaths()
prefix = "NewPrefix_"

for path in asset_paths:
    if path.endswith(".prefab"):
        file_name = os.path.basename(path)
        new_file_name = prefix + file_name
        UnityEditor.AssetDatabase.RenameAsset(path, new_file_name)
        
UnityEditor.AssetDatabase.Refresh()

案例 2:自动化构建流程

使用 Python 脚本自动构建项目、生成构建报告,并进行构建后处理。

import UnityEditor
import datetime

build_target = UnityEditor.BuildTarget.StandaloneWindows
build_path = "Builds/MyGame.exe"
report_path = "Builds/BuildReport.txt"

UnityEditor.BuildPipeline.BuildPlayer(UnityEditor.EditorBuildSettings.scenes, build_path, build_target, UnityEditor.BuildOptions.None)

with open(report_path, 'w') as file:
    file.write(f"Build Report - {datetime.datetime.now()}\n")
    file.write(f"Build Path: {build_path}\n")
    file.write("Scenes Included:\n")
    for scene in UnityEditor.EditorBuildSettings.scenes:
        file.write(f"- {scene.path}\n")

案例 3:自定义编辑器工具

使用 Python 创建自定义编辑器窗口,实现对选中对象名称的快速修改。

import UnityEditor
import UnityEngine

class CustomEditorWindow(UnityEditor.EditorWindow):
    @staticmethod
    def show_window():
        window = UnityEditor.EditorWindow.GetWindow(CustomEditorWindow, True, "Custom Editor Tool")
        window.Show()

    def OnGUI(self):
        self.obj_name = UnityEditor.EditorGUILayout.TextField("Object Name", self.obj_name)
        
        if UnityEditor.EditorGUILayout.Button("Change Object Name"):
            selected_objects = UnityEditor.Selection.objects
            for obj in selected_objects:
                if isinstance(obj, UnityEngine.GameObject):
                    obj.name = self.obj_name
                    UnityEditor.EditorUtility.SetDirty(obj)

CustomEditorWindow.show_window()

案例 4:数据导入与处理

从 CSV 文件导入数据,并将数据应用到场景中的游戏对象上。

Name,X,Y,Z
Cube1,10,10,10
Cube2,20,20,20
import csv
import UnityEditor
import UnityEngine

file_path = "Assets/PositionData.csv"
with open(file_path, newline='') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        obj_name = row['Name']
        x, y, z = float(row['X']), float(row['Y']), float(row['Z'])
        obj = UnityEngine.GameObject.Find(obj_name)
        if obj:
            obj.transform.position = UnityEngine.Vector3(x, y, z)




TechX —— 心探索、心进取!

每一次跌倒都是一次成长

每一次努力都是一次进步


END
感谢您阅读本篇博客!希望这篇内容对您有所帮助。如果您有任何问题或意见,或者想要了解更多关于本主题的信息,欢迎在评论区留言与我交流。我会非常乐意与大家讨论和分享更多有趣的内容。
如果您喜欢本博客,请点赞和分享给更多的朋友,让更多人受益。同时,您也可以关注我的博客,以便及时获取最新的更新和文章。
在未来的写作中,我将继续努力,分享更多有趣、实用的内容。再次感谢大家的支持和鼓励,期待与您在下一篇博客再见!
;