前言

  经过长达两个星期(包含国庆假期)的爆肝, Minigame 项目终于搞完了。
  虽然之前 Minigame 刚启动不久就已经写了一篇概况文章进行总结,但是后来事情不断增多,就没有就行跟进文章了。
  没想到腾出时间来, Minigame 项目已经基本做完了。
  下面就记录一下这次 Minigame 的开发经历~

前期准备

游戏
存档工具
AI人工智能角色行为Unreal游戏素材资源

角色素材

(写实)
牲畜

(页游)
大唐人物
3DMAX古代大唐中国风人物角色

动作
骑兵弓箭手
手持剑盾
武士动画
15组角色行走动画
攀爬 Unreal Engine虚幻游戏引擎扩展资料2017年10月合辑第一季
忍者动作

shader 效果
雪地

场景
植物山脉

(low poly)
武士道 lowpoly

(页游)
大唐无双场景
高品质中国风场景
游戏镇魔曲

(写实)
日式建筑 Unreal Engine虚幻游戏引擎扩展资料2020年1月合辑第一季
日式建筑 UE4幻游戏引擎扩展资料2020年2月合辑第二季
亚洲神庙寺庙
亚洲建筑景观
日本德川幕府江户旧东京城市建筑场景

  当时在人人素材网里面找到一些比较合适可用的素材。

场景

  在前期准备的过程中,我们定了以影子战术这种潜行暗杀游戏为核心玩法。
  虽然也找好了一些 low poly 的模型素材,但是为什么不直接从游戏里面直接拿呢?

  我知道这款游戏是用 Unity 打包的,于是我去网上找了如何破击 Unity 游戏的方法
  破解 Unity 游戏资源的软件有好多,但是最好用的还是 Github 上开源的 AssetStudio
  免费而且更新相当频繁,抓取得素材也非常全。(就是动画似乎没能成功抓取出来)

  抓取之后可以获取到影子战术的场景的FBX ,将 FBX 导入到 Maya 就可以获取到可以用的资源。

alt
alt
alt

  因为我把资源都抓取出来,所以就打算直接抄里面的资源素材来用。
  于是尝试用这个进行关卡搭建。珠玉在前,最后几乎就是照着抄了原来的场景做。

角色

  我们比较早确定了使用潜行暗杀的玩法,并且将题材固定到了荆轲刺秦上。
  为此我需要找一批合适的角色模型,并且对角色进行绑定制作动画。
  角色上虽然上面找到的素材已经有一些也有风格的资源,但是整体呈现不太 low poly
  而且角色需要围绕秦朝,带有一些古代士兵的模型,于是找来找去,还是往秦时明月上找到了好资源。 资源链接

  这套资源虽然是手绘贴图的,但是角色足够多,这样可以解决风格统一的风格。

alt
alt

  上面是 Maya 整合出来的部分资源。

  有了角色资源之后需要进行 Maya 角色绑定,这里还是采用了 Advance Skeleton 插件来解决控制器的问题。
  通过 ADV5 的 Name Matcher 可以让 ADV 的骨架同步到 Unreal 的骨架并且进行约束控制。

alt

  然后需要导入 Unreal 官方的 Mannequin 骨架,将骨架适配到角色模型上。
  这里有个坑点,原本是打算是只匹配左边,然后右边的骨架删除镜像过去的,但是这么操作会导致 Unreal 的动画不匹配,应该是动了骨骼的朝向导致出问题了。
  后面还是老老实实地调完左边再调整右边的位置,强迫症表示有点难受。
  骨架摆好位置之后可以直接和目标模型进行绑定了,控制器生成,ADV已经做好了按钮,照着顺序点击即可。

alt

  有了控制器,自己做动画也会方便很多。
  后续就是花时间刷权重即可,因为我们的模型都是 low poly ,所以刷权重比较简单。
  刷好了主角的权重之后,其他角色都复制主角的权重就已经差不多了,在把一些边边角角修补一下,就可以了。

  最后放进引擎的 NPC 18 个 | 主角 3 个 | 士兵 5 个
  为了减少秦时明月的辨识度,我还通过换头大法,凭空制作出了几个新的角色,所以 NPC 会有那么多,不过并不是所有的角色都放到游戏里使用。

alt

动画

