骑马与砍杀中文站论坛

 找回密码
 注册(Register!)

QQ登录

只需一步,快速开始

搜索
购买CDKEY 衣谷三国
查看: 1919|回复: 3

[经验与教程] 关于骑砍战团的战场内行为控制系统的一些研究和坑

[复制链接]

1

主题

5

回帖

7

积分

平民

Rank: 1

UID
3657494
第纳尔
17
精华
0
互助
1
荣誉
0
贡献
0
魅力
0
注册时间
2024-5-22
鲜花(5) 鸡蛋(0)
发表于 2025-6-14 23:49:54 | 显示全部楼层 |阅读模式
本帖最后由 WKSPT 于 2025-6-15 18:40 编辑

最近在搞战场AI优化,发现站内似乎没什么系统性讲解战场内AI控制的帖子,给大伙分享一下最近的一些实践经验和研究


1.骑砍代码里面控制移动、控制切换武器和控制攻击动作的AI基本上是分开的,不会互相影响,所以你可以只修改三者其一。
2.“agent_force_rethink”是唯一的例外,它的AI重置效果同时作用于控制移动和控制攻击动作的AI,但完全不影响控制切换武器的AI。
3.“agent_set_animation”可以让单位执行特定动作,但只有动作动画,没有对应的效果,如果要控制单位攻击或者防御,要使用“agent_set_attack_action”“agent_set_defend_action”,武器切换同理,必须使用“agent_set_wielded_item”

接下来详解各个具体代码的效果

首先是移动控制,主要有两个OP:“agent_set_scripted_destination”“agent_clear_scripted_mode”,前者的作用是给与agent一个移动的目标点,单位会自动寻找路径前往这个点。需要注意的是,如果同时设定了多个目标点,agent一定会先到达之前设定的目标点,然后才会继续前往新的目标点。如果想要让agent直接前往新设定的目标点,需要使用“agent_force_rethink”来强制刷新AI状态。
如果一个单位被设定过目标点,即使到达目标点之后你不去管他了,他也会继续呆在你设定的目标点上面不动。如果想恢复游戏自带的AI,需要使用“agent_clear_scripted_mode”取消先前设定的目标点。
由于某些游戏自带的AI判定是单次的,比如战斗胜利后欢呼的动作,只会在战斗胜利的瞬间给出一个“开始播放欢呼动作”的命令。这时候如果agent的AI还没有恢复到默认,就不会受到游戏自带的AI发出的“开始播放欢呼动作”命令影响。这种情况下最好先取消先前设定的目标点,然后再加上一个“agent_force_rethink”,让AI重新检测一下。

然后是武器切换,涉及到的OP只有一个:“agent_set_wielded_item”,但这部分的坑是最恶心人也最难解决的
第一个坑是,这个OP的功能根据切换目标的不同是不一样的。如果你要切换的目标物品是武器类型,那么即使高频重复发出同一个指令,AI也会正确执行动作。如果发出的动作和正在进行的动作完全相同,前一个动作不会被后一个动作打断,这部分很人性化。但如果你要切换的目标物品是盾牌类型,就绝对不能高频重复同一个指令。因为这个OP重复装备一个盾牌的时候,它的功能就会变成取消装备盾牌,也就是把盾牌放回背后。高频触发同一个指令就会导致重复持盾、重复收盾的循环,表现为不断抽搐。
第二个坑是,这个OP的功能对原版游戏AI的覆盖是不完全持续的。正常情况下应该是设定装备某个武器后就一直装备这个武器,但ms没有提供类似于“agent_clear_scripted_mode”的手动取消操作。在实际应用中,AI只要更改面向的敌方目标,就会自动重置武器切换AI(顺带一提,回到原版武器切换AI的方式似乎不止这一种)。那么重写目标选取机制,在更改面向目标的瞬间再发出一次“agent_set_wielded_item”指令行不行呢?我的测试表明,如果你这样做,agent就会开始疯狂抽搐,一帧抽搐一次的那种。所以这个OP用来切换不同的武器的实际使用价值被大大限制了,只要原版有对应的切换机制,就只能通过“agent_unequip_item”强行拿掉你不希望AI自动换上的武器来控制武器切换。而由于空手也被原版游戏的AI视作一种近战武器,所以理论上不存在任何办法确保AI在近距离时仍然使用远程武器(除非那个远程武器在代码上属于近战类型,比如赛瑞米林的麻醉枪)。虽然本来就应该近战的时候掏出近战武器,但由于这个BUG的存在,没法具体调整掏近战武器的距离。而且通过“agent_unequip_item”移除的武器不会显示在单位的背上或者腰间,兵种在视觉分辨上可能出现问题。
第三个坑还是盾牌切换方面。这个涉及骑砍的盾牌底层机制,当你从持盾单手武器切换到双手武器(或者随便什么不能持盾的武器)的时候,盾牌虽然显示是背在身后了,但当你重新掏出单手武器,盾牌就会自动被连带着拿出来。这说明即使在使用双手武器时,盾牌的装备状态仍然会被保留。比较蛋疼的一点是,虽然盾牌的装备状态保留了,但只要agent还拿着双手武器,使用“agent_set_wielded_item”试图改变盾牌装备状态就没有任何效果。也就是说,只有当agent真正拿出盾牌拿在手里的时候,才能收回盾牌或者拿出盾牌。

