UE编程基础

Arya Lv3

⏸️前言

都是一些零零碎碎的知识,做些笔记防止自己忘记

打开UE项目的方式

(1)在Epic里面双击项目打开
(2)进入UE引擎,选择项目中的.uproject文件打开
(3)复制UE快捷方式,并且更改UE快捷方式的Target为

1
"D:/install/UnrealEditor.exe(UE程序的地址)" "D:/Game/Sample.uproject(UE项目地址)" -log  

或者把上面的代码存储为.bat文件也可以打开UE项目。

在UE里使用python

1普通python命令在UE中的使用

(1)UE启动之后,在Plugins里面启动Python Editor Script Plugin插件

(2)给UE项目添加python环境变量

在project settings下的搜索栏搜索python,然后在Additional Paths的index下选择路径,会添加相对路径。(最好是添加相对路径)

(3)开启开发者模式

在project settings下的搜索栏搜索python,然后勾选Developer Mode(all users)。此选项勾选后,启动UE,在output log中会看到一条记录:generated:xxx\xxx\unreal.py。这就是UE提供给python的unreal模块。(如果需要快捷提示的话可以添加这个文件到编译器的环境变量中去)

(4)运行python:

(1)在output Log中,下面的下拉框选择python或者python(REPL),区别是REPL可以实时返回数据。使用python在命令行中输入python命令即可。
(2)在output Log中,下面的下拉框选择Cmd(Cmd本身是运行UE中自带的命令的),在命令行中输入

1
py D://test.py               

2.UE里调用python文件并且传参

1
2
3
4
5
6
7
8
import argparse

if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--a', type = int)
parser.add_argument('--b', type = int)
args = parser.parse_args()
print(args.a + args.b)

在命令行使用

1
py D://test.py --a 1 --b 2

3.UE给python提供的模块 – unreal

UE有自己专门提供给python的模块,有且只有一个,那就是unreal模块

1
2
3
4
import unreal
import sys
for f in sys.path:
unreal.log(f)

初学项目

1.按类型选择UE中的actor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import unreal

editor_subsystem = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem)
editor_actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

def get_actor_by_class(actor_class):
world = editor_subsystem.get_editor_world()
actors = unreal.GameplayStatics.get_all_actors_of_class(world, actor_class)
return actors

def select_actors_by_type():
actors = get_actors_by_class(unreal.PostProcessVolume)
editor_actor_subsystem.set_selected_level_actors(actors)

if __name__ == '__main__':
select_actors_by_type()

2.获取特定类型actor的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import unreal

editor_subsystem = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem)
editor_actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

def get_actor_by_class(actor_class):
world = editor_subsystem.get_editor_world()
actors = unreal.GameplayStatics.get_all_actors_of_class(world, actor_class)
return actors

def get_actors_by_classes(actor_classes):
actors = []
for klass in actor_classes:
actors.append(get_actors_by_class(klass))

return actors

def log_actors():
actors = get_actors_by_class(unreal.StaticMeshActor)
for actor in actors:
unreal.log('_'*100)
unreal.log("actor label: {}".format(actor.get_actor_label()))
unreal.log("actor name: {}".format(actor.get_name()))
unreal.log("actor instance name: {}".format(actor.get_fname()))
unreal.log("actor path name: {}".format(actor.get_path_name()))
unreal.log("actor full name: {}".format(actor.get_full_name()))
unreal.log("actor owner: {}".format(actor.get_owner()))
unreal.log("actor attached parent actor: {}".format(actor.get_attached_parent_actor())) # outliner里面的父子关系
unreal.log("actor attached actors: {}".format(actor.get_attached_actors()))
unreal.log("actor folder path: {}".format(actor.get_folder_path())) # outliner里面的父子关系
unreal.log("actor level: {}".format(actor.get_level()))
unreal.log("actor owner: {}".format(actor.get_owner()))
unreal.log("actor parent: {}".format(actor.get_parent_actor())) # 逻辑上的父子关系
unreal.log("actor location: {}".format(actor.get_actor_location()))
unreal.log("actor rotation: {}".format(actor.get_actor_rotation()))


unreal.log("actor root component: {}".format(actor.get_editor_property("RootComponent"))) # 获取根组件
unreal.log("component materials: {}".format(actor.get_materials()))

3.编辑actor属性

注意:每个asset的路径可以通过复制,然后粘贴到编译器中获得。单引号前面是材质类型,后面是路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import unreal
editor_subsystem = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem)
editor_actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

def get_actors_by_selection():
actors = editor_actor_subsystem.get_selected_level_actors()
return actors