RPG动作 官网链接
NPC动作 官网链接
武士动画 官网链接

  上面进一步收集了偏 low poly 的战斗动画。
  动画这边经过我在项目组的经验,如果所有的角色都可以用同一套骨骼,那就可以实现动画的互通,这样适配动画会很省事。
  UE 这边也搜索了相关的动画蓝图系统,无意中在一些 Unreal 合集里面发现了 Advance Locomotion 3.0 的包
  万万没想到这个动画蓝图库居然到 4.0 之后完全免费开放到官方的商城里。 链接
  Advance Locomotion 整合了各种运动的变化,4.0 还加入任意攀爬系统以及脚的 IK 系统。在游戏动画的圈子里相当有名,以至于网上都有不少分析这个的文章。
  Advance Locomotion 是以 虚幻的官方 骨骼为标准的,如果我将上面的 Unity 动画全部重定向到 虚幻引擎的官方骨骼就可以同时接入 Advance Locomotion 的特性。

  于是我写了脚本批量将上面的 Unity 动画骨架重定向到 Unreal 上。
  当然这个过程并非一帆风顺的,需要解决一些问题。

  首先就是上面找到的 RPG 动作 和 NPC 动作的 FBX 文件动作只是个 locator 动画数据,并没有骨骼。
  所以我要想办法将 locator 层级转换为骨骼层级。

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
# -*- coding: utf-8 -*-
"""
选择 locator 层级 生成跟随骨骼
"""

from __future__ import division
from __future__ import print_function
from __future__ import absolute_import

__author__ = 'timmyliang'
__email__ = '820472580@qq.com'
__date__ = '2020-09-08 15:34:00'

from maya import cmds

def hierarchyTree(parent, tree):
children = cmds.listRelatives(parent, c=True, type='transform')
if children:
tree[parent] = (children, {})
for child in children:
hierarchyTree(child, tree[parent][1])
else:
del tree

def retrieve2Jnt(tree,jnt_list=[]):
for parent, data in tree.items():

parent_jnt = "%s_jnt" % parent
if not cmds.objExists(parent_jnt):
cmds.select(cl=1)
parent_jnt = cmds.joint(n=parent_jnt)
jnt_list.append((parent_jnt,parent))
# cmds.delete(cmds.parentConstraint(parent,parent_jnt))
cmds.parentConstraint(parent,parent_jnt)

children, child_tree = data
for child in children:
cmds.select(cl=1)
child_jnt = cmds.joint(n="%s_jnt" % child)
jnt_list.append((child_jnt,child))
# cmds.delete(cmds.parentConstraint(child,child_jnt))
cmds.parentConstraint(child,child_jnt)
cmds.parent(child_jnt,parent_jnt)

retrieve2Jnt(child_tree,jnt_list)


def main():

hierarchy_tree = {}
hierarchyTree(cmds.ls(sl=1)[0],hierarchy_tree)

if not hierarchy_tree:
return

jnt_obj_list = []
retrieve2Jnt(hierarchy_tree,jnt_obj_list)

if __name__ == "__main__":
main()

alt

  输出带动画的骨骼之后将关键帧 bake 下来输出成 FBX 文件。
  然后将脚本写成批量操作输出一套带骨骼的 FBX 文件。
  最后就是要解决这套新生成的骨骼如何匹配到 Unreal 骨骼上的问题了。

  有了骨架文件之后需要做一套新骨架约束到 ADV 骨架的重定向方案,最初我是想着用 HumanIK 来做的。
  网上查了一下,发现 ADV 有内置对接 mocap 骨架的功能。

alt

  因为生成的骨架并不是 mocap 骨架,直接用 ADV 归零匹配是会有问题的,所以需要骨架和角色以 T-pose 的方式进行匹配到一起。
  然后就可以用 ADV 做好的一键约束功能将两套骨架通过旋转约束进行同步。
  最好了这个模板即可。

alt

  最后就是用脚本批量导入前面生成的 FBX 骨架动画,然后将角色的 Unreal 官方骨架输出为 FBX 即可,这个 FBX 导入虚幻就是重定向动作的文件了。
  这样就可以得到好几百个重定向好的动画文件,动画匹配其实并不是很完美,但是我们俯视角的游戏下其实问题不大。
  另外武士动画系列的文件带骨骼,比较好处理,虽然全部输出了 FBX 文件,但是最后由于动作太过浮夸,并没有采用。

  输出了 FBX 文件又担心策划不会使用,所以写了个 批量 拍屏脚本,将动画文件套入到我们的主角上,输出了一批视频文件。

alt


  做完了前期工作之后,大概中间有1个多星期没有弄 minigame 了。
  一直到临近脱产才开始将前面搭建的场景合入到项目的 git 下面。