最后是攻击动作控制,涉及的OP是“agent_get_attack_action”“agent_set_attack_action”,需要注意的是,这两个OP看起来很像,但它们对应的输入输出完全是两个系统
先说“agent_get_attack_action”的。根据实验,完全没有攻击动作会被记录为0,远程武器的瞄准和近战武器的抬手过程会被记录为1,近战武器的挥舞过程在击中敌人前会被记录为2,击中敌人造成伤害后会被记录为3,如果攻击被格挡会被记录为4,攻击的后摇阶段会被记录为6,而如果抬手到一半收手了(也就是按住左键的时候再按右键的效果)就会被记录为7,需要装填弹药的远程武器如果正在装填弹药则记录为6。这个OP比较反直觉的是,远程武器射击结束后的后摇会直接被记录为0,而且抬手动作只要开始就会被记录为1。至于具体什么时候完成抬手没法判断,只能自己通过熟练度武器速度之类的已知条件自己去算。
再说“agent_set_attack_action”的。这个OP有两个参数,第一个参数为0、1、2、3时表示挥砍的方向(似乎对远程武器都是一个效果),参数为-2时表示取消命令。第二个参数是控制抬手准备完成后是否攻击的,0表示抬手完成后直接攻击,1表示抬手完成后保持抬手状态。第二个参数的两个状态区别很大,当状态为“抬手完成后直接攻击”时,有时候完成一次攻击后就会回归正常,有时候会一直持续攻击,这个我还没搞明白。而当状态为“抬手完成后保持抬手状态”时,这个抬手状态会一直持续下去。无论第一个参数是什么,只要状态持续了,即使切换武器也不会变回原版的AI,需要使用(agent_set_attack_action, ":agent_no", -2, 0),或者(agent_set_attack_action, ":agent_no", -2, 1),来进行取消。如果当前状态是“抬手完成后保持抬手”,这两者的效果似乎是相同的。但由于我没搞明白怎么主动让“抬手完成后直接攻击”的状态持续,没法测试对这种情况的效果是否相同,就不下定论了。
另外,这个取消攻击的效果不能取消目前正在进行的攻击动作,但如果高频触发,却可以阻止agent进行新的攻击。猜测这个OP只能取消抬手刚开始那几帧的攻击。“agent_force_rethink”也会取消设定的攻击命令,需要注意移动控制AI和攻击控制AI互相干扰的问题。(但似乎高频触发“agent_force_rethink”不能阻止agent进行新的攻击,这一点尚未经过验证

除此之外还有一个“agent_set_defend_action”,控制防御动作的。我找到的注释没有说清楚第三个参数的实际含义,经过测试是防御动作持续时间,以毫秒为单位。另外这个OP能取消正在进行的攻击抬手,可以理解为效果等于玩家的右键。

鲜花鸡蛋

ggfgfgf  在2025-6-22 11:08  送朵鲜花  并说:我非常同意你的观点,送朵鲜花鼓励一下
快乐风猫  在2025-6-16 15:39  送朵鲜花  并说:我非常同意你的观点,送朵鲜花鼓励一下
偃靖  在2025-6-16 08:48  送朵鲜花  并说:我非常同意你的观点,送朵鲜花鼓励一下
lazyworker  在2025-6-16 05:06  送朵鲜花  并说:我非常同意你的观点,送朵鲜花鼓励一下

1

主题

5

回帖

7

积分

平民

Rank: 1

UID
3657494
第纳尔
17
精华
0
互助
1
荣誉
0
贡献
0
魅力
0
注册时间
2024-5-22
鲜花(5) 鸡蛋(0)
 楼主| 发表于 2025-6-15 00:14:59 | 显示全部楼层
本帖最后由 WKSPT 于 2025-6-15 00:29 编辑

顺带分享一下我做试验的代码,加在战场触发器里就可以用了,我用了wse2所以可能报错,删掉对应代码就行了,兵种ID和物品ID需要你自己填
  1. battle_experiment = (
  2.                 0, 0, 0,
  3.                 [],
  4.                 [
  5.                         (try_begin),
  6.                                 (key_clicked, key_h),
  7.                                 (mission_get_time_speed,":cur_time_speed"), # 更改战场时间流速 h加快,j减慢
  8.                                 (val_mul, ":cur_time_speed", 2),
  9.                                 (mission_set_time_speed,":cur_time_speed"),
  10.                         (else_try),
  11.                                 (key_clicked, key_j),
  12.                                 (mission_get_time_speed,":cur_time_speed"),
  13.                                 (val_div, ":cur_time_speed", 2),
  14.                                 (mission_set_time_speed,":cur_time_speed"),
  15.                         (try_end),
  16.                        
  17.                         (try_begin),
  18.                                 (key_clicked, key_n),
  19.                                 (team_get_hold_fire_order, reg1, 0, 0),
  20.                                 (team_get_movement_order, reg2, 0, 0),
  21.                                 (team_get_riding_order, reg3, 0, 0),
  22.                                 (team_get_weapon_usage_order, reg4, 0, 0),
  23.                                 (display_message, "@hold_fire_order:{reg1},movement_order:{reg2}"),
  24.                                 (display_message, "@riding_order:{reg3},weapon_usage_order:{reg4}"),
  25.                         (try_end),

  26.                         (try_begin),
  27.                                 (key_clicked, key_numpad_0), # 小键盘键 0,agent_set_defend_action
  28.                                 (try_for_agents, ":agent_no"),
  29.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  30.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  31.                                        
  32.                                         (agent_set_defend_action, ":agent_no", 3, 1),
  33.                                 (try_end),
  34.                         (else_try),
  35.                                 (key_clicked, key_numpad_1), # 小键盘键 1,agent_set_attack_action 持续攻击
  36.                                 (try_for_agents, ":agent_no"),
  37.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  38.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  39.                                        
  40.                                         (agent_set_attack_action, ":agent_no", 3, 0),
  41.                                 (try_end),
  42.                         (else_try),
  43.                                 (key_clicked, key_numpad_2), # 小键盘键 2,agent_set_attack_action 仅抬手
  44.                                 (try_for_agents, ":agent_no"),
  45.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  46.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  47.                                        
  48.                                         (agent_set_attack_action, ":agent_no", 3, 1),
  49.                                 (try_end),
  50.                         (else_try),
  51.                                 (key_is_down, key_numpad_4), # 小键盘键 4,agent_set_attack_action 取消
  52.                                 (try_for_agents, ":agent_no"),
  53.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  54.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  55.                                        
  56.                                         (agent_set_attack_action, ":agent_no", -2, 0),
  57.                                 (try_end),
  58.                         (else_try),
  59.                                 (key_clicked, key_numpad_5), # 小键盘键 5,agent_set_attack_action 取消
  60.                                 (try_for_agents, ":agent_no"),
  61.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  62.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  63.                                        
  64.                                         (agent_set_attack_action, ":agent_no", -2, 1),
  65.                                 (try_end),
  66.                         (else_try),
  67.                                 (key_clicked, key_numpad_7), # 小键盘键 7,agent_set_wielded_item 拿出武器 1
  68.                                 (try_for_agents, ":agent_no"),
  69.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  70.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  71.                                        
  72.                                         (agent_set_wielded_item, ":agent_no", "要拿出的武器1的ID"),
  73.                                 (try_end),
  74.                         (else_try),
  75.                                 (key_clicked, key_numpad_8), # 小键盘键 8,agent_set_wielded_item 拿出武器 2
  76.                                 (try_for_agents, ":agent_no"),
  77.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  78.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  79.                                        
  80.                                         (agent_set_wielded_item, ":agent_no", "要拿出的武器2的ID"),
  81.                                 (try_end),
  82.                         (else_try),
  83.                                 (key_clicked, key_numpad_9), # 小键盘键 9,agent_set_wielded_item 拿出或收回盾牌
  84.                                 (try_for_agents, ":agent_no"),
  85.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  86.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  87.                                        
  88.                                         (agent_set_wielded_item, ":agent_no", "要拿出的盾牌的ID"),
  89.                                 (try_end),
  90.                         (else_try),
  91.                                 (key_clicked, key_numpad_plus), # 小键盘 加号键,agent_set_wielded_item 收回一切武器装备
  92.                                 (try_for_agents, ":agent_no"),
  93.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  94.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  95.                                        
  96.                                         (agent_set_wielded_item, ":agent_no", -1),
  97.                                 (try_end),
  98.                         (else_try),
  99.                                 (key_clicked, key_numpad_3), # 小键盘键 3,agent_clear_scripted_mode
  100.                                 (try_for_agents, ":agent_no"),
  101.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  102.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  103.                                        
  104.                                         (agent_clear_scripted_mode, ":agent_no"),
  105.                                 (try_end),
  106.                         (else_try),
  107.                                 (key_clicked, key_numpad_6), # 小键盘键 6,agent_force_rethink
  108.                                 (try_for_agents, ":agent_no"),
  109.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  110.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  111.                                        
  112.                                         (agent_force_rethink, ":agent_no"),
  113.                                 (try_end),
  114.                         (else_try),
  115.                                 (key_clicked, key_num_lock), # 小键盘锁定键(Num),agent_refill_ammo 恢复弹药
  116.                                 (try_for_agents, ":agent_no"),
  117.                                         (agent_get_troop_id, ":troop_id", ":agent_no"),
  118.                                         (eq, ":troop_id", "你想测试的兵种的ID"),
  119.                                        
  120.                                         (agent_refill_ammo, ":agent_no"),
  121.                                 (try_end),
  122.                         (else_try),
  123.                                 (key_clicked, key_numpad_slash), # 小键盘 除号键 /
  124.                                 (get_player_agent_no, reg1),
  125.                                 (agent_get_position, pos1, reg1),
  126.                                 (set_spawn_position, pos1),
  127.                                 (spawn_agent, "你想测试的兵种的ID"),
  128.                                 (agent_set_team, reg0, 0),
  129.                         (else_try),
  130.                                 (key_clicked, key_numpad_multiply), # 小键盘 乘号键 *
  131.                                 (get_player_agent_no, reg1),
  132.                                 (agent_get_position, pos1, reg1),
  133.                                 (set_spawn_position, pos1),
  134.                                 (spawn_agent, "敌方兵种的ID"),
  135.                                 (agent_set_team, reg0, 1),
  136.                         (try_end),
  137.                 ])
复制代码

1

主题

34

回帖

21

积分

随仆

Rank: 1

UID
3284052
第纳尔
474
精华
0
互助
2
荣誉
0
贡献
0
魅力
0
注册时间
2021-11-3

骑砍中文站APP会员勋章

鲜花(11) 鸡蛋(0)
发表于 2025-6-15 13:47:00 来自手机 | 显示全部楼层
研究得很细,学习了来自: Android客户端

0

主题

62

回帖

19

积分

随仆

Rank: 1

UID
3346943
第纳尔
519
精华
0
互助
0
荣誉
0
贡献
0
魅力
0
注册时间
2022-4-8
鲜花(2) 鸡蛋(0)
发表于 2025-6-19 19:53:43 来自手机 | 显示全部楼层
研究很详细啊来自: Android客户端
您需要登录后才可以回帖 登录 | 注册(Register!)

本版积分规则

Archiver|手机版|小黑屋|骑马与砍杀中文站

GMT+8, 2025-9-4 11:24 , Processed in 0.110922 second(s), 23 queries , Gzip On, MemCached On.

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表