- 好友
- 7
- 在线时间
- 0 小时
- 最后登录
- 2024-11-18
见习骑士
- UID
- 3189500
- 第纳尔
- 2704
- 精华
- 0
- 互助
- 26
- 荣誉
- 6
- 贡献
- 20
- 魅力
- 437
- 注册时间
- 2020-6-13
鲜花( 67) 鸡蛋( 0)
|
本帖最后由 武安apk43 于 2023-9-26 15:50 编辑
我想实现一些比较有意思的功能,比如攻城的闸门、吊桥、可破坏的城墙等等,但无奈于AI网格是场景编辑时定好的,就算做了这些,AI不会正确寻路也白搭。这也是为什么一些动态场景在联机比较常见,而单机就几乎没有,最大的问题就是AI寻路问题。
单机里默认module.ini把can_use_scene_props_in_single_player设为0,禁用了可移动场景道具的交互。如果把这个启用就会发现,战团原版里的几乎所有城堡的闸门都是可以控制开关的,因为触发器代码都是写好的。
比如攻城塔,AI网格都是按照攻城塔终点位置来铺的,在攻城塔未到达终点之前,脚本里默认是让所有人坚守,然后到了终点命令所有人冲锋。如果在未到达终点之前玩家手动命令所有人冲锋,AI就会傻乎乎按照AI网格往前走,不管有没有路。
为了让AI能够根据场景变动而改变寻路,我受Unity的Nav Mesh Obstacle的启发,想到了动态AI网格的方案。这个方案的好处在于,无需用脚本控制AI目的地,更别提用脚本重写寻路算法。
于是在wse2作者k700的启发下,了解了这个战团自带OP:
ai_mesh_face_group_show_hide = 1805 # (ai_mesh_face_group_show_hide, <group_no>, <value>), # 1 for enable, 0 for disable
# Debug -- Draws the selected index of triangles/quads from the navigation graph on-screen.
这个group_no就是AI网格的id,以面为单位。而经过尝试后就又遇到了棘手的问题,详细请看这个帖:
【探究】关于AI网格纹理消失的原因和解决方案 - MOD制作技术区 - 骑马与砍杀中文站论坛 - Powered by Discuz! (mountblade.com.cn)。
在修复这个问题之前,我尝试用这个op代码来测试是否有效,结果铺好网格后,无论是否显示、隐藏,AI都能通过指定的AI网格面,并且由于显示不出AI网格的面,也无法判断AI网格的状态。
在通过修复字体之后,神奇的事发生了,op生效了。
方法比较简单:
在能正确显示AI网格面的纹理的情况下,选定需要动态变化的网格,编辑AI网格时设定一个特殊id(默认创建的都是0),
然后在脚本里用ai_mesh_face_group_show_hide控制指定ID的AI网格的显示和隐藏。
加勒比海盗那个独立游戏的MS系统里还有一个ai_mesh_face_group_translate更加灵活,可以移动AI网格。。。
以城堡闸门为例:
在编辑模式下铺好AI网格,并让闸门下方的网格设定一个AI mesh id(只要不为0,不与其他AI网格重复就行),然后
这个是闸门开关的触发器在scene_props.py里:
- ("winch_b",sokf_moveable|spr_use_time(5),"winch_b","bo_winch", [
- (ti_on_scene_prop_use,
- [
- (store_trigger_param_1, ":agent_id"),
- (store_trigger_param_2, ":instance_id"),
- #for only server itself-----------------------------------------------------------------------------------------------
- (call_script, "script_use_item", ":instance_id", ":agent_id"),
- #for only server itself-----------------------------------------------------------------------------------------------
- (get_max_players, ":num_players"),
- (try_for_range, ":player_no", 1, ":num_players"), #0 is server so starting from 1
- (player_is_active, ":player_no"),
- (multiplayer_send_2_int_to_player, ":player_no", multiplayer_event_use_item, ":instance_id", ":agent_id"),
- (try_end),
- ]),
- ]),
复制代码
战团原版把一些交互场景道具都写在了script_use_item里,不难发现scene_prop_open_or_close_slot就是存储一些场景道具的开关状态。其中闸门是spr_portcullis,代码部分
- (try_begin),
- (eq, ":effected_object", "spr_portcullis"),
- (scene_prop_get_slot, ":opened_or_closed", ":instance_id", scene_prop_open_or_close_slot),
- (try_begin),
- (eq, ":opened_or_closed", 0), #open gate
- (scene_prop_enable_after_time, ":instance_id", 400), #4 seconds
- (try_begin),
- (this_or_next|multiplayer_is_server),
- (neg|game_in_multiplayer_mode),
- (prop_instance_get_position, pos0, ":effected_object_instance_id"),
- (position_move_z, pos0, 375),
- (prop_instance_animate_to_position, ":effected_object_instance_id", pos0, 400),
- (try_end),
- (scene_prop_set_slot, ":instance_id", scene_prop_open_or_close_slot, 1),
- (try_begin),
- (eq, ":scene_prop_id", "spr_winch_b"),
- (this_or_next|multiplayer_is_server),
- (neg|game_in_multiplayer_mode),
- (prop_instance_get_position, pos1, ":instance_id"),
- (prop_instance_rotate_to_position, ":instance_id", pos1, 400, 72000),
- (try_end),
- (else_try), #close gate
- (scene_prop_enable_after_time, ":instance_id", 400), #4 seconds
- (try_begin),
- (this_or_next|multiplayer_is_server),
- (neg|game_in_multiplayer_mode),
- (prop_instance_get_position, pos0, ":effected_object_instance_id"),
- (position_move_z, pos0, -375),
- (prop_instance_animate_to_position, ":effected_object_instance_id", pos0, 400),
- (try_end),
- (scene_prop_set_slot, ":instance_id", scene_prop_open_or_close_slot, 0),
- (try_begin),
- (eq, ":scene_prop_id", "spr_winch_b"),
- (this_or_next|multiplayer_is_server),
- (neg|game_in_multiplayer_mode),
- (prop_instance_get_position, pos1, ":instance_id"),
- (prop_instance_rotate_to_position, ":instance_id", pos1, 400, -72000),
- (try_end),
- (try_end),
复制代码
所以完全可以在#open gate部分加上 (ai_mesh_face_group_show_hide, <your_mesh_id>, 1),比如在“(scene_prop_set_slot, ":instance_id", scene_prop_open_or_close_slot, 1),”后面加上;
在#close gate部分加上(ai_mesh_face_group_show_hide, <your_mesh_id>, 0),比如在“(scene_prop_set_slot, ":instance_id", scene_prop_open_or_close_slot, 0),”后面加上。
因为城门默认是关闭的,所以可以在winch_b里加上
(ti_on_scene_prop_hit,
[
(ai_mesh_face_group_show_hide, <your_mesh_id>, 0),
]),
似乎这个op代码在这里不生效,我推测是先加载场景道具再加载AI网格,所以就在场景开始之后触发一次:
(3, 0, ti_once, [],
[
(ai_mesh_face_group_show_hide, <your_mesh_id>, 0),
]),
这样城门打开时AI就能自动进城,关闭时就绕路走了
为了更好记忆场景道具对应的AI Mesh ID,可以在module_constants.py里定义一些常量,比如设定城堡吊闸的AI网格ID设为了10,那么就可以写PORTCULLIS_AI_MESH_ID = 10 # 吊闸,这样就更方便管理一些,需要用的时候直接用(ai_mesh_face_group_show_hide, PORTCULLIS_AI_MESH_ID, <value>)。
|
评分
-
查看全部评分
鲜花鸡蛋815208129 在2023-9-20 13:08 送朵鲜花 并说:我非常同意你的观点,送朵鲜花鼓励一下 815208129 在2023-9-20 13:08 送朵鲜花 并说:我非常同意你的观点,送朵鲜花鼓励一下 815208129 在2023-9-20 13:08 送朵鲜花 并说:我非常同意你的观点,送朵鲜花鼓励一下 半世尘埃 在2023-9-18 20:22 送朵鲜花 并说:我非常同意你的观点,送朵鲜花鼓励一下
|