国庆前脱产

  终于 9月25日 进入了 Minigame 脱产开发阶段。
  结合之前搭建好的场景,我计划教会策划使用 Maya ,然后直接复用 影子战术的素材来完成场景的搭建。

Maya 搭建场景输出到 Unreal

  影子战术的素材非常多,最初我考虑用 Maya 缝合影子战术的场景,然后统一导入到 Unreal 里面。
  我考虑使用 Maya 的 Assembly Reference 的方式将相同类型的素材整合到一起,方便切换堆砌场景。

alt

  所以我又写了个脚本一键将 影子战术 的场景中选中的模型导出到制定的目录,并且将模型位置归位到原点上。

alt

  工具还配套了一些修复材质透明等等的辅助功能。
  在开发这些东西的过程中,策划搭建不了场景,我只能安排他们去游戏里找可以用的资源(结果这些时间都浪费掉了)


  使用 Maya 搭建场景是影视的工作流程,在游戏开发里面反而还会多出了一步了迁移模型到引擎的操作。
  而用 Maya 搭建的模型,即便是用了完全相同的模型,引擎也无法识别出来,还是会以独立的模型进行分配。
  不同位置的模型全部会变成一个单独的 StaticMesh , 而且导入到 Unreal 会把电脑的 内存 吃满,流程非常不合理。

  然而导入的时候如果勾选 Combine 选项,最后只会生成一个 StaticMesh ,相对不会那么吃内存。但是碰撞会变成一个整体,又出大问题。

  最后痛定思痛,我需要在 Maya 里面找出相同的模型,然后通过 Locator 定位在虚幻里重新排列模型。 UE4论坛链接
  这套操作参考了论坛小哥的方案,通过 Socket 命名可以让虚幻识别到对应的 locator 位置。
  识别 locator 排列模型则是通过 Unreal 的 Python 来实现。

  寻找相同模型的方案我是通过 材质 + 点数 进行判断的。
  虽然不排除相同材质下的模型点数可能相同但是模型却是不同类型的情况,但是这些特殊情况很少,到时候就单独拿出来处理就好。

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
# -*- coding: utf-8 -*-
"""
材质拓扑一致的模型进行实例替换
"""

from __future__ import division
from __future__ import print_function
from __future__ import absolute_import

__author__ = 'timmyliang'
__email__ = '820472580@qq.com'
__date__ = '2020-09-17 00:00:27'

import os
import json
from collections import defaultdict

import pymel.core as pm
import pymel.core.nodetypes as nt


def error_log(func):
def wrapper(*args, **kwargs):
try:
res = func(*args, **kwargs)
return res
except:
import traceback
print(u"程序错误 | 请联系 梁伟添 timmyliang\n\n%s" % traceback.format_exc())

return wrapper

@error_log
def main():

export_dir = r"D:\_minigame\_scene\test"

# TODO 遍历所有的 Phong 材质进行场景导出
# mtl_list = [mtl for mtl in pm.ls(materials=1) if isinstance(mtl,nt.Phong)]
m = pm.PyNode('bas_ca_wall_stone_12m_00_mat_wet')
mtl_list = [m]

for i,mtl in enumerate(mtl_list):

obj_list = [obj for se in mtl.connections()
if isinstance(se, nt.ShadingEngine)
for obj in se.connections()
if isinstance(obj, nt.Transform)]
if not obj_list:
continue

grp = pm.group(obj_list,n="EXPORT_#",w=1)
data = defaultdict(list)
for mesh in obj_list:
data[mesh.numTriangles()].append(mesh)
# NOTE 清空小于等于 1 的模型
obj_list = [data.pop(verts) for verts,m_list in data.items() if len(m_list) <= 1]

# TODO 获取每个模型的位置
for mesh_list in data.values():

try:

loc_list = []
for i,mesh in enumerate(mesh_list):
# NOTE 居中轴心
pm.parent(mesh,w=1)
pm.xform(mesh,cp=1)
# NOTE 命名为 Socket_序号 方便虚幻识别
loc = pm.spaceLocator(n="SOCKET_#")
pm.parentConstraint(mesh,loc,mo=0)
pm.scaleConstraint(mesh,loc,mo=0)
loc_list.append(loc)

m = mesh
m_name = m.shortName().replace("|","_")
m_name = m_name[1:] if m_name.startswith("_") else m_name
pm.parent(mesh,w=1)
pm.select(mesh)
# NOTE bake 轴心点
pm.mel.BakeCustomPivot()
mesh.t.set(0,0,0)
mesh.r.set(0,0,0)
path = os.path.join(export_dir,"%s.fbx" % m_name)
pm.mel.FBXExport(f=path,s=None)

