UE4 Python脚本编辑器扩展

Python+编辑器扩展

1. 各种菜单的扩展

1.1 主菜单内添加一个子菜单

mainMenu = menus.find_menu('LevelEditor.MainMenu') // 找到主菜单

ownerName = mainMenu.get_name()
# 该名称用于标识一个菜单下的分区名,如果menu的sectionName一致,它们会被放在一起
sectionName = 'PythonTools'
subMenuName = 'MenuTest'
subMenuLabel = 'MenuTest1'
subMenuTip = 'This is menutest1'
menus.add_sub_menu(ownerName, sectionName, subMenuName, subMenuLabel, subMenuTip)
# 刷新窗口
menus.refresh_all_widgets()

想要查看ue编辑器内的各个sectionname,可以在EditorPreference中的Misc中打开相应配置,打开一个菜单时会刷新对应的widget,如果想要窗口全部刷新则可以执行如下python命令
py unreal.ToolMenus.get().refresh_all_widgets()

1.2 菜单项下添加一个按钮

menus = unreal.ToolMenus.get()
# 根据上面的subMenuName找到目标菜单
targetMenu = menus.find_menu('LevelEditor.MainMenu.MenuTest')

menuEntry = unreal.ToolMenuEntry(type=unreal.MultiBlockType.MENU_ENTRY)
menuEntry.set_label('Test Button 1')
menuEntry.set_string_command(unreal.ToolMenuStringCommandType.PYTHON, '', 'print('this is button 1')')

sectionname = ''
targetMenu.add_menu_entry(sectionname, menuEntry)
menus.refresh_all_widgets()

按钮的命令:
unreal.ToolMenuStringCommandType.PYTHON,后面的字符串为python代码;
unreal.ToolMenuStringCommandType.COMMAND,后面的字符串为cmd命令,如使用py xxx.py执行脚本;
等同于输出日志中的python控制台和cmd控制台的py命令;

1.3 为ToolBar添加按钮

# 和上面的两个区别,首先是targetMenu,然后是Entry的类型 
targetMenu = menus.find_menu('LevelEditor.ToolEditorToolBar')
menuEntry = unreal.ToolMenuEntry(type=unreal.MultiBlockType.TOOL_BAR_BUTTON)

1.4 内容浏览器右键菜单扩展

targetMenu = unreal.ToolMenus.get('ContentBrowser.FolderContextMenu')
entry = unreal.ToolMenuEntry(type=unreal.MultiBlockType,MENU_ENTRY) 

# 选中的资源
unreal.ContentBrowserAssetContextMenuContext.get_selected_objects()

1.5 关卡视口中actor右键菜单

可以用如下方式获取选中的actor,但是无法像蓝图一样将actor强转到相应的派生类,因此也就无法获取到实例actor的属性以及不能调用相应的函数;目前的python是不支持这个的,可参考:https://answers.unrealengine.com/questions/938515/casting-a-blueprint-in-python.html;
只能调用actor类已有的内置函数,如set_actor_location()等;

assets = unreal.EditorLevelLibrary.get_selected_level_actors()
for actor in assets:

但是可以修改bp的默认值,如下所示:
我们需要调用unreal.get_default_object来获取CDO(Class Default Object),然后使用set_editor_property来完成功能;

bp_class = unreal.load_class(None, '/Game/NewBlueprint.NewBlueprint_C')
cdo = unreal.get_default_object(bp_class)
cdo.set_editor_property('var', 102)
cdo.call_method('TestFunc', (actor,))

上述列出的问题虽然python内不能解决,但是能够通过蓝图扩展来完成;
基于python的扩展依然还只是在pie中使用;


2. 基础实践

2.1 日志系统

  • unreal.log() : python中的print也会在内部通过unreal.log()来处理
  • unreal.log_warning()
  • unreal.log_error()

2.2 处理资源

如果需要在项目中处理资源,必须使用Unreal Python API来完成,而不能使用Python内置模块来处理磁盘资源文件,比如资源的移动,如果不适用unreal的api则会导致引用失效,所以要尽量使用unreal.EditorAssetLibrary或unreal.AssetTools

尽可能使用虚幻类型
比如数学类等,要尽可能使用Unreal API提供的类型,如unreal.Vector()

2.3 使用json配置来管理各种扩展

os.open/read/write
import json
json.dumps/loads

3.其它常用api

3.1 资源相关

资源相关的api都在这个库里:unreal.EditorAssetLibrary
资源的保存:save_asset()

3.2 工程路径

系统库:unreal.SystemLibrary
获取项目路径:get_project_directory()

4.结合pyqt5的进阶实践

本想使用ue4的api来打开一个文件对话框,但是没有找到,网上有一些使用C++的扩展;
因此就想到了pyqt5也可以完成,而且ue4也可以调用python,这样就不用在C++层处理了,但是这只能用于编辑器模式下;

4.1 打开一个文件对话框

import unreal
import os
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QToolTip, QPushButton, QMessageBox, QDesktopWidget, QFileDialog, QLabel)

class Example(QFileDialog):
 
    def __init__(self):
        super().__init__()
        self.open_folder()

 
    def open_folder(self):
        path = QFileDialog.getExistingDirectory(self, u'选择文件夹', unreal.SystemLibrary.get_project_directory())
        print(path)


app = QApplication(sys.argv)
ex = Example()
sys.exit(app.quit())

5. 常见问题

5.1 Python missing classes from unreal module

一些模块没有找到是因为我们需要安装对应的插件
我们可以使用如下方式可以遍历到unreal下所有的子模块

import unreal
moduels = dir(unreal)
for module in modules:
    print(module)

你可能感兴趣的:(UE4编辑器扩展)