- 好友
- 12
- 在线时间
- 486 小时
- 最后登录
- 2024-12-18
子爵[版主]
- UID
- 2893127
- 第纳尔
- 14847
- 精华
- 0
- 互助
- 93
- 荣誉
- 21
- 贡献
- 325
- 魅力
- 1382
- 注册时间
- 2017-11-5
鲜花( 431) 鸡蛋( 0)
|
本帖最后由 vegetto 于 2023-1-6 16:45 编辑
你们有时是否有这样的苦恼,就是agent的很多时候除非是碰上ti on开头的那些trigger事件,要表达特定几个agent之间的复杂互动行为时,非要用循环来表达,一个try for agents 套着另一个try for agents 的循环操作,甚至不只双重,可能几重。
或者感觉遇到比较少的作者,因为大部分战争情况大家分组群体活动行为比较模糊不要太精细就像全战一样,除非一对一手术式精准干啥事,比如精准一对一射击到某人某部位,一对一产生对话和动作行为等等,特别是如果做一些特殊模式,比如说我做了暴力篮球足球网球台球的modhttps://bbs.mountblade.com.cn/thread-2069525-1-1.html这种需要单体个人竞技的,对每个人需要微操行为的,我人不多,但是每个人都有自己的分工,ai行为要受周边特定的单体个人影响,大家互相影响行为,导致就这么几个人还要写多重循环。这样代码就会冗长,整体格式也会向起伏的山脉一样,看着很膈应。
所以针对这种情况,我研究了一种方法,把agent对agent这种多重循环的代码格式简化为拆分成多个单体循环的格式。
首先为什么agent会出现这样的控制繁琐的代码格式,因为agent本身不具备特例编号,比如我从100个刷出来的人就点名要第3个人办点特殊的事情,还要自己先用slot给刷出来的人编号0,1,2,3。。。,然后各种troop id ,team是多少来筛选。从try for agents 来控制,无论你控制的对象是1个人还是几十上百人。所以要想破开这种多重循环,就需要一个可以不通过循环,直接抓取特定编号的中间媒介,来传导指令。
而这个媒介,这个信使就落到了scene prop 场景物头上。
为什么呢?
我们看看这个op:(scene_prop_get_instance, <destination>, <scene_prop_id>, <instance_no>),
<scene_prop_id>就是spr_开头的sceneprop的各种场景物种类id,<destination>是对其中同类场景物的一个特例的id进行获取,而这个特例的编号就是<instance_no>,
<instance_no>这个值是系统刷出来自己生成的,就比如你刷100个spr_aaa,那么你第30个刷的spr_aaa的<instance_no>编号就是29,第一个刷的编号就是0。
所以说我们在1.161ms系统之前没有出现try for props这个op前,要循环场景物,就会采用如下的代码操作格式:
----------------------------------------
(scene_prop_get_num_instances, ":var_0", "spr_gun"),
(try_for_range, ":var_11", 0, ":var_0"),
(scene_prop_get_instance, ":var_12", "spr_gun", ":var_11"),
(scene_prop_set_visibility, ":var_12", 0),
(try_end),
---------------------------------------------------
意思就是循环编号为0到编号数为gun这个场景物总数量减1的编号范围,这些spr gun类型的所有场景物都影身。
这种格式在以前处理同一种数量很多的场景物时很常见。
所以这时候想,如果每个agent刷出来的时候随机给他刷一个没有形态(如果有特殊作用也可以有模型形态默认隐藏,有条件拿出来作用)的场景物模型,然后给agent用slot按次序从0依次加1进行编号。
然后让agent的slot储存的编号与场景物的<instance_no>相等或成一定线性计算规律时,那与agent一一对应的场景物便可以利用自己的运动和位置获取特性以及自身的prop slot,来对agent受到和发出的部分行为进行反馈。
比如我举个例子
(ti_on_agent_spawn, 0.000000, 0.000000,
[
],
[
(store_trigger_param_1, ":var_0"),
(agent_set_slot, ":var_0", 200, "$agentpos"),
(agent_get_position, pos1, ":var_0"),
(set_spawn_position, pos1),
(spawn_scene_prop, "spr_agentpos"),
(scene_prop_set_visibility, reg0, 0),
(scene_prop_set_slot, reg0, 200, 11),
(val_add, "$agentpos", 1),
]),
以上我把spr_agentpos在agent刷出来时,序号对应编号的过程先写出来。
此时我要求agentslot记录的编号为3的人对编号为30的人要在250距离范围内时,编号3的人要执行anim_a的动作,编号30的人要执行anim_b的动作,trigger条件先待定
那这个agent伤害事件的触发器主体一般情况可以这么写:
(try_for_agents, ":var_0"),
(agent_is_alive, ":var_0"),
(agent_is_human, ":var_0"),
(agent_get_slot, ":var_1", ":var_0", 200),
(eq, ":var_1", 3),
(try_for_agents, ":var_2"),
(agent_is_alive, ":var_2"),
(agent_is_human, ":var_2"),
(agent_get_slot, ":var_1", ":var_2", 200),
(eq, ":var_1", 30),
(agent_get_position, pos1, ":var_0"),
(agent_get_position, pos2, ":var_2"),
(get_distance_between_positions, ":var_3", pos1, pos2),
(neg|ge, ":var_3", 250),
(agent_set_animation, ":var_0", "anim_a"),
(agent_set_animation, ":var_2", "anim_b"),
(try_end),
(try_end),
那这样这个触发器就是一个双循环。
如果结合spr_agentpos来作为媒介进行处理呢,我们可以这么写:
触发器1-按0.000000, 0.000000, 0.000000,条件触发
(try_for_agents, ":var_0"),
(agent_is_alive, ":var_0"),
(agent_is_human, ":var_0"),
(agent_get_slot, ":var_1", ":var_0", 200),
(scene_prop_get_instance, ":var_2", "spr_agentpos", ":var_1"),
(agent_get_position, pos1, ":var_0"),
(prop_instance_set_position, ":var_2", pos1),
(try_end),
触发器2-trigger条件待定
(scene_prop_get_instance, ":var_0", "spr_agentpos", 3),
(scene_prop_get_instance, ":var_1", "spr_agentpos", 30),
(prop_instance_get_position, pos1, ":var_0"),
(prop_instance_get_position, pos2, ":var_1"),
(get_distance_between_positions, ":var_2", pos1, pos2),
(neg|ge, ":var_2", 250),
(try_for_agents, ":var_3"),
(agent_is_alive, ":var_3"),
(agent_is_human, ":var_3"),
(agent_get_slot, ":var_4", ":var_3", 200),
(try_begin),
(eq, ":var_4", 3),
(agent_set_animation, ":var_3", "anim_a"),
(else_try),
(eq, ":var_4", 30),
(agent_set_animation, ":var_3", "anim_b"),
(try_end),
(try_end),
看到没有,这样操作后原本要写多循环的事件,因为spr agentpos的场景物充当了中间媒介,传递了自己对应agent的位置信息,所以将多循环转换成了单循环事件。这个例子可能看不出有什么方便,但是如果两个agent互动的事件种类多了,并且不只是两两发生关系,产生多循环嵌套,用这种操作就极有可能把多循环事件拆成我上面的一个使得场景物和对应编号产生关联比如位置伴随的联系的agent循环,另一个把事件的主动方和被动方变成一个try for agents中以else连接的同级并列关系的agent循环。
当然这个做法并不适用于任何情况,比如需要执行的事件本身需要主动施加方和被动接受方两个人同时作为一个OP的参数条件,比如 agent_deliver_damage_to_agent这种传递伤害的op,主动伤害事件就避不开双循环。
最佳的使用场合就是一个agent的行为对另一个agent产生了因果关系的影响但是不需要双方配合产生的事件,多用于这种多方agent的位置关系运动关系等行为关系的判断。
综上:https://bbs.mountblade.com.cn/thread-2094114-1-1.html我在我的技术总目录贴里面各项都谈到了场景物对于换皮和辅助其他系统方面有很多作用应用,因为场景物是所有系统可操作op种类最丰富的,控制最灵活的,抓住场景物的控制手段,可以有助于其他系统更上一层楼。很多人不怎么用到场景物方面的代码,所以这几天集中给你们洗洗脑。
|
评分
-
查看全部评分
|