def set_selected_actors_location():
for actor in get_actors_by_selection():
actor_location = actor.get_actor_location()
actor_location.y += 100
actor.set_actor_location(actor_location, sweep=False, teleport=True)

def set_selected_actors_property(property_name, property_value):
# 设置actor属性值
for actor in get_actors_by_selection():
try:
actor.set_editor_property(property_name, property_value)
continue
except:
pass
for component in actor.get_components_by_class(unreal.ActorComponent):
try:
component.set_editor_property(property_name, property_value)
except:
pass

def set_selected_actors_assets(property_name, assets_path):
# 设置actor中资产属性的资产路径,例如材质等资产。即设置actor的材质
assets = [get_asset_by_path(a) for a in assets_path]
set_selected_actors_property(property_name, assets)

def set_selected_actors_material_parameter(parameter_name, parameter_value):
# 设置mesh组件的动态材质参数(如果是静态材质则转换为动态材质)
for actor in get_actors_by_selection():
for component in actor.get_components_by_class(unreal.MeshComponent):
if type(parameter_value) in [int, float]:
setter = component.set_scalar_parameter_value_on_materials
elif type(parameter_value) in [tuple, list]:
parameter_value = unreal.Vector(*parameter_value)
setter = component.set_vector_parameter_value_on_materials
elif type(parameter_value) is unreal.Vector:
setter = component.set_vector_parameter_value_on_materials
else:
unreal.log_warning("Unsupported type of parameter{}".format(parameter_value))
try:
setter(parameter_name, parameter_value)
except:
pass

4.添加和销毁actor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
editor_actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
def spawn_actor_from_class(actor_class, actor_label):
# 生成一个只储存在场景中存在的actor,比如light之类的
actor_location = unreal.Vector(0,0,0)
actor_rotation = unreal.Rotator(0,0,0)
actor = editor_actor_subsystem.spawn_actor_from_class(
actor_class, actor_location, actor_rotation
)
actor.set_actor_label(actor_label)
return actor

def spawn_static_mesh_actor_from_asset(actor_label, asset_path):
# 生成一个储存在硬盘上的actor,比如static mesh之类的
actor = spawn_actor_from_class(unreal.StaticMeshActor, actor_label)
asset = get_asset_by_path(asset_path)
actor.static_mesh_component.set_static_mesh(asset)

def get_actors_by_selection():
actors = editor_actor_subsystem.get_selected_level_actors()
return actors

def destroy_actor_by_selection():
# 销毁所选择的actor
actors = get_actors_by_selection()
if type(actors) is list:
for actor in actors:
actor.destroy_actor()
return actors

5.处理asset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
editor_level_subsystem = unreal.get_editor_subsystem(unreal.LevelEditorSubsystem)
def get_content_browser_selection():
# 得到选择的asset名称信息
assets = unreal.EditorUtilityLibrary.get_selected_assets()

def show_assets_in_cb(paths=None):
# 在内容浏览器中定位到资产位置
if paths = None:
paths = []
elif type(paths) is str:
paths = [paths]
elif type(paths) is list:
pass
else:
raise Exception("Unknown value {} in parameter paths".format(paths))
unreal.EditorAssetLibrary.sync_browser_to_objects(asset_paths=paths)

def show_current_level_in_cb():
# 在内容浏览器中定位到当前关卡位置
level_path = editor_level_subsystem.get_current_level().get_path_name()
show_assets_in_cb([level_path])
return level_path

def open_assets_in_editor(paths=None):
if paths is None:
paths = []
elif type(paths) is str:
paths = [paths]
else:
raise Exception("Unknown value {} in parameter paths".format(paths))
loaded_assets = [get_asset_by_path(x) for x in paths]
asset_tools.open_editor_for_assets(assets=loaded_assets)

def asset_exists(path=""):
return unreal.EditorAssetLibrary.does_asset_exist(asset_path=path)

def get_material_instance_constant_parameter(mi_asset_path, parameter_name):
mi_asset = get_asset_by_path(mi_asset_path)

scalars = unreal.MaterialEditingLibrary.get_scalar_parameter_names(mi_asset)
switches = unreal.MaterialEditingLibrary.get_static_switch_parameter(mi_asset)
textures = unreal.MaterialEditingLibrary.get_texture_parameter_names(mi_asset)
vectors = unreal.MaterialEditingLibrary.get_vector_parameter_names(mi_asset)

