骑马与砍杀中文站论坛

 找回密码
 注册(Register!)

QQ登录

只需一步,快速开始

搜索
购买CDKEY 衣谷三国
查看: 1715|回复: 1

[经验与教程] 【性能优化】创建一个伪列表来储存每个阵营的部队

[复制链接]

23

主题

78

回帖

340

积分

贵族[MOD作者]

Rank: 7Rank: 7Rank: 7

UID
3154436
第纳尔
1428
精华
1
互助
14
荣誉
14
贡献
10
魅力
134
注册时间
2020-4-2

霸主正版勋章

鲜花(40) 鸡蛋(0)
发表于 2025-4-23 07:03:18 | 显示全部楼层 |阅读模式
本帖最后由 我只玩MID 于 2025-4-23 07:10 编辑

在制作《骑马与砍杀:战团》MOD时,众所周知,脚本系统本身并不支持类似 Python 的“列表”结构。这意味着我们无法直接创建一个只包含特定阵营(比如某几个“非法”阵营)的集合来进行遍历,而是通常需要循环所有阵营(或指定范围)并通过条件判断筛选目标。这种方式不仅繁琐,也影响效率。那么,有没有办法模拟类似 Python 中的“列表”功能,从而只遍历我们关心的几个特定阵营,而不是全体 fac_ 阵营?答案是:可以,通过“伪列表”,完全可以实现这一目标。
不过,如果只是为了存储少量特定阵营,单独去构建一个“伪列表”似乎显得不太有必要。因此,接下来我将介绍进阶的内容 —— 如何为每个阵营单独记录它所拥有的全部野怪部队,并演示如何方便地调用这些数据。

第一步:在 module_constants.py 中定义用于计数的 Slot
我们首先需要为每个阵营记录它拥有的野怪部队数量,并创建每个阵营对应的列表。为此,在 module_constants.py 中添加二个新的 Slot 定义:
  1. slot_faction_bandit_party_number = 200 # 两个slot使用不同的调用方法,一个是faction_set_slot 一个是 troop_set_slot 所以值可以是相同的
  2. slot_store_faction_bandit_party_list       = 301 ##储存阵营野怪的部队的列表
复制代码

第二步:在 module_scripts.py 中新增一个脚本
这个脚本的作用是在每次新的部队生成时,将这个部队储存到我们的“伪列表”中。所以,在 module_scripts.py 的最后添加一个新的脚本:
  1.     ("add_faction_bandit_party_list", [  # 将一个野怪部队添加到所属阵营的野怪列表中

  2.     (store_script_param, ":party_no", 1),  # 获取传入的部队编号

  3.     (store_faction_of_party, ":party_faction", ":party_no"),  # 获取该部队所属的阵营

  4.     (try_begin),
  5.         (neg|is_between, ":party_faction", kingdoms_begin, kingdoms_end),  # 排除王国阵营,只处理野怪等非国家阵营 # 在我的mod中处于性能考虑屏蔽了王国阵营

  6.         (faction_get_slot, ":party_number", ":party_faction", slot_faction_bandit_party_number),  # 获取该阵营当前记录的野怪部队数量
  7.         (store_add, ":faction_bandit_party_list", slot_store_faction_bandit_party_list, ":party_faction"),  # 计算该阵营的“伪列表”起始 Slot 编号

  8.         (assign, ":is_passed", -1),  # 标志变量,初始为 -1,表示未找到插入位置

  9.         # 遍历该阵营已记录的野怪部队 Slot
  10.         (try_for_range, ":list_id", 0, ":party_number"),
  11.             (eq, ":is_passed", -1),  # 只在未插入时继续判断

  12.             (troop_get_slot, ":party_id", ":list_id", ":faction_bandit_party_list"),  # 获取当前列表中的部队 ID

  13.             # 校验部队是否有效,如果无效则视作可插入位置
  14.             (try_begin),
  15.                 (party_is_active, ":party_id"),
  16.                 (store_faction_of_party, ":party_id_faction", ":party_id"),
  17.             (else_try),
  18.                 (assign, ":party_id_faction", ":party_faction"),
  19.             (try_end),

  20.             # 如果部队阵营不匹配 或 非活跃 或 编号非法,则覆盖当前槽位
  21.             (this_or_next|neq, ":party_id_faction", ":party_faction"),
  22.             (this_or_next|le, ":party_id", centers_end),
  23.             (neg|party_is_active, ":party_id"),

  24.             (troop_set_slot, ":list_id", ":faction_bandit_party_list", ":party_no"),  # 将部队编号写入列表
  25.             (assign, ":is_passed", ":list_id"),  # 标记插入位置

  26.             # 如果原槽位的部队属于其他阵营,则尝试将其重新插入对应阵营的列表
  27.             (try_begin),
  28.                 (neq, ":party_id_faction", ":party_faction"),
  29.                 (call_script, "script_add_faction_bandit_party_list", ":party_id"),
  30.             (try_end),
  31.         (try_end),

  32.         # 如果前面没有找到可覆盖的位置,则在末尾新加一条记录
  33.         (try_begin),
  34.             (eq, ":is_passed", -1),
  35.             (troop_set_slot, ":party_number", ":faction_bandit_party_list", ":party_no"),  # 在末尾追加部队编号
  36.             (val_add, ":party_number", 1),  # 阵营部队数量+1
  37.             (faction_set_slot, ":party_faction", slot_faction_bandit_party_number, ":party_number"),  # 写入新的部队数量
  38.         (try_end),
  39.     (try_end),
  40.     ]),