# NOTE 创建一个三角面来导出 Locator
tri = pm.polyCreateFacet( ch=0,p=[(0.0, 0.0, 0.0), (0.10, 0.0, 0.0), (0.10, 0.10, 0.0)],n="LocContainer")[0]
pm.parent(loc_list,tri)
pm.select(tri)
pm.hyperShade( assign=mtl )
path = os.path.join(export_dir,"%s_loc.fbx" % m_name)
pm.mel.FBXExport(f=path,s=None)
except:
print("fail",mesh_list)
continue

if __name__ == "__main__":
main()

  上面的脚本用来输出一个材质的 Locator 效果。

alt

  接下来将输出的 LocContainer1 模型导入虚幻即可。
  导入的效果如下图

alt

  在虚幻引擎里面导入大量FBX,通过 ImportAll 按钮导入有时候会导致模型的明明和原本的 FBX 并不一致的问题。
  为此我又写了脚本来实现遍历目录批量逐个导入的功能。

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
# -*- coding: utf-8 -*-
"""
导入 FBX
手动导入大量 FBX 名称会有对不上
"""

from __future__ import division
from __future__ import print_function
from __future__ import absolute_import

__author__ = 'timmyliang'
__email__ = '820472580@qq.com'
__date__ = '2020-09-17 13:59:15'

import os
import unreal


asset_tool = unreal.AssetToolsHelpers.get_asset_tools()

def buildImportTask(filename='', destination_path=''):
options = unreal.FbxImportUI()
options.set_editor_property(
"mesh_type_to_import", unreal.FBXImportType.FBXIT_STATIC_MESH)

task = unreal.AssetImportTask()
task.set_editor_property("factory", unreal.FbxFactory())
name = os.path.basename(os.path.splitext(filename)[0])
# NOTE 设置 automated 为 True 不会弹窗
task.set_editor_property("automated", True)
task.set_editor_property("destination_name", name)
task.set_editor_property("destination_path", destination_path)
task.set_editor_property("filename", filename)
task.set_editor_property("replace_existing", True)
task.set_editor_property("save", False)
task.options = options
return task

def main():

path = r"D:\_minigame\_scene\test"
export_path = '/Game/Map'
for i,fbx in enumerate(os.listdir(path)):
if not fbx.endswith(".fbx"):
continue

task = buildImportTask(os.path.join(path,fbx),export_path)
asset_tool.import_asset_tasks([task])


if __name__ == "__main__":
main()

  成功导入之后,需要按照带有 locator 的 StaticMesh 记录的位置进行场景重排。

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
# -*- coding: utf-8 -*-
"""
https://answers.unrealengine.com/questions/75214/view.html
使用 locator 流程导入 模型 节省资源
"""

from __future__ import division
from __future__ import print_function
from __future__ import absolute_import

__author__ = 'timmyliang'
__email__ = '820472580@qq.com'
__date__ = '2020-09-17 10:13:14'

import os
import unreal

level_lib = unreal.EditorLevelLibrary()
util_lib = unreal.EditorUtilityLibrary()

def main():

for asset in util_lib.get_selected_assets():
name = asset.get_name()
if not isinstance(asset,unreal.StaticMesh) or name.endswith("_loc"):
continue
container_path = os.path.splitext(asset.get_path_name())[0]
container = unreal.load_asset("%s_loc" % container_path)
if not container:
print("失败路径 -> %s" % container_path)
continue
container = level_lib.spawn_actor_from_object(container,unreal.Vector(0.0, 0.0, 0.0))
r = unreal.AttachmentRule.SNAP_TO_TARGET
for socket in container.root_component.get_all_socket_names():
mesh = level_lib.spawn_actor_from_object(asset,unreal.Vector(0.0, 0.0, 0.0))
mesh.attach_to_actor(container,socket,r,r,r,False)

