- 好友
- 12
- 在线时间
- 486 小时
- 最后登录
- 2024-12-18
子爵[版主]
- UID
- 2893127
- 第纳尔
- 14847
- 精华
- 0
- 互助
- 93
- 荣誉
- 21
- 贡献
- 325
- 魅力
- 1382
- 注册时间
- 2017-11-5
鲜花( 431) 鸡蛋( 0)
|
本帖最后由 vegetto 于 2023-5-5 10:32 编辑
我们现在很多mod制作者已经也开始修改非战团风格和机制的玩家血条和能量条,虽然有一定五花八门的样式,但是基本操作还是把原本的战团玩家血条ui通过game_variables挪到屏幕外、或者新的大ui遮挡、或者战团玩家血条ui透明通道涂黑等手段隐藏后,然后利用带有槽子的底图背景加上长方形线条式的血条能量条ui来组合,而血条能量条的增减则通过overlay的set scale来放缩横向大小来实现 。
但是如果要做到有些游戏一样的血条能量条风格比如:像齿轮一样的圆形能量条(格子变化呈旋转方式如守望先锋)、整个血条和槽子是平行四边形不能像长方形放缩长边与槽子契合并且还会影响分辨率的、血条呈现英雄联盟的格子型甚至格子是平行四边形斜着的(比如下图我的骑砍龙珠mod)、血条底图槽子背景和血条颜色流感波动甚至死亡后血槽会先进行一段荧光流动的渐变效果比如拳皇这些格斗游戏的血条(比如下图我的骑砍仿黑神话悟空mod)、rpg/moba游戏那种血条旁边带着人物动态表情的大头像、地下城那种血瓶沙漏式风格的血条能量条等等,
那么用传统放缩的方法便不再适用。但是这并不是不可实现的,首先阅读我的【贴图变换模拟动图系统在骑砍里的综合应用】https://bbs.mountblade.com.cn/thread-2098384-1-1.html帖子,所以这个需要采用动图模拟即序列帧图模拟的方式来实现。
为了 让大家更好理解这个东西的实现应该具备哪些环节和操作,以我这个骑砍仿黑神话悟空的拳皇式血条做一个示例(我的mod已经不打算在国内分享了,所以现在你们没下的想研究只能去外网):
1.模型贴图等素材处理环节:
首先找到拳皇血条的绿幕素材库(喜欢看鬼畜视频吗,喜欢看别人做特效视频剪辑吗,就是用绿幕素材,绿幕素材相当于是类似可以实现透明通道将我们需要的素材从图像视频上抠出来然后叠放到其他视频上我们需要加效果的一段上),如果找不到,自己打一遍拳皇,控制下每次伤害均匀,录下视频自己扣。
为了方便不用在代码环节调整ui的overlay坐标,并且既然用了序列图,这个血条不需要平移和放缩,所以图像可以不对齐openbrf的O点,直接按照屏幕范围大小来做mesh,即我上面那个动图的左下角相对位置就是血条mesh在openbrf的坐标系原点O。
然后血条ui的mesh及序列图一套在openbrf里形式如下图:
其实准确来做,应该把血条分为三部分抠图拼接作为三个mesh overlay然后在代码环节按条件进行组合,一个是左血条一般给玩家用,一个是右血条一般给对手用,中间那个无限大其实就是格斗游戏的计时用的如果是打傀儡练手没有时间限制才显示数据为无限大。
但是从图上,你们应该可以看出来,我为了图省事,直接把我方和对手的血条中只有我方均匀损血至死亡的环节抠出了序列图(贴图导入brf后新建材质,材质贴图一一对应且名称均命名为1000001-1000040的数字名称,共40张贴图,从连续绿幕素材上扣出的贴图越多在游戏里控制表现越精细),然后我后面的做法就是把完整呈现这些序列图的这个mesh从中间切开,然后另一半镜像,再两个mesh拼起来,这样就直接得到了两边血条的完整损血序列图像,然后中间计时区域因为镜像拼接,无限大的图案变成了蝴蝶形,因为我不讲究,所以当中间那块没用纯属花纹,大不了下方另起一行text overlay表示计时得分。
最后请注意按我开头说的三种方法中选改透明贴图或game_variables把战团自己的血条马头人头ui隐藏掉。
2.代码程序控制环节:
(1)首先module_meshes.PY注册两个mesh,就是上面图中镜像拼接关系的左右拳皇血条。
("kofhudbarl", 0, "kofhudbarl", 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 1.000000, 1.000000),
("kofhudbarr", 0, "kofhudbarr", 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 1.000000, 1.000000),
(2)其次module_strings.PY注册一个string来记录数字式贴图材质名称(不理解的看我开头的动图理论总章贴)
("mjb", "{reg21}"),
(3)然后module_presentations.PY中运行如下(为了简洁点,我只写关于上面那两个mesh的控制情况,其他ui控制不列出来):
("battle", prsntf_manual_end_only|prsntf_read_only, 0, [
(ti_on_presentation_load, [
(set_fixed_point_multiplier, 1000),
(create_mesh_overlay, "$kofhudbar", "mesh_kofhudbarl"),
(position_set_x, pos1, 0),
(position_set_y, pos1, 20),
(overlay_set_position, "$kofhudbar", pos1),
(assign, reg21, 1000001),
(str_store_string, s21, "str_mjb"),
(956, "$kofhudbar", 21),
(create_mesh_overlay, "$kofhudbarem", "mesh_kofhudbarr"),
(position_set_x, pos1, 0),
(position_set_y, pos1, 20),
(overlay_set_position, "$kofhudbarem", pos1),
(assign, reg21, 1000001),
(str_store_string, s21, "str_mjb"),
(956, "$kofhudbarem", 21),
(presentation_set_duration, 999999),
]),
----------------------------------------------------------------------------
(ti_on_presentation_run, [
(store_trigger_param_1, ":var_0"),
(set_fixed_point_multiplier, 1000),
(get_player_agent_no, ":var_1"),
(store_agent_hit_points, ":var_2", ":var_1", 0), #参数0表示相对血量:var_2按照百分比形式表示即正常人是0-100取值,但是不正常情况可以溢出
(try_begin),
(store_mul, "$vhp", ":var_2", 10), #为了扩大控制区间,血量乘10来使得相对血量按千分比。(因为里面有可替换风格的血条ui,所以为了其他服务的,显得这一步看起来多余)
(val_max, "$vhp", 10), #这一步也是为了非本次介绍的其他可替换选择样式的放缩式血条系统服务,注意血条ui的overlay缩小set scale不要到0,一旦缩没了,就不能再放大回来了,所以要设下限,这是题外话
(try_end),
(try_begin),
(store_sub, ":var_3", 1000, "$vhp"), #获取按千分比表示的相对血条当前的已扣血部分的千分比量是多少
(store_div, ":var_4", ":var_3", 34), #得到需要贴图对应材质跃变的帧数,34是因为我的序列图名称是1000001-1000040的数字名称,共40张贴图,但是只有1000001-1000034是打击扣血状态,1000035-1000040是死亡后血槽会有一种流动的特效,具体看我上面黑神话mod的动图最后几秒。
(try_begin),
(troop_slot_eq, "trp_player", 311, 0), #trpplayer的troop slot311号表示是否执行死亡时的序列图序列即我上面说的1000035-1000040贴图材质
(store_add, ":var_5", ":var_4", 1000001), #得到当前贴图对应材质的名称
(assign, reg21, ":var_5"), #将材质名称对应的数字存储reg21
(str_store_string, s21, "str_mjb"), #将材质名称通过str_mjb的reg21来储存到s21
(956, "$kofhudbar", 21), #956号op就是可以将overlay性质的mesh的贴图对应材质进行实时变换的核心操作,具体用法引申再看看我开头的理论总贴
(try_begin),
(eq, ":var_4", 29), #29的由来就是29x34是最接近1000的整数,表示29取值时,贴图材质已经变换到濒临死亡的临界图像1000034了
(troop_set_slot, "trp_player", 311, 1), #slot311号表示为1时,人物濒临死亡或已经死亡,所以我这个功能在进行下一步死亡血条变化时是考虑濒临死亡还能活动的状态的
(try_end),
(else_try),
(troop_slot_ge, "trp_player", 311, 1), #进行濒临死亡或致死一击时的血条动态变化状态材质在1000035-1000040名称变化 ,类比上面的写法注释理解,
(troop_get_slot, ":var_6", "trp_player", 311),
(store_add, ":var_7", ":var_6", 1000034),
(assign, reg21, ":var_7"),
(str_store_string, s21, "str_mjb"),
(956, "$kofhudbar", 21),
(try_end),
(try_end),
(try_begin), #上面是玩家的左侧血条变化,下面是ai敌人的右侧血条变化,基本逻辑是你攻击新的敌人时,该敌人被标记,血条的记录会记录你新攻击敌人的血量变化状态,当再次攻击新的敌人就转移标记,也就是场上只有一个单位被特别对待标记血量,因为我这个用例不是拳皇1v1下,还是1v多。
(troop_slot_ge, "trp_player", 333, 1),
(troop_get_slot, ":var_8", "trp_player", 333), #slot333号相当于玩家的slot311号,也是为了记录敌人的被致死一击或濒临死亡的状态,为什么还是用trp player的slot,因为我的设定死亡时的1000035-1000040贴图材质变化必须执行完毕才能切换其他被玩家攻击的人的血量情况,所以此环节不需要区分多单位。
(store_add, ":var_9", ":var_8", 1000034),
(assign, reg21, ":var_9"),
(str_store_string, s21, "str_mjb"),
(956, "$kofhudbarem", 21),
(else_try),
(try_for_agents, ":var_10"), #以下是判断被玩家攻击标记的敌人
(agent_is_human, ":var_10"),
(agent_is_alive, ":var_10"),
(agent_get_troop_id, ":var_11", ":var_10"),
(agent_slot_eq, ":var_1", 442, ":var_11"), #这个在ti on agent hit的打击trigger里,标记被特殊照顾血条状态的敌人的troop id
(agent_slot_eq, ":var_10", 443, 1), #表示agent被玩家攻击后的标记状态,同一个场景只允许一个单位此agent 443号slot为1
(store_agent_hit_points, ":var_12", ":var_10", 0), #下面的模式类比我玩家的写法,就是在致死前的正常损血状态对贴图材质控制变化的影响。
(store_mul, ":var_13", ":var_12", 10),
(val_max, ":var_13", 10),
(store_sub, ":var_14", 1000, ":var_13"),
(store_div, ":var_15", ":var_14", 34),
(try_begin),
(troop_slot_eq, "trp_player", 333, 0),
(store_add, ":var_16", ":var_15", 1000001),
(assign, reg21, ":var_16"),
(str_store_string, s21, "str_mjb"),
(956, "$kofhudbarem", 21),
(try_begin),
(eq, ":var_15", 29),
(troop_set_slot, "trp_player", 333, 1),
(try_end),
(try_end),
(try_end),
(try_end),
]),
------------------------------------------------------------------
(4)然后module_mission_templates.PY中运行如下
i)在打击事件trigger中判断agent被玩家攻击后被标记的状态
(ti_on_agent_hit, 0.000000, 0.000000,
[
],
[
(store_trigger_param_1, ":var_0"),
(store_trigger_param_2, ":var_1"),
(store_trigger_param_3, ":var_2"),
(agent_get_troop_id, ":var_3", ":var_0"),
(agent_get_troop_id, ":var_4", ":var_1"),
(try_begin),
(eq, ":var_4", "trp_player"),
(neg|eq, ":var_3", "trp_player"),
(agent_set_slot, ":var_1", 442, ":var_3"), #标记troop id
(agent_set_slot, ":var_0", 443, 1), #标记被关照拳皇血条状态的agent的状态
(try_for_agents, ":var_5"),
(agent_is_human, ":var_5"),
(agent_is_alive, ":var_5"),
(neg|eq, ":var_5", ":var_0"),
(neg|eq, ":var_5", ":var_1"),
(agent_set_slot, ":var_5", 443, 0), #强制关闭非本次被玩家攻击的其他agent这种关照拳皇血条的状态
(try_end),
(try_end),
]),
------------------------------------------------------
ii)在死亡事件trigger中判断记录拳皇血条状态的玩家和ai死亡时的状态,和presentation中eq29的濒临死亡判断一起触发1000035-1000040的贴图材质变化区间状态判定。
(ti_on_agent_killed_or_wounded, 0.000000, 0.000000,
[
],
[
(store_trigger_param_1, ":var_0"),
(store_trigger_param_2, ":var_1"),
(agent_get_troop_id, ":var_2", ":var_0"),
(agent_get_troop_id, ":var_3", ":var_1"),
(try_begin),
(eq, ":var_2", "trp_player"),
(troop_set_slot, "trp_player", 311, 1), #slot311为1开始判断玩家的致死或濒临死亡状态,然后触发上面presentation的1000035-1000040的mesh贴图材质变化
(else_try),
(neg|eq, ":var_2", "trp_player"),
(eq, ":var_3", "trp_player"),
(troop_set_slot, "trp_player", 333, 1), #slot333为1开始判断记录血条的ai致死或濒临死亡状态,然后触发上面presentation的1000035-1000040的mesh贴图材质变化
(try_end),
]),
------------------------------------------------------------------------------------------
iii)以下是一种模糊计时法,因为正常损血状态的血条mesh贴图材质变化是靠血量的增减来调整序号贴图的,而致死和濒死时的血条流光变化需要靠时间模拟控制状态延续。
(0.000000, 0.000000, 0.000000,
[
],
[
(troop_get_slot, ":var_1", "trp_player", 312), #trp312号slot表示0-20区间取值循环变化,因为触发器基础间隔和游戏frame运行帧数有关,所以60帧游戏这样处理0-20的循环大致有肉眼可识别的时间间隔
(try_begin),
(is_between, ":var_1", 0, 20),
(store_add, ":var_2", ":var_1", 1),
(troop_set_slot, "trp_player", 312, ":var_2"),
(else_try),
(ge, ":var_1", 20),
(troop_set_slot, "trp_player", 312, 0),
(try_end),
(troop_get_slot, ":var_3", "trp_player", 311), #控制玩家致死或濒临死亡状态启动后,slot311号在1-6区间值+1变化,最后归0重置恢复满血条(配合复活功能),1-6区间取值正是对应了1000035-1000040贴图之间有6张贴图的关系,一一对应
(try_begin),
(is_between, ":var_3", 1, 6),
(this_or_next|troop_slot_eq, "trp_player", 312, 0), #上面的slot312号在0-20之间循环,所以当其值为0和10的时候,表示利用slot312号产生的一半时间来作为slot311号玩家致死或濒临死亡状态每次贴图序列帧数+1的条件
(troop_slot_eq, "trp_player", 312, 10),
(store_add, ":var_4", ":var_3", 1),
(troop_set_slot, "trp_player", 311, ":var_4"),
(else_try),
(ge, ":var_3", 6),
(troop_set_slot, "trp_player", 311, 0),
(try_end),
(troop_get_slot, ":var_5", "trp_player", 333), #控制ai致死或濒临死亡状态启动后,slot333号在1-6区间值+1变化,最后归0重置恢复满血条(配合复活功能),1-6区间取值正是对应了1000035-1000040贴图之间有6张贴图的关系,一一对应
(try_begin),
(is_between, ":var_5", 1, 6),
(this_or_next|troop_slot_eq, "trp_player", 312, 0), #上面的slot312号在0-20之间循环,所以当其值为0和10的时候,表示利用slot312号产生的一半时间来作为slot333号玩家致死或濒临死亡状态每次贴图序列帧数+1的条件
(troop_slot_eq, "trp_player", 312, 10),
(store_add, ":var_6", ":var_5", 1),
(troop_set_slot, "trp_player", 333, ":var_6"),
(else_try),
(ge, ":var_5", 6),
(troop_set_slot, "trp_player", 333, 0),
(try_end),
]),
----------------------------------------------------------------over------------------------------------------------------------------------------
这种功能的难点在于对序列贴图的批量处理、分解、格式转换、命名和抠图,所以用这个案例告诉大家,模型手段和代码手段是怎么深度结合创造奇迹的,当我们的素材真正的被代码控制的灵动飘逸,而不是用来点缀装饰的死物和一成不变的抄袭,才是战团真正的续命之道。
|
评分
-
查看全部评分
|