if parameter_name in scalars:
getter = unreal.MaterialEditingLibrary.get_material_instance_scalar_parameter_value
elif parameter_name in switches:
getter = unreal.MaterialEditingLibrary.get_material_instance_static_switch_parameter_value
elif parameter_name in textures:
getter = unreal.MaterialEditingLibrary.get_material_instance_texture_parameter_value
elif parameter_name in vectors:
getter = unreal.MaterialEditingLibrary.get_material_instance_vector_parameter_value
parameter_value = getter(instance=mi_asset, parameter_name=parameter_name)
return parameter_value

def duplicate_asset(from_path='', to_path=''):
return unreal.EditorAssetLibrary.duplicate_asset(
source_asset_path = from_path,
destination_asset_path=to_path
)

def rename_asset(from_path='', to_path=''):
return unreal.EditorAssetLibrary.rename_asset(
source_asset_path = from_path,
destination_asset_path = to_path

def delete _asset(path=""):
if not path:
return
elif asset_exists(path):
return unreal.EditorAssetLibrary.delete_asset(asset_path_to_delete=path)
)

def save_asset(path='', force_save=True):
return unreal.EditorAssetLibrary.save_asset(
asset_to_save=path,
only_if_is_dirty=not force_save
)

def create_generic_asset(asset_path="", asset_class=None, asset_factory=None, unique_name=True):
"""
_path + 'sequence', unreal.LevelSequence, unreal.LevelSequenceFactoryNew(),
_path + 'material' unreal.Material, unreal.MaterialFactoryNew(),
_path+'world' unreal.World, unreal.WorldFactory(),
_path+'particle_system' unreal.ParticalSystem, unreal.ParticleSystemFactoryNew()
_path+ 'paper_flipbook'
_path+ 'data_struc'
"""
if unique_name:
asset_path, asset_name = asset_tools.create_unique_asset_name(
base_package_name = asset_path, suffix=''
)
if not unreal.EditorAssetLibrary.does_asset_exist(asset_path=asset_path):
_path_ = os.path.dirname(asset_path)
_name_ = os.path.basename(asset_path)
return asset_tools.create_asset(
asset_name=_name_, package_path=_path_,
asset_class=asset_class,
factory=asset_factory
)
return unreal.load_asset(asset_path)

def create_material_instance_constant(parent_mat_path, mi_asset_name=None):
if not mi_asset_name:
parent_material_basename = os.path.basename(parent_material_path).split('.')[0]
mi_asset__name = parent_material_basename + "_inst"
mi_asset_directory = os.path.dirname(parent_material_path)
mi_asset_path = "/".join([mi_asset_directory, mi_asset_name])
mi_asset = create_generic_asset(
asset_path=mi_asset_path,
asset_class=unreal.MaterialInstanceConstant,
asset_factory=unreal.MaterialIntanceConstantFactoryNew()
)
unreal.MaterialEditingLibrary.set_material_instance_parent(mi_asset, parent_mat_path)
return mi_asset_path

def build_import_task(filename='', dest_path='', dest_name=None,opetions=None):
task = unreal.AssetImportTask()
task.automated = True
if dest_name is not None:
task.destination_name = dest_name
task.destination_path = dest_path
task.filename = filename

task.replace_existing =True
task.set_editor_property('options', options)
return task

def execute_import_tasks(tasks=None):
if tasks is None:
tasks = []
asset_tools.import_asset_tasks(tasks)
imported_asset_paths = []
for task in tasks:
for path in task.get_editor_property('imported_object_paths'):
imported_asset_paths.append(path)
return imported_asset_paths

def build_static_mesh_import_options():
options = unreal.FbxImportUI()
options.import_mesh = True
options.mesh_type_to_import = unreal.FBXImportType.FBXIT_STATIC_MESH
options.import_textures = False
options.import_materials = False
options.import_as_skeletal = False

import_data = options.static_mesh_import_data
import_data.import_translation = unreal.Vector(0,0,0)
import_data.import_rotation = unreal.Rotator(0,0,0)
import_data.import_uniform_scale = 1.0
import_data.set_editor_property('combine_meshes', True)
import_data.set_editor_property('generate_lightmap_u_vs', True)
import_data.set_editor_property('auto_generate_collision', True)
return options

def build_skelecton_mesh_import_options(skeletion_path=None):
options = unreal.FbxImportUI()
options.import_mesh = True
options.import_as_skeletal = True
options.mesh_type_to_import = unreal.FBXImportType.FBXIT_SKELETAL_MESH
options.import_textures = False
options.import_materials = False
options.create_physics_asset = False

if skeleton_path is None:
options.skeleton = skeleton_path
else:
options.skeleton = unreal.load_asset(skeleton_path)
import_data = options.static_mesh_import_data
import_data.import_translation = unreal.Vector(0,0,0)
import_data.import_rotation = unreal.Rotator(0,0,0)
import_data.import_uniform_scale = 1.0
import_data.set_editor_property('import_morph_targets', True)
import_data.set_editor_property('update_skeleton_reference_pose', False)
return options

def example_import_csv_asset():
source = "{}".format(csv_file_path)
directory = "{}".format(saved_path)
struct_path = "{}".format(path of whcih struch you want to import csv)

datatable_task = build_import_task(source, directory)
factory = unreal.CSVImportFactory()
factory.automated_import_settings.import_row_struct = get_asset_by_path(struct_path)
datatabale_task.factory = factory
unreal.log(execute_import_tasks([datatable_task]))

7.在UE中添加菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class Toolbox:
def __init__(self):
self.menus = unreal.ToolMenus.get()
self.main_menu = self.menus.find_menu("LevelEditor.MainMenu")
if not self.main_menu:
unreal.log_warning("Failed to find the 'Main' menu.Something is wrong in the force")

def add_sub_menu(self, menu_name, label, parent, section, tip='placeholder', force_recreate=False, submenu_full_name = "{}.{}".format(parent.menu_name, menu_name)):
if force_recreate:
self.menus.remove_menu(submenu_full_name)
if not self.menus.is_menu_registered(submenu_full_name):
self.menus.register_menu(name=menu_name,parent=parent.menu_name)
sub_menu = self.menus.find_menu(submenu_full_name)
if not sub_menu:
unreal.log("Creating Menu {} '{}'".format(submenu_full_name, label))
sub_menu = parent.add_sub_menu(
owner=parent.get_name(),
section_name=section,
name=menu_name,
label=label
)
return sub_menu
def add_menu_item(self, name, label, parent, command, tip="", insert_after="",section="Scripts"):
if insert_after:
entry_position = unreal.ToolMenuInsert(insert_after, unreal.ToolMenuInsertType.AFTER)
else:
entry_position = unreal.ToolMenuInsert("",unreal.ToolMenuInsertType.FIRST)
new_entry = unreal.ToolMenuEntry(
name=name,
type=unreal.MultiBlockType.MENU_ENTRY,
insert_position=entry_position
)
new_entry.set_label(label)
new_entry.set_tool_tip(tip)
new_entry.set_string_command(
type=unreal.ToolMenuStringCommandType.COMMAD,
custom_type="Command",
string=command
)
parent.add_menu_entry(
section_name=section,
args=new_entry
)
return new_entry
def create_menu_items(self):
toolbox_menu = self.add_sub_menu(
menu_name="PythonTools",
label="PythonTools"
parent=self.main_menu,
section='PythonTools'
tip="this is a collection of python tool"
)
toolbox_menu.add_section(
section_name='ActorToolsSection',
label='Actor Tools',
insert_type=unreal.ToolMenuInsertType.DEFAULT
)
toolbox_menu.add_section(
section_name='AssetToolsSection',
label='AssetTools',
insert_type=unreal.ToolMenuInsertType.DEFAULT
)
toolbox_menu.add_section(
section_name='MiscToolsSection',
label='Misc'
insert_type=unreal.ToolMenuInsertType.DEFAULT
)
self.add_menu_item(
name='LogSelectedActor',
label='LogSelectedActors',
parent=toolbox_menu,
command='py LevelActorUtils.py --log_selected_actors()'
tip='Log information for selected actors in level editor',
section='ActorToolsSection'
)

6.ue如何调用py文件中的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import argparse
import types

def my_func1():
print(1)


def my_func2(x=2):
print(x)

def my_func3(*args):
print(*args)


def my_func4(x=4, *args):
print(x, *args)


my_lambda = lambda:print(5)


def _run(input_locals):
parser = argparse.ArgumentParser()
funcs = []
for name,var in input_locals.items():
if type(var) not in [types.FunctionType, types.LambdaType]:
continue
parser.add_argument("--"+name)
funcs.append(name )
sys_args = parser.parse_args()
for name in funcs:
arg_value = getattr(sys_args, name)
if not arg_value:
continue
assert arg_value.startwith("(") and arg_value.endwith(")",\
"Insufficient function arguments found for funtion{}".format(name))
if arg_value == "()":
input_locals[name]()
else:
arguments = arg_value[1:-1].split(",")
input_locals[name](*arguments)



if __name__ == "__main__":
_run(locals())

7.UE中的UI编写

1
 
  • 标题: UE编程基础
  • 作者: Arya
  • 创建于 : 2024-03-12 09:00:00
  • 更新于 : 2024-04-01 15:36:47
  • 链接: https://aryagala0.github.io/2024/03/12/UE开发/UE编程基础/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
 评论