前言:几个月前做项目时写的东西,主要的过程还是在python中拿json数据创序列打各种关键帧
1.准备工作:
-
UE4项目中启用Python插件:--Python Editor Script Plugin
-
项目插件设置中启用Python编辑器插件:--Python Editor (BT)
MarketplaceURL:com.epicgames.launcher://ue/marketplace/product/f6b726c986ee42838882d004bdf94380
-
项目插件设置中启用VaRest插件并重启:
MarketplaceURL:
com.epicgames.launcher://ue/marketplace/content/e47be161e7a24e928560290abd5dcc4f
2.基础文件与代码:
-
在Python编辑器中创建CreateSequence.py:
-
示例createseq.Json文档(Content/JsonFile/...)--序列的开始结束时间,船与子弹的位移行动与关键帧:
{
"starttimestamp": "0",
"endtimestamp": "50",
"commands": [
{
"commandtype": "Create",
"objectcreateinfo": {
"object": {
"id": "1",
"objecttype": "myship"
},
"propertys": [
{
"key": "DisplayName",
"value": "我的船",
"propertytype": "String",
"displaystring": "我的船"
}
],
"rotation": {
"roll": 60,
"pitch": 0,
"yaw": 0
},
"position": {
"latitude": "0",
"longitude": "0",
"elevation": "0"
}
},
"lasttimestamp": "0",
"timestamp": "3"
},
{
"commandtype": "Action",
"objectactioninfo": {
"object": {
"id": "1",
"objecttype": "myship"
},
"action": "Show",
"propertys": []
},
"lasttimestamp": "3",
"timestamp": "4"
},
{
"commandtype": "Move",
"objectmoveinfo": {
"object": {
"id": "1",
"objecttype": "myship"
},
"rotation": {
"pitch": 90,
"roll": 0,
"yaw": 0
},
"position": {
"latitude": "50",
"longitude": "300",
"elevation": "600"
}
},
"lasttimestamp": "4",
"timestamp": "30"
},
{
"commandtype": "Action",
"objectactioninfo": {
"object": {
"id": "1",
"objecttype": "myship"
},
"action": "Fire",
"propertys": []
},
"lasttimestamp": "30",
"timestamp": "32"
},
{
"commandtype": "Create",
"objectcreateinfo": {
"object": {
"id": "1_0",
"objecttype": "bullet"
},
"propertys": [
{
"key": "DisplayName",
"value": "子弹",
"propertytype": "String",
"displaystring": "子弹"
}
],
"rotation": {
"roll": 0,
"pitch": 0,
"yaw": 0
},
"position": {
"latitude": "0",
"longitude": "0",
"elevation": "0"
}
},
"lasttimestamp": "32",
"timestamp": "35"
},
{
"commandtype": "Action",
"objectactioninfo": {
"object": {
"id": "1_0",
"objecttype": "Bullet"
},
"action": "Show",
"propertys": []
},
"lasttimestamp": "35",
"timestamp": "36"
},
{
"commandtype": "Move",
"objectmoveinfo": {
"object": {
"id": "1_0",
"objecttype": "Bullet"
},
"rotation": {
"pitch": 90,
"roll": 0,
"yaw": 0
},
"position": {
"latitude": "50",
"longitude": "300",
"elevation": "600"
}
},
"lasttimestamp": "36",
"timestamp": "40"
},
{
"commandtype": "Move",
"objectmoveinfo": {
"object": {
"id": "2_0",
"objecttype": "Bullet"
},
"rotation": {
"pitch": 90,
"roll": 0,
"yaw": 0
},
"position": {
"latitude": "50",
"longitude": "300",
"elevation": "800"
}
},
"lasttimestamp": "36",
"timestamp": "45"
},
{
"commandtype": "Action",
"objectactioninfo": {
"object": {
"id": "1_0",
"objecttype": "Bullet"
},
"action": "Fire",
"propertys": []
},
"lasttimestamp": "40",
"timestamp": "50"
}
]
}
-
CreateSequence.py中:
# coding: utf-8 #兼容utf-8 import unreal,json,os,sequencer_key_examples #连接虚幻,json,os,sequence库 #创建关卡序列函数,传入一个Str命名即可 def create_seq(filename): #读取/项目目录/JsonFile中的JSON文件数据存入json_data root_path = unreal.SystemLibrary.get_project_directory() + 'Content/JsonFile/' final_path = root_path + filename + '.json' fp = open(final_path,'r',encoding='utf-8') json_str = fp.read() json_data = json.loads(json_str) #下面开始创建序列 #获取开始/结束时间 sequence_starttimestamp = float(float(json_data["starttimestamp"]) / 1000.0) sequence_endtimestamp = float(float(json_data["endtimestamp"]) / 1000.0) print(sequence_endtimestamp) #创建序列的路径 package_path = '/Game/Sequence' print(package_path) #创建序列并设置开始/结束/显示格式 sequence = unreal.AssetToolsHelpers.get_asset_tools().create_asset(str("LS_" + filename), package_path, unreal.LevelSequence, unreal.LevelSequenceFactoryNew()) sequence.set_display_rate(unreal.FrameRate(numerator=1000, denominator=1)) sequence.set_playback_start_seconds(sequence_starttimestamp) sequence.set_playback_end_seconds(sequence_endtimestamp) #读取各项数据创建关键帧 commands = json_data["commands"] for index in range(0,len(commands)): #for command in commands: #json中commandtype为Create时执行 if commands[index]["commandtype"] == "Create": #根据objecttype创建对应的actor #1.创建myship if commands[index]["objectcreateinfo"]["object"]["objecttype"] == "myship": actor_name = "BP_myship" #设置actor_location actor_x = float(commands[index]["objectcreateinfo"]["position"]["uex"]) actor_y = float(commands[index]["objectcreateinfo"]["position"]["uey"]) actro_z = float(commands[index]["objectcreateinfo"]["position"]["uez"]) #设置actor_rotation actor_roll = float(commands[index]["objectcreateinfo"]["rotation"]["roll"]) actor_pitch = float(commands[index]["objectcreateinfo"]["rotation"]["pitch"]) actor_yaw = float(commands[index]["objectcreateinfo"]["rotation"]["yaw"]) #2.创建Bullet if commands[index]["objectcreateinfo"]["object"]["objecttype"] == "Bullet": actor_name = "BP_Bullet" #设置actor_location actor_x = float(commands[index]["objectcreateinfo"]["position"]["uex"]) actor_y = float(commands[index]["objectcreateinfo"]["position"]["uey"]) actro_z = float(commands[index]["objectcreateinfo"]["position"]["uez"]) #设置actor_rotation actor_roll = float(commands[index]["objectcreateinfo"]["rotation"]["roll"]) actor_pitch = float(commands[index]["objectcreateinfo"]["rotation"]["pitch"]) actor_yaw = float(commands[index]["objectcreateinfo"]["rotation"]["yaw"]) #根据路径创建对应的蓝图Actor--/Game/BP/'actor_name' actor_class = unreal.EditorAssetLibrary.load_blueprint_class('/Game/BP/' + actor_name) #打印actor_class到输出日志 print(actor_class) #设置生成/位移/命名 actor_location = unreal.Vector(actor_x,actor_y,actro_z) actor_rotation = unreal.Rotator(actor_roll,actor_pitch,actor_yaw) actor_self = unreal.EditorLevelLibrary.spawn_actor_from_class(actor_class,actor_location,actor_rotation) actor_self.set_actor_label(commands[index]["objectcreateinfo"]["object"]["id"],False) #序列绑定actor/actor的创建关键帧 binding = sequence.add_possessable(actor_self) #为actor添加一个位移关键帧/设置起始结束点 transform_track = binding.add_track(unreal.MovieScene3DTransformTrack) transform_section = transform_track.add_section() transform_section.set_start_frame_seconds(0) transform_section.set_end_frame_seconds(sequence_endtimestamp) #为actor添加一个显示隐藏关键帧/设置起始结束点 visibility_track = binding.add_track(unreal.MovieSceneVisibilityTrack) visibility_track.set_property_name_and_path('bHidden', 'bHidden') visibility_section = visibility_track.add_section() visibility_section.set_start_frame_seconds(0) visibility_section.set_end_frame_seconds(sequence_endtimestamp) #添加关键帧: #位移: #获取位置的xyz通道 channel_location_x = transform_section.get_channels()[0] channel_location_y = transform_section.get_channels()[1] channel_location_z = transform_section.get_channels()[2] #获取旋转yz的关键帧 channel_rotation_x = transform_section.get_channels()[3] channel_rotation_y = transform_section.get_channels()[4] channel_rotation_z = transform_section.get_channels()[5] #添加一个位移关键帧 if index - 1 < 0: index = 1 new_time = unreal.FrameNumber(value = int(commands[index-1]["timestamp"])) channel_location_x.add_key(new_time, actor_x, 0.0) channel_location_y.add_key(new_time, actor_y, 0.0) channel_location_z.add_key(new_time, actro_z, 0.0) channel_rotation_x.add_key(new_time, actor_roll, 0.0) channel_rotation_y.add_key(new_time, actor_pitch, 0.0) channel_rotation_z.add_key(new_time, actor_yaw, 0.0) #设置显示隐藏: #为actor添加可视性(隐藏)关键帧 channel_visibility_bool = visibility_section.get_channels()[0] channel_visibility_bool.add_key(new_time,False) #JSON中命令为move时执行 if commands[index]["commandtype"] == "Move": #位置 actor_x = float(commands[index]["objectmoveinfo"]["position"]["uex"]) actor_y = float(commands[index]["objectmoveinfo"]["position"]["uey"]) actro_z = float(commands[index]["objectmoveinfo"]["position"]["uez"]) #旋转 actor_roll = float(commands[index]["objectmoveinfo"]["rotation"]["roll"]) actor_pitch = float(commands[index]["objectmoveinfo"]["rotation"]["pitch"]) actor_yaw = float(commands[index]["objectmoveinfo"]["rotation"]["yaw"]) #添加关键帧 #获取位置3个通道 channel_location_x = transform_section.get_channels()[0] channel_location_y = transform_section.get_channels()[1] channel_location_z = transform_section.get_channels()[2] #获取旋转yz通道 channel_rotation_x = transform_section.get_channels()[3] channel_rotation_y = transform_section.get_channels()[4] channel_rotation_z = transform_section.get_channels()[5] new_time1 = unreal.FrameNumber(value = int(commands[index]["timestamp"])) channel_location_x.add_key(new_time1, actor_x, 0.0) channel_location_y.add_key(new_time1, actor_y, 0.0) channel_location_z.add_key(new_time1, actro_z, 0.0) channel_rotation_x.add_key(new_time1, actor_roll, 0.0) channel_rotation_y.add_key(new_time1, actor_pitch, 0.0) channel_rotation_z.add_key(new_time1, actor_yaw, 0.0) #JSON中命令为action时执行 if commands[index]["commandtype"] == "Action": #添加可视性/发射子弹的关键帧 new_time2 = unreal.FrameNumber(value = int(commands[index]["timestamp"])) if commands[index]["objectactioninfo"]["object"]["objecttype"] == "myship": if commands[index]["objectactioninfo"]["action"] == "Show": channel_visibility_bool.add_key(new_time2,True) print("Show!") if commands[index]["objectactioninfo"]["action"] == "Fire": print("Fire!") if commands[index]["objectactioninfo"]["action"] == "Hide": channel_visibility_bool.add_key(new_time,False) if commands[index]["objectactioninfo"]["object"]["objecttype"] == "Bullet": if commands[index]["objectactioninfo"]["action"] == "Show": print("Show!") channel_visibility_bool.add_key(new_time2,True) if commands[index]["objectactioninfo"]["action"] == "Fire": print("Fire!") #hide Missile,create particlesystem actor channel_visibility_bool.add_key(new_time2,False) new_time3 = unreal.FrameNumber(value = 0) new_time4 = unreal.FrameNumber(value = int(commands[index]["timestamp"])) #关卡中生成一个BP_Enemy actor_class1 = unreal.EditorAssetLibrary.load_blueprint_class('/Game/BP/BP_Enemy') actor_x1 = float(commands[index-1]["objectmoveinfo"]["position"]["uex"]) actor_y1 = float(commands[index-1]["objectmoveinfo"]["position"]["uey"]) actro_z1 = float(commands[index-1]["objectmoveinfo"]["position"]["uez"]) actor_location1 = unreal.Vector(actor_x1,actor_y1,actro_z1) actor_rotation1 = unreal.Rotator(actor_roll,actor_pitch,actor_yaw) actor_self1 = unreal.EditorLevelLibrary.spawn_actor_from_class(actor_class1,actor_location1,actor_rotation1) #绑定到序列/设置隐藏与显示时间 binding1 = sequence.add_possessable(actor_self1) visibility_track = binding1.add_track(unreal.MovieSceneVisibilityTrack) visibility_track.set_property_name_and_path('bHidden', 'bHidden') visibility_section = visibility_track.add_section() visibility_section.set_start_frame_seconds(0) visibility_section.set_end_frame_seconds(sequence_endtimestamp) channel_visibility_bool = visibility_section.get_channels()[0] channel_visibility_bool.add_key(new_time3,False) channel_visibility_bool.add_key(new_time4,True) if commands[index]["objectactioninfo"]["action"] == "Hide": channel_visibility_bool.add_key(new_time2,False) print("Hide!") #保存关卡序列 unreal.EditorAssetLibrary.save_loaded_asset(sequence, False) #create_seq("TestData") #调用此函数运行
3.虚幻引擎中:
-
菜单栏中-窗口-Python-PythonEditor并双击打开刚才写好的py文件点击运行:
-
创建编辑器工具控件-添加文本输入框与按钮(创建sequence)-添加点击事件:
4.蓝图中:
-
创建函数GetStartEndTime-并且在细节栏中勾选纯函数:
-
控件蓝图事件图表中:
-
编译保存-右击运行该编辑器工具控件-输入json文件名创建序列:
后言:
这个例子只是一部分关键帧,其他的关键帧track类型可以在官方api文档中搜索自己添加
还需要解决一个问题:每次运行函数前需要在PythonEditor中RUN一遍
希望这篇文档能帮到你!