Unity与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 for Python 使用条件与安装
  • 1、使用条件
  • 2、安装
  • 3、验证安装
  • 四、Python for Unity 设置
  • 1、使用requirements.txt文件
  • 2、手动安装Python包
  • 五、API 介绍
  • 1、Low-level API
  • 2、High-level API
  • 3、 API 交互 —— 带参调用与返回结果
  • 六、实际应用案例

  • 一、什么是 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

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

    物联沃分享整理
    物联沃-IOTWORD物联网 » Unity与Python的融合:强大的脚本支持助你提升Unity编辑器效率

    发表回复