复制代码
我们已经成功创建了一个用于储存各个阵营野怪部队的“伪列表”。这个机制具有良好的扩展性:即使新增了阵营,也无需手动重新配置,只需在部队生成的地方调用一次 script_add_faction_bandit_party_list 脚本即可完成记录。
例如,在使用如下语句生成部队时:
  1. (spawn_around_party, ":center_no", "pt_knight_garrison_g"),
  2.       (assign, ":party_no", reg0),
  3. (party_set_faction, ":party_no", ":center_knights"),
  4. (call_script, "script_add_faction_bandit_party_list", ":party_no"),
复制代码
需要注意的是,若你随后通过 (party_set_faction, "sparty_no", ":center_knights") 等方式手动设置了该部队的阵营务必确保在设置阵营之后再调用 script_add_faction_bandit_party_list 脚本。否则,由于默认情况下部队模板的阵营可能与你设置的不一致,就会导致错误地将该部队记录到错误的阵营列表中。
战团自身通过代码自动生成的野怪部队,如果希望它们也能被完整地记录进各自阵营的“野怪部队列表”中,同样需要在这些部队创建之后手动调用一次 script_add_faction_bandit_party_list 脚本


在完成所有前置准备后,我们现在就可以随时调用“伪列表”中储存的各阵营野怪部队了。调用方式非常简单。
下面以调用 不法之徒(fac_outlaws) 阵营的全部野怪部队为例,示范如何获取并遍历获取一个离玩家最近的不法之徒野怪部队:
  1.     (assign, ":faction_no", "fac_outlaws"),  # 设定要查询的阵营为不法之徒(fac_outlaws)

  2.     (assign, ":party_distance", 99999),      # 初始化最近距离为一个极大值(用来后续比较)
  3.     (assign, ":attack_party", -1),           # 初始化攻击目标为 -1,表示尚未找到合适目标

  4.     (faction_get_slot, ":party_number", ":faction_no", slot_faction_bandit_party_number),  # 获取该阵营已记录的野怪部队数量
  5.     (store_add, ":faction_bandit_party_list", slot_store_faction_bandit_party_list, ":faction_no"),  # 获取该阵营对应的野怪部队列表槽位起始值

  6.     (try_for_range, ":list_id", 0, ":party_number"),  # 遍历该阵营所有登记在册的野怪部队
  7.         (troop_get_slot, ":party_id", ":list_id", ":faction_bandit_party_list"),  # 从伪列表中读取当前部队的 ID
  8.         
  9.         (gt, ":party_id", centers_end),             # 排除 ID 属于城镇等固定据点的情况
  10.         (party_is_active, ":party_id"),             # 确保该部队仍处于活动状态(未被消灭)

  11.         (store_faction_of_party, ":party_faction", ":party_id"),  # 获取该部队当前所属阵营
  12.         (eq, ":party_faction", ":faction_no"),      # 再次确认该部队确实属于指定阵营(防止阵营变化后数据未更新)

  13.         (store_distance_to_party_from_party, ":distance", "p_main_party", ":party_id"),  # 计算主角与该部队的距离

  14.         (lt, ":distance", ":party_distance"),       # 如果该部队比当前记录的最近部队更近
  15.             (assign, ":party_distance", ":distance"),   # 更新记录的最近距离
  16.             (assign, ":attack_party", ":party_id"),     # 更新攻击目标部队 ID
  17.     (try_end),
复制代码
通过这种“伪列表”方法,避免了每次都遍历所有阵营的情况,极大提升了性能,特别是在频繁检查特定阵营或部队时。通过预先存储和管理相关部队信息,减少了不必要的循环,从而优化了游戏的运行效率,即使加入新的阵营或部队,相关操作依然可以顺利执行,而无需重新调整复杂的循环结构并且这种方法不仅适用于部队,也可以轻松扩展到储存特定物品、人物等数据。

总结优势:
1、性能优化:每次只针对特定阵营或条件进行处理,避免了遍历所有数据的性能损耗。
2、灵活调用:通过动态存储阵营的部队列表,能够随时快速地获取目标部队或信息。


23

主题

78

回帖

340

积分

贵族[MOD作者]

Rank: 7Rank: 7Rank: 7

UID
3154436
第纳尔
1428
精华
1
互助
14
荣誉
14
贡献
10
魅力
134
注册时间
2020-4-2

霸主正版勋章

鲜花(40) 鸡蛋(0)
 楼主| 发表于 2025-4-23 07:05:54 | 显示全部楼层
ps:由于我的表述问题,怕大伙不好理解我说的话(自认为说话可能比较混乱),所以用ai帮我润色了一下表达。并且由于我写代码没有写注释的习惯,所以也用ai加上了中文注释,再自己略微调整了下,读起来应该没什么大问题。
您需要登录后才可以回帖 登录 | 注册(Register!)

本版积分规则

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

GMT+8, 2025-9-1 12:58 , Processed in 0.096238 second(s), 19 queries , Gzip On, MemCached On.

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.

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