一生二,二生三,三生万物
在之前的为虚幻编辑器添加菜单项中,我们使用 unreal.PythonBPLib.get_selected_folder()
获取到了用户在ContentBrowser中选中的目录。
这个unreal.PythonBPLib.get_selected_folder
就是TAPython内置的200+个扩展的编辑器API之一,这些API补充了为UE编辑器添加了非常多的扩展功能。你可以在这里找它们的API介绍,也可以在这里,找到最常用的编辑器APIs中看到使用频率最高的100个编辑器API。
如何找到已有的API¶
当我们想要使用(调用)一个编辑器功能的时候,推荐照下面的顺序进行查找:
- 如果蓝图中可以有完成这个功能的节点,那么这个蓝图节点的功能就也有对应的Python函数可供调用
- 在设置好Auto Complete For TApython的编辑器中,尝试通过自动补全来查找是否有可用的API
- 搜索unreal的Stub文件,通过它可以快速得找到所需的API。在Auto Complete For TApython中有将unreal.py按类切分成小文件的介绍,这将是我们的搜索和跳转变得非常轻量和快速。
- 查看TAPython的扩展API里是提供类似的功能,比例
- 在编辑的cmd console命令中查找是否有可调用的cmd命令
TIP
在Cmd中输入help
可以显示当前编辑器可使用的所有调试命令
- 在VS中搜索Unreal的各个Editor Library和各个EditorSubSystem相关的代码。
Extra
Epic一直在完善Python的编辑器API,这也是为什么TAPython的扩展的API中会有一些和UE内置的API重复
如果上面的步骤中都没有找到可用的API,我们就可用考虑需要通过C++添加一个额外的编辑器API,以供Python使用,具体做法如下:
添加步骤¶
1. C++ 类型工程¶
首先你需要一个C++类型的Unreal工程
2. 添加一个BlueprintLibrary类型的Unreal插件¶
打开Plugin窗口,点击左上角的Add
按钮
选择Blueprint Library
类型的插件,填写插件名,Author等信息,点击Create Plugin
按钮,这样就创建了一个BlueprintLibrary类型的插件。
在VS Studio中编译完成,其中工程之后,我们在Python命令行中就可以看到这个插件了。
TIP
上图使用的是Python(REPL)模式,在非REPL模式下,需要使用print()函数来输出
插件默认会添加一个MagicBoxSampleFunction的实例函数,参数是一个float,返回-1.0f
MagicBoxBPLibrary.h
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Execute Sample function", Keywords = "MagicBox sample test testing"), Category = "MagicBoxTesting")
static float MagicBoxSampleFunction(float Param);
MagicBoxBPLibrary.cpp
float UMagicBoxBPLibrary::MagicBoxSampleFunction(float Param)
{
return -1;
}
这个函数对于的PythonAPI为:unreal.MagicBoxBPLibrary.magic_box_sample_function
,注意函数名的大小写与C++中的不同
help(unreal.MagicBoxBPLibrary.magic_box_sample_function)
# magic_box_sample_function(...) method of builtins.type instance
# X.magic_box_sample_function(param) -> float
# Magic Box Sample Function
#
# Args:
# param (float):
#
# Returns:
# float:
3. 添加蓝图可调用的函数¶
在VS Studio中打开c++工程,找到MagicBoxBPLibrary这个插件,在MagicBoxBPLibrary.h
和MagicBoxBPLibrary.cpp
分别添加给Python调用的函数的申明和定义,然后编译。通过之后,重启编辑器,我们就可以在编辑中使用新的Python API了
TIP
TAPython提供了额外的编辑器API,当然你编写的编辑器API也可以在TAPython中使用。
4. 编译后在Python中试验¶
函数转换规则¶
c++的函数名在Python中会有大小写的变化,UE的主要规则有以下几点
命名空间¶
- 所有新增的BPLibrary都在unreal命名空间下
- BPLibrary名字与C++中名字一致,大小写不便,如上面的例子中的
MagicBoxBPLibrary
函数名大小写转换¶
- c++中的函数名全部转换为小写字母,大写字母直接以"_"连接。有多个大写字母连续出现时,例如
LOD
,视为一个整体 - bool类型的参数中,如果第一字母为小写的b,然后接着是大写字母。在Python中会将b去掉
例如c++ 中的参数bool bOverride;
在python中对应的为override
- 函数中的参数名亦遵循此规则
例如:
MessageDialog
转换为message_dialog
SetStaticMeshLODMaterialID
转换为set_static_mesh_lod_material_id
参数类型¶
- c++ 中的bool, FString, int32, float 分别对应Python 中的bool,str, integer 和float
- FName 对应Python中的unreal.Name。
NOTE
在Python中不用过分执着于区分FName,FString,甚至FText,它们在Python中有细微的区别,但实际使用时,可以直接使用str,UE会自动做类型转换
-
TArray,TMap分别对应Python中的unreal.Array, unreal.Map
-
蓝图可见的UObject类型在python的unreal命名空间下有同名的python类型
非const引用¶
- 非const引用类型的参数,在python中是对应的返回值,而非输入参数
举个例子
下面函数中的FIntPoint& OutSizeXY
是一个非const的引用类型:
UFUNCTION(BlueprintCallable, meta = (Keywords = "Python Editor"), Category = "PythonEditor")
static TArray<FColor> GetViewportPixels(FIntPoint& OutSizeXY);
它对应的Python函数的签名为:
unreal.PythonBPLib.get_viewport_pixels() -> (Array[Color], out_size_xy=IntPoint)
返回的是一个tuple,其中第一项是Array[Color]
, 第二项为IntPointl类型的out_size_xy
又如:
下面例子中的InGuidStr
变量类型是const的FString引用。正因为这个const
,所以它是输入值;如果去掉const
则它也将变成返回值
UFUNCTION(BlueprintCallable, meta = (Keywords = "Python Editor"), Category = "PythonEditor")
static FGuid GuidFromString(const FString& InGuidStr);
它对应的Python函数的签名为:
unreal.PythonBPLib.guid_from_string(guid_str:str) -> Guid
Array¶
- 参数/返回值中的TArray只能是1维的TArray,不支持2D Array和嵌套
因此对于2D的Array,例如Image中的Pixels,需要将Pixels展平后再输入或者输出
例如:
UFUNCTION(BlueprintCallable, Category = Scripting)
void SetImagePixels(FName AkaName, TArray<FLinearColor> PixelColors, int32 Width, int32 Height);
输入值pixel_colors
是一个1D的Linear的数组
set_image_pixels(...)
x.set_image_pixels(aka_name, pixel_colors, width, height) -> None
Set SImage's Image content with Linear Colors.
Args:
aka_name (Name): The aka name of the widget
pixel_colors (Array[LinearColor]): The pixel list of image, len(PixelColors) == Height * Width
width (int32): Width of Image.
height (int32): Height of Image.
多个返回值¶
利用上面介绍的非const引用的参数,我们可以在c++中将多个返回值,一同返回给Python。
其中c++函数自身的返回值一定是多个返回值(tuple)元素中的第一个,其他参数依次往后排列
自定义结构体¶
我们可以在c++中定义自定义的结构体,然后在Python中使用。
例如下面的例子中,我们定义了一个FStaticSwitchInfo
结构体。在USturct中,我们可以通过USTRUCT(Blueprintable, BlueprintType)
来声明这个结构体是蓝图/Python可见的
USTRUCT(Blueprintable, BlueprintType)
struct FStaticSwitchInfo
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PythonEditor)
FName Name;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PythonEditor)
bool Value;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PythonEditor)
bool bOverride;
};
通过编译之后,我们就可以在Python中使用这个结构体了
class StaticSwitchInfo(StructBase):
r"""
Static Switch Info
**C++ Source:**
- **Plugin**: TAPython
- **Module**: TAPython
- **File**: PythonMaterialLib.h
**Editor Properties:** (see get_editor_property/set_editor_property)
- ``name`` (Name): [Read-Write] Name
- ``override`` (bool): [Read-Write] Override
- ``value`` (bool): [Read-Write] Value
"""
对于为了在Python中使用自定义的结构体,而在c++中定义的结构体,经过我的实践。如果只是为了方便传参,那么不太推荐使用。原因是后续对这个结构体的修改,需要重新编译插件,使得Python在开发中快速敏捷的特性就失去了意义。
TIP
Some tips and Tricks