if __name__ == "__main__":
main()

  然而使用上面的方式 spawn 模型到场景里面,位置没有问题,就是旋转值会有偏差。
  但是处理到这里已经花费了我大量的时间了。

  原本打算在花点时间把旋转的问题也解决一下的,但是第二天开了会之后,所有的规划都被打乱了。
  起因是开会的前天晚上,我们把搭建好的初版模型给被别人看到了。
  别人一看就说,这不就是影子战术吗?
  这个回答如同闪电一样,让我们所有人都不好了,虽然并非不可以做移植,但是终究还是抄得太过明显了(:з」∠)
  所以第二天开会之后,讨论的结果是放弃掉 影子战术 的资源。
  毕竟我们做的是中国风的游戏,影子战术的模型太过 日本 风了,辨识度也有点高。
  因为这个问题,我还尝试过将 影子战术 的贴图转成马赛克 来混淆视听,最后经过讨论还是否决了这个提案。

  于是我们又需要找适合新的模型资源了,而且折腾了这么久我还是没有把 Maya 到 Unreal 的流程跑通,既然换资源,程序建议直接在 Unreal 里面搭建场景。
  我想了想还是觉得自己不要折腾了,所以也同意了程序的方案。(即便我把 Maya 的流程跑通了,其实并没有方便多少搭场景的操作,顶多是可以用 Asseembly Reference 来方便切换模型而已(:з」∠),这么一想感觉自己被 Maya 束缚了,虽然前面做了大量工作都要放弃有点可惜,但是固执己见只是拖慢进度而已)

推倒重建场景

  推倒重来之后,需要新的场景素材来搭建,而且 国庆临近,工期变得非常赶(:з」∠)
  而我们还没有想好到底是用我一开始找到的 low poly 素材还是找一些 偏影子战术 中国风的场景素材。
  经过一个早上折腾找资源,最后还是由我们的主策 星楠 拍板用 low poly 的素材。
  然后其他策划就帮忙在网上找些能用比较适合我们风格的素材。

Japnese_Temple
LowPoly_Asia

  最后是上面两个素材最符合我们的要求(现在的场景充满了上面两个素材的痕迹)
  确定了素材之后,我将之前的 Low poly 资源(那个原本是 Unity 的资源)分门别类地整合了一下,发给策划们单独搭建场景。
  最初我没有将角色模型给到他们,结果他们搭建的场景过大,还好后面及时补救了一下。
  于是场景构建的工作逐渐步入正轨。

Unreal Placer 工具

alt

  因为素材都是分门别类地放到引擎里面,策划找起来不太方便。
  所以我想搭建一个工具,方便策划来搭建场景,所以就加班加点做了个 Placer 搭建场景的 Unreal 工具。

alt

  为此我参考了 UnrealEnginePython 的插件,通过蓝图实现资源缩略图的获取,然后在 PySide 里面重建缩略图。

  策划双击面板的缩略图对应的资源就可以将模型生成到场景里面。
  我还打算把模型对齐的功能做上去,考虑到有点难,我还是先将自己的工作成果和 PM 同步了一下。
  PM 给我的回答是功能很鸡肋(:з」∠),这些功能并不是很重要,没有也照样可以搭。
  虽然很不愿意承认,但是说的是事实。

  所以后续我的工作回归到重头戏的 动作 上。

国庆期间

  Minigame 项目的场景还没有出来,我还是很焦虑的,虽然策划说只要一天就可以把堆量工作搞完,我还是不放心。
  尽管如此,国庆还是来了。
  今年国庆我很早就规划好要回老家,需要花三天时间。
  没想到出游的人实在是太多了,三天回家的时间有两天都在路上(:з」∠)

  赶回深圳之后还要抽空搬家,真是挺赶的。
  原本打算这三天把一个 Unreal 动画的教程给看完的,但是路途颠簸,加上自己太累了,还是没能完成任务。

角色动作叠加

  我们的游戏动作完全依靠 Advance Locomotion 框架实现的。
  框架上已经实现了 Overlay 系统,因此要叠加更多的动作,应该也是在 Overlay 的动画层上添加。
  这样可以确保角色下半身可以移动奔跑而不影响到动画的播放。

alt

  最后做完是上面的效果。
  叠加的方式其实可以抄 举火炬 之类的效果。

alt

  动画蓝图里面会根据当前 跑步 走路 攀爬 的装填然后去这个动作特定时间的动画曲线。
  这些动画曲线控制了注入 IK 系统等等的过渡。
  直接复制这些部分最后在动作输出的时候叠加上我们要播放的攻击动画即可。

