Bootstrap Chameleon Logo

Learning Unreal Engine with Python

Python不仅用来做工具,更是学习的工具

简单的说,自省就是在运行时确定对象类型的能力。(在虚幻引擎和TAPython的语境下,这里的运行时指的时编辑器自身的运行时,而不是GamePlay)。通过它我们可以快速熟悉和理解虚幻引擎的的对象及其相互直接的关系。

Python中的一切皆对象,每个对象都有属性和方法(函数)。通过自省我们可以动态得检查每个对象和他们的方法。

获取虚幻引擎中的对象

在编辑器中获取对象中介绍了如何获取引擎中的对象,并将其赋予全局变量_r

其中可以通过菜单获取的对象类型有:

  • UActor
  • UAsset
  • UComponent
  • UMaterialExpression 等

除了通过预置的菜单项来获取物体对象,我们也可以通过Python命令来获取对象

获取Actor

例如,获取选中的Actor

unreal.get_editor_subsystem(unreal.EditorActorSubsystem).get_selected_level_actors()

按照物体的名字查找

unreal.PythonBPLib.find_actor_by_name("StaticMeshActor_8")

CAUTION
注意,物体有所谓的name(ID Name) 和label_name之分。ID Name是不可重复的,而label_name是显示的物体名,会有重名的情况
089_label_id_name

Help命令

在Python窗口中,使用Help命令,可以显示对象的详细信息

例如,通过help(unreal.PythonBPLib.find_actor_by_name),就可以看到 unreal.PythonBPLib.find_actor_by_name这个方法的用途,参数和返回值等等

help(unreal.PythonBPLib.find_actor_by_name)

find_actor_by_name(...) method of builtins.type instance
    X.find_actor_by_name(name, world=None, include_dead=True) -> Actor
    Get actor by name(ID Name) in specified World

    Args:
        name (str): Name(ID Name) of actor
        world (World): World Context
        include_dead (bool): Include dead object or not

    Returns:
        Actor: A pointer to the named actor or NULL if not found.

在上面的方法中,第二个参数是可选的World。默认值为:当前编辑器的World

NOTE
UE用不同的World来划分物体所属于的对象。例如Static Mesh编辑器中的模型,和场景中的物体就处于不同的World;编辑器中摆放的物体和PILE运行游戏时的同一个物体,事实上也属于不同的World

获取当前编辑器的World, UE5

unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem).get_editor_world()

UE4:

unreal.EditorLevelLibrary.get_editor_world()

按Label名字查找

通过unreal.PythonBPLib.find_actors_by_label_name,可以找到当前World中,某一Label Name的所有同名物体

cubes = unreal.PythonBPLib.find_actors_by_label_name("SM_Cube", unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem).get_editor_world())

获取资源UAsset

  • ContentBrowser中选中的资源
  • 按照资源路径获取
  • ContentBrowser中选中的目录
  • 获取指定目录内的所有资源
  • 获取指定类型的资源

获取Component组件

  • 获取选中的Component
  • 获取指定类型的所有Components

自省

在获得想要的物体、资源等后,我们就可以

dir

dir可以列出Python对象的属性,方法等等。对dir稍微包装一下,可以用来快速搜索物体中的属性和方法名等

def d(obj, sub_string=''):
    sub_string = sub_string.lower()
    for x in dir(obj):
        if not sub_string or sub_string in x.lower():
            print(x)

例如用"d(_r, 'name')",来搜索"name"相关的内容

Snapshot showing 'd' method and result in Output window

type

Editor Property

UE中的对象(UObject)与普通的Python对象的有一大不同:

UObject的属性的获取和设置需要通过get_editor_propertyset_editor_property来做。只有这样,才能触发编辑器的PostEditChangeProperty等函数

获取方法

unreal.PythonBPLib.get_all_property_names提供获取某个UObject Class下所有"editor_property"的功能

unreal.PythonBPLib.get_all_property_names(_r.static_class())

NOTE
上面_r是一个StaticMeshActor对象的实例,_r.static_class()获取它的Class

进阶

inspect

inspect模块在Python中提供了许多有用的功能,可以帮助您获取有关实时对象的信息,如模块、类、方法、函数、回溯、帧对象和代码对象。例如,它可以帮助您检查类的内容,检索方法的源代码,提取并格式化函数的参数列表,或者获取显示详细回溯所需的所有信息。”

使用Python的inspect模块,我们可以获得更多更详细的关于物体的信息。

例如:

  • inspect.ismodule(obj) 判断对象是否是模块
  • inspect.getdoc(obj) 获取对象文档
  • inspect.signature(func) 获取函数签名
  • inspect.isbuiltin(attr) 是否为builtin 属性
  • inspect.getsourcefile(func) 获取方法所在的python源文件

把它们连起来

Object detail viewer

当我们能够获取对象的属性,方法,函数签名等等,就可以将它们放在一起,做成一个工具。这就是U_003_ObjectDetailViewer

Unreal Python Stub

当我们在 Preferences > Plugins > Python 中勾选 Developer Mode ,启动UE编辑器之后,就会在 <Your_UE_Project>/Intermediate/PythonStub下生成一个名为unreal.py的存根文件。其中包含了当前编辑器中所有的Python可用的对象和API。我们不仅可以利用它来实现PyCharm,VsCode中的代码补全,也可以利用它来做一些简单的数据分析。从而了解那些Python对象是最常用的,那些是需要重点学习和熟悉的编辑器库

Image showing editor property count for all classes in Unreal Engine

将工程中 Intermediate/PythonStub 目录下的unreal.py 拷贝到 TA/TAPython/Python目录下

使用matplotlib 和networkx,分类和可视化UE对象

参考

拆分unreal.py以获得更好的开发体验

Setting up Autocomplete for Editor Python Scripting