Unreal Python代码段

zhangly 2021-11-05 23:16:35
Categories: > Tags:

列出所有Assets以及类型

import unreal

workingPath = "/Game/"

@unreal.uclass()
class GetEditorAssetLibrary(unreal.EditorAssetLibrary):
    pass

editorAssetLib = GetEditorAssetLibrary()
allAssets = editorAssetLib.list_assets(workingPath, True, False)
allAssetsCount = len(allAssets)

selectedAssetPath = workingPath
print('---'*20)
with unreal.ScopedSlowTask(allAssetsCount, selectedAssetPath) as slowTask:
    slowTask.make_dialog(True)
    for asset in allAssets:
        _assetData = editorAssetLib.find_asset_data(asset)
        _assetName = _assetData.get_asset().get_name()
        _assetPathName = _assetData.get_asset().get_path_name()
        _assetClassName = _assetData.get_asset().get_class().get_name()
        print('{0}  >>>>  {1}'.format(_assetName, _assetClassName))

"""
type:
LevelSequence, Material, StaticMesh, SkeletalMesh, AnimSequence, Skeleton, PhysicsAsset
"""

输出log

import unreal

unreal.log('基本')
unreal.log_warning('警告')
unreal.log_error('报错')

列出所有选择的资产

概念:在Content Browser里的是Assets,在场景中的是Actor

import unreal

@unreal.uclass()
class MyEditorUtility(unreal.GlobalEditorUtilityBase):
    pass

selectedAssets = MyEditorUtility().get_selected_assets()

for asset in selectedAssets:
    unreal.log(asset.get_full_name()) # 获取该资产全名(类的名称+完整的路径)
    unreal.log(asset.get_fname())     # 获取该资产的名称
    unreal.log(asset.get_name())      # 获取该资产的名称
    unreal.log(asset.get_path_name()) # 获取该资产的路径
    unreal.log(asset.get_class())     # 获取该资产的类名
    unreal.log('--'*20)

更多关于ObjectBase的方法可以参考:

https://docs.unrealengine.com/4.27/en-US/PythonAPI/class/_ObjectBase.html

列出所有选择的Actor

import unreal

@unreal.uclass()
class MyEditorUtility(unreal.GlobalEditorUtilityBase):
    pass

selectedActors = MyEditorUtility().get_selection_set()

for actor in selectedActors:
    unreal.log(actor.get_name())             # 获取actor的名称
    unreal.log(actor.get_actor_location())   # 获取actor的loaction实例
    unreal.log(actor.get_actor_transform())  # 获取actor的transform实例
    unreal.log(actor.is_hidden_ed())         # actor是否隐藏
    if actor.actor_has_tag("tagOne"):        # actor是否有xx标签
        actor.destroy_actor()                # 删除actor
        unreal.log_warning(">>>> Do Remove")

    unreal.log("--"*20)

更多关于Actor的方法可以参考:

https://docs.unrealengine.com/4.27/en-US/PythonAPI/class/Actor.html#unreal.Actor

创建蓝图

Factory 工厂:如果需要创建一个蓝图,就要找到蓝图工厂,如果要创建一个动画就要创建动画工厂。

import unreal

blueprintName = "MyEpicBPActorClass"  # 定义蓝图的名称
blueprintPath = "/Game/AutoCreated"   # 定义蓝图的路径

factory = unreal.BlueprintFactory()   # 实例化蓝图类
factory.set_editor_property("ParentClass", unreal.Actor)  # 定义蓝图类型

# 实例化资产创建工具,并执行创建
assetTools = unreal.AssetToolsHelpers.get_asset_tools() 
myFancyNewAssetFile = assetTools.create_asset(blueprintName, blueprintPath, None, factory)

# 保存创建的结果
unreal.EditorAssetLibrary.save_loaded_asset(myFancyNewAssetFile)

创建进度条任务

当一些任务执行时间较长,程序长时间处于“卡死”的状态,可以使用进度条来告知用户程序并没有崩溃。

import unreal

totalFrames = 500000
textDisplay = "This is the text displayed on a progress bar" # 进度显示的文字

with unreal.ScopedSlowTask(totalFrames, textDisplay) as ST:
    ST.make_dialog(True)         # 创建对话框
    for i in range(totalFrames):
        if ST.should_cancel():   # 当用户点击取消时
            break
        unreal.log("running running")
        ST.enter_progress_frame(1)

参考:

https://docs.unrealengine.com/4.27/en-US/PythonAPI/class/ScopedSlowTask.html

创建多个蓝图(案例结合)

import unreal

totalRequiredBlueprints = 70
newAssetName = "BP_pythonMade_%d"
createdAssetsPath = "/Game/TestStuff"
slowTaskDisplayText = "Createing new assets....."

factory = unreal.BlueprintFactory()
factory.set_editor_property("ParentClass", unreal.Pawn)

assetTools = unreal.AssetToolsHelpers.get_asset_tools()

with unreal.ScopedSlowTask(totalRequiredBlueprints, slowTaskDisplayText) as ST:
    ST.make_dialog(True)
    for x in range(totalRequiredBlueprints):
        if ST.should_cancel():
            break
        newAsset = assetTools.create_asset(newAssetName%(x), createdAssetsPath, None, factory)
        unreal.EditorAssetLibrary.save_loaded_asset(newAsset)
        unreal.log("Just created an asset BP_PythonMade_%d via PYTHON API" %(x))
        ST.enter_progress_frame(1)

将选中的Actor放到Level中

import unreal

actorsCount = 50
slowTaskDisplayText = "Spawning actors in the level...."

@unreal.uclass()
class MyEditorUtility(unreal.GlobalEditorUtilityBase):
    pass

selectedAssets = MyEditorUtility().get_selected_assets()

with unreal.ScopedSlowTask(actorsCount, slowTaskDisplayText) as ST:
    ST.make_dialog(True)
    for x in range(actorsCount):
        if ST.should_cancel():
            break
        # 针对关卡的操作,所有这里去找EditorLevelLibray里的方法
        unreal.EditorLevelLibrary.spawn_actor_from_object(selectedAssets[0], unreal.Vector(1.0+x*100, 1.0+x*100, 30.0), unreal.Rotator(0.0, 0.0, 10.0*x))
        unreal.log("Just added an actor to the level!")
        ST.enter_progress_frame(1)

在程序主菜单下添加自定义菜单

unreal-add-custom-menus-p1.png

import unreal

# Get the main menu class
menus = unreal.ToolMenus.get()
menu_name = 'LevelEditor.MainMenu'
menu = menus.find_menu(menu_name)

# Custom menu parameters
owner = menu.get_name()
section_name = 'PythonTools'
name = 'lingyunFX'
label = 'lingyunFX'
tool_tip = 'This is some python toolset.'

# Add and refresh
menu.add_sub_menu(owner, section_name, name, label, tool_tip)
menus.refresh_all_widgets()

为菜单添加按钮

unreal-add-custom-menus-p2.png

import unreal

# Get the menu class
menus = unreal.ToolMenus.get()
menu_name = "LevelEditor.MainMenu.lingyunFX"
menu = menus.find_menu(menu_name)

# Set the button type and label
entry = unreal.ToolMenuEntry(type=unreal.MultiBlockType.MENU_ENTRY)
entry.set_label('TEST BUTTON 01')

# Set button command
typ = unreal.ToolMenuStringCommandType.PYTHON
entry.set_string_command(typ, "", 'print "this is test button"')

# Add and refresh
section_name = ''
menu.add_menu_entry(section_name, entry)
menus.refresh_all_widgets()

section_name 这个参数后面会说到它,其实是一个定位的作用。

关于add_sub_menu和add_menu_entry的参数,可以查看官方文档:

https://docs.unrealengine.com/en-US/PythonAPI/class/ToolMenu.html

(吐槽一下简陋的官方文档,就给了个参数名)

添加工具架按钮

unreal-add-custom-menus-p3.png

import unreal

# Get the menu class
menus = unreal.ToolMenus.get()
menu_name = "LevelEditor.LevelEditorToolBar"
menu = menus.find_menu(menu_name)

# Set the button type and label
entry = unreal.ToolMenuEntry(type=unreal.MultiBlockType.TOOL_BAR_BUTTON)
entry.set_label("Test Button")

# Set button command
typ = unreal.ToolMenuStringCommandType.PYTHON
entry.set_string_command(typ, "", 'print "Hello World!"')

# Add and refresh
section_name = 'Settings'
menu.add_menu_entry(section_name, entry)
menus.refresh_all_widgets()

这里就可以看到section_name参数的意义,它会将按钮放置在Settings集的最后。
如果想把按钮放在其它地方,就得先知道控件的名称。
如何知道这些控件的名字,在这里开启:

unreal-add-custom-menus-p4.png

开启后重启Unreal就可以看到,如下图所示:

unreal-add-custom-menus-p5.png

右键菜单扩展

unreal-add-custom-menus-p6.png

这里想把按钮放到Source Control类别下,所以需要去查看控件名。

通过上面的方法可以看到,名称为:PathContextSourceControl

unreal-add-custom-menus-p7.png

找到控件名,则可以用代码实现效果:

import unreal

# Get the menu class
menus = unreal.ToolMenus.get()
menu_name = "ContentBrowser.FolderContextMenu"
menu = menus.find_menu(menu_name)

# Set the button type and label
entry = unreal.ToolMenuEntry(type=unreal.MultiBlockType.MENU_ENTRY)
entry.set_label("Right Click Test")

# Set button command, add button
typ = unreal.ToolMenuStringCommandType.PYTHON
entry.set_string_command(typ, "", 'print "entry test"')
menu.add_menu_entry('PathContextSourceControl', entry)

右键菜单是点击的时候实时刷新的,所以这里不需要再调用refresh_all_widgets()