alt

  攻击的时候上半身叠加攻击动画,这样角色就可以以奔跑只是进行攻击。
  虽然看着抄过来很简单,这个过程摸索花了我很多时间,特别是双手动画需要开启 IK 。
  最初不知道是相关的动画曲线会开启,摸索了很长时间。

  触发动画则需要通过一个 布尔 变量来实现, 动画蓝图的 Tick 里面有不断同步角色蓝图变量的操作。
  这里我依葫芦画瓢加多了个 攻击 变量,攻击的时候让变量变为 true 就会叠加攻击状态的动画,通过 delay 让变量变为 false 恢复角色状态。
  另外因为之前重定向了很多的动画,我通过 Blend Pose By Int 节点通过输入随机数来随机抓取一个攻击动画。
  发挥动作丰富的优势。

角色随机状态

  考虑到动作士兵的种类都比较多。
  如果加入随机状态的话,就可以组合成各种各样不同的士兵。

  于是我构建出新的数据结构,更好地随机角色的状态。

alt

  通过构建 OverLayTable 可以区分出左手和右手的攻击动画,并且获取动画的长度方便进行 Delay 结束。

alt

  设置 Enum 状态判断角色左右手, Both 则是双手武器,动画也会根据这个状态来进行随机。
  通过这个方式可以随机出大量不同状态的士兵,士兵的 SkeletalMesh 以及单手武器也都是通过蓝图随机添加上去的,增加关卡击杀的体验。

alt


  士兵的随机语句通过 EnemyWordTable 来获取。

alt

  根据关卡名配置,这样不同关卡下角色说的话也会有所不同。


alt

  角色的死亡动画也通过 Table 来随机获取。
  因为死亡动画有些许穿模到地上,所以加了 offset 数值来偏移角色位置,不过后来加入了 ragdoll 自由摆动,基本不穿模了。


  另外在 NPC 的一些细节上也进行了优化。
  比如 NPC 没有主角靠近的时候会随机做 吃东西 挠头 的动作。
  碰到 主角 之后就会直接望向主角做 交谈 的动作。

材质风动效果

  这些也是一些细节上的东西,不仔细观察其实根本发现不了。
  但是加上了之后就会有更真实的体验。
  风动材质我在 Japanese_Temple 里面的树叶材质上有。
  我将相关的材质节点拷贝出来,接入到其他的植物模型上,把细节拉满。

alt
alt

技能效果

  技能上我们主要做了 扔石头(吸引士兵注意) 和 撒粉(减少士兵视野) 的功能。


  扔石头需要实现石头飞到目标区域的效果。
  在 Youtube 上查了一圈,还是推荐使用 ProjectileMovement 来实现。
  然而 ProjectileMovement 一般用来做子弹的效果,是纯物理模拟,没有确定的终点坐标。
  最后在论坛上查到了一个有用的节点 链接
  SuggestProjectileVelocity Custom Arc 这个节点可以算出两个目标需要的速度。
  将速度接入到 ProjectileMovement 里面就可以实现完美的抛物线。

alt

  遗憾就是开启碰撞检测的话,石头会被中途的障碍物挡住,如果不开启碰撞检测有不知道石头什么时候到达了目标点位置(:з」∠)
  现在想了下,其实可以通过 tick 计算坐标是否很靠近目标点的坐标来实现触发的,不过已经太晚了。


  撒粉需要一些特效效果的支持。
  然而 Unreal 的特效我懂得很少,所以还是抄效果比较方便。
  于是又找了个特效素材包。

vfx-impacts

  撒粉其实很简单,就是在目标点区域将上面的打枪特效随机堆上去即可。

总结

  以上就是 Minigame 的全面复盘,有点流水账的感觉。
  Unreal 的蓝图无法用 git 进行二进制合并,结果合作开发会遇到很多冲突问题,非常难受。
  网上查了官方在很久以前做了个 蓝图 Merge 工具,然而已经很久没有维护了。

  Unreal 用蓝图做游戏,说实话自从去年校招匆匆学了个入门教程做了个小案例之后,就再也没有深入碰过了。
  这次 Minigame 我也学习到了很多东西,收获匪浅~

2020-10-16

  昨天 minigame 评审,虽然很努力去做,还是没能拿到奖项,有点可惜。
  不过也是情理之中,竞争对手都是神仙,甘拜下风~

  昨晚小组聚餐, PM 还是挺沮丧的,我们的主策划复盘了这次 Minigame 的问题。
  主要还是 评审的时间比较短, 我们需要在短时间内显示出我们玩法的创新点和爽点。
  然而我们还是有很多没有完善的地方,特不是作为动作游戏,动作上没有调优,缺少反馈。
  创新上也没有特别的亮点(虽然我们觉得手游上很少有这种潜行游戏,然而这的确不算创新)
  所以虽然可惜,不过这个过程还是有不少收获哒~