Simple AvZ ---------- 一种很新的 AvZ
植物大战僵尸吧
全部回复
仅看楼主
吧务
level 11
Crescendo 楼主
Simple AvZ, 即 "AvZ 简化版", 是基于 AvZ 1 设计的一套用于精简脚本的语法框架.
2023年11月30日 20点11分 1
吧务
level 11
Crescendo 楼主
使用方式
从零开始安装 AvZ 1 与 Simple AvZ 的视频教程:BV1pC4y1U7WL
如果你已安装 AvZ 1 环境,只需通过 Get AvZ Extension 下载本插件后, 在脚本中加入 #include "SimpleAvZ/lib.h" 即可.
若 Get AvZ Extension 不可用, 可从本仓库 /release 目录中手动下载. (gitlab.com/avzlib/AvZLib/-/tree/main/crescendo/SimpleAvZ/SimpleAvZ).
2023年11月30日 20点11分 2
v1.0.1更新:适配全12场景(增加对蘑菇园、禅境花园、水族馆、智慧树、D6E、N6E无尽场景的支持)。
2023年12月22日 07点12分
吧务
level 11
Crescendo 楼主
设计理念
简洁 好于 冗长
声明 好于 命令
安全 好于 效率
下面举一些例子说明上述理念.
2023年11月30日 20点11分 3
吧务
level 11
Crescendo 楼主
剔除 SetTime
Simple AvZ 的重要目标之一, 是让脚本中不再出现 SetTime 与 Delay.
以 [PE]. 最后之作 的减速波为例:
// 原生 AvZ 1
for (auto wave : {...}) {
SetTime(410 - 373, wave);
pao_operator.pao({{2, 8.75}, {5, 8.75}});
Delay(220);
pao_operator.pao({{1, 8.575}, {5, 8.575}});
SetTime(1100 - 378);
pao_operator.pao(3, 8.2375);
SetTime(1887 - 200 - 373);
pao_operator.pao({{2, 8.5}, {5, 8.5}});
SetTime(1887 + 10 - 298);
ice_filler.coffee();
SetPlantActiveTime(ICE_SHROOM, 298);
}
如果你刚写完这段脚本, 并不会觉得有违和感.
可当一段时间后重读, 或是其他人阅读此段时, 大家关心的是具体操作及时机, 可满眼望去却都是 SetTime, Delay, 和反复出现的神秘嘉宾 -373.
使用 Simple AvZ, 以上代码简化为:
// Simple AvZ 💫
for (auto w : waves(...)) {
PP(410, 8.75);
DD(after(220), 8.575);
B(1100, 3, 8.8275);
PP(1887 - 200, 8.5);
I(after(210));
}
代码行数减半, 重要信息一览无余, 且十分接近我们熟知的轨道语言, 一看就懂.
我们知道炮的飞行时间, 知道当前场景, 更知道 PE 下多数情况不是炸 2,5 就是炸 1,5 路. 既然如此, 为何不对这些信息加以利用呢? 这是 Simple AvZ 的初衷.
2023年11月30日 20点11分 4
吧务
level 11
Crescendo 楼主
以生效时机思考
对手控玩家而言, 掐时机至关重要, 什么时候点冰, 什么时候拖炮都有讲究.
可在键控领域, 我们更关心生效时机!
使用 Simple AvZ, 你可以写出这样的代码:
// Simple AvZ 💫
PP(318, 8.8);
以声明我要在 318cs 于 8.8 列生效并炸炮.
至于 PP 炸哪行? 如果有上界之风, 应如何修正发炮时间? 这一切都由 Simple AvZ 自动推测, 编写者无需多虑.
这就是所谓的声明式编程, 即以结果为导向,而非以过程为导向.
这不仅让代码更简洁易懂, 增加编写效率, 更避免了一些本不必要的 bug. 例如炮击泳池飞行 378cs, 炮击平地飞行 373cs, 若不小心区分很容易混淆, 可多数情况下我们本不关心这些, 只是想在特定时机让炮生效罢了.
2023年11月30日 20点11分 5
吧务
level 11
Crescendo 楼主
基于炮的时间体系
由于游戏的蛋疼设定, 每帧结算顺序为 [植物] --> [僵尸] --> [子弹].
说来也巧, 由于冰与灰烬(樱辣窝核)属于 [植物], 而炮又属于 [子弹], 两者相对于 [僵尸] 的结算顺序便有了 1cs 偏差.
简单来说, x cs 生效的炮 = x + 1 cs 生效的卡.
这个不一致性在 AvZ 1 设计伊始就已显现, 如 AvZ::SetPlantActiveTime(), 即 Ice3 函数, 其实际效果为将冰生效时机修正为设定时机的 下一 cs.
一说这有道理, 因为按僵尸时间, 巨人确实运动了 105/210cs, 只是由于冰早于僵尸结算, 故实际要 +1cs. 一说这不科学, 其它用卡用炮皆以实际时机书写, 为何冰要特殊处理?
Simple AvZ 对此的解决思路如下.
首先,基于声明好于命令的理念, 樱辣窝核这四张卡以炮时机书写更优, 因为实际时机不如等效炮时机好用. 如此便有:
// Simple AvZ 💫
P(359, 2, 9);
C(359, CHERRY, 5, 9);
DD(after(107), 1, 7.8);
樱桃实际在 360 生效, 但编写者和读者无需考虑这样的细枝末节, 统一作 359 即可, 清晰易懂.
由于樱辣窝核以炮时机书写甚为合理, Simple AvZ 选择将冰也纳入此体系, 以炮为纲, 一统江湖. 这也使得其对旧脚本的兼容性更佳, 且更符合 AvZ 的设计初衷.
2023年11月30日 20点11分 6
吧务
level 11
Crescendo 楼主
自动设定波次
原生 AvZ 中, 我们常用 for (auto wave : {...}) 书写循环, 但循环节内部首次 SetTime 时, 必须不能忘记带上 wave, 否则 AvZ 很生气, 后果很严重.
既然这种写法如此常用, 为何不自动设定波次呢? 于是就有了:
// Simple AvZ 💫
for (auto w : waves(1, 2, 3)) {
PP(318);
...
}
使用 Simple AvZ 提供的 waves() 函数, 妈妈再也不担心我忘记设定波次啦.
不仅如此, 你还可以用 waves() 表达更复杂的循环:
waves({1, 9}, 4) // w1~w9 每 4 波一循环
waves({1, 9}, {11, 19}, 4) // w1~w9, w11~w19 每4波一循环
2023年11月30日 21点11分 8
吧务
level 11
Crescendo 楼主
更便捷的用卡
原生 AvZ 有以下三种常用的用卡方式:
Card(PEA_SHOOTER, 1, 1); // 在1-1种植豌豆射手
Card(PEA_SHOOTER, {{1, 1}, {1, 2}}); // 先尝试在1-1种, 不行则改为1-2
Card({{PEA_SHOOTER, 1, 1}, {SUNFLOWER, 1, 2}}); // 1-1种豌豆, 1-2种小向
可在实战中, 我们经常需要:
// 垫1, 2, 5, 6路
Card({{PUFF_SHROOM, 1, 9}, {SUN_SHROOM, 2, 9}, {SCAREDY_SHROOM, 5, 9}, {FLOWER_POT, 6, 9}});
// 在水上点核
Card({{LILY_PAD, 3, 9}, {DOOM_SHROOM, 3, 9}, {COFFEE_BEAN, 3, 9}});
长久以来, 我们都习惯了这样写. 可既然这两种情况如此常见, 为何不提供更便捷的写法呢?
// Simple AvZ 💫
C(400, {PUFF, SUN, SCAREDY, POT}, {1, 2, 5, 6}, 9); // 垫1, 2, 5, 6路
C(359, {LILY, DOOM, COFFEE}, 3, 9); // 在水上点核
对常用的植物与僵尸, Simple AvZ 提供了(合理的)缩写.
有种即有铲. 你可以便捷地传入铲除时机:
// Simple AvZ 💫
C(400, keep(268), PUFF, 1, 9); // 400cs种植, 268cs后铲
C(400, until(1038), PUFF, 1, 9); // 400cs种植, 于1038cs铲
此外, 你也可以指定延迟 x cs 生效卡, 或是直接调用铲除函数等, 详见完整 API.
2023年11月30日 21点11分 9
请问,类似于原生AVZ的第二种用法 C(700,{LILY,DOOM},{{3,8},{3,9}}); 这种写法是允许的吗?
2023年12月30日 14点12分
@时间微元 不允许。SimpleAvZ尽可能避免了不确定操作结果的操作,而是提倡哪一波用哪个坑就明确写明,这样方便调试,避免了不必要的麻烦。
2023年12月30日 14点12分
@Crescendo 好的
2023年12月31日 03点12分
吧务
level 11
Crescendo 楼主
安全优先
不知道你是否曾手滑, 写出过下面这样的代码呢?
// 原生 AvZ 1
pao_operator.pao(5, 8525);
PvZ 里当然没有 8525 列, 可 AvZ 对于这样的语句全程不会报错, 徒留你在游戏里看着莫名奇妙轨迹的炮独自凌乱.
游戏设定是明确的, 发射 0.0~10.0 列之外的炮必定没有意义. 既然如此, 我们可以增加报错信息, 让你在手滑后第一时间就能发现错误.
Simple AvZ 提供的每一个函数都会对输入进行严格检查. 在 AvZ 调用 Script(), 也就是刚点进 Survival Endless 模式时, 就会告知玩家代码中的错误.
上面的代码若用 Simple AvZ 提供的 P 函数, 将报如下错:
[调用 P 时出错]
落点列应在0.0~10.0内
落点列: 8525
此外, Simple AvZ 会自动检测 waves() 调用的波次是否有重复的, 避免写错波次造成的不必要的麻烦.
2023年11月30日 21点11分 10
吧务
level 11
Crescendo 楼主
API 一览 (v1.0.0)
设定波次
waves(1, 2, 3); // w1, w2, w3(可指定任意多个)
waves({1, 9}, 4); // w1~w9 每4波一循环
waves({1, 9}, {11, 19}, 4); // w1~w9, w11~w19 每4波一循环
for (auto w : waves(...)) {
// 具体操作
// 可以使用 if 语句判断当前在哪波
if (w == 1) {
C(359, DOOM, 2, 9);
} else if (w == 5) {
C(359, DOOM, 3, 9);
}
}
Simple AvZ 的函数除非标注"[外]", 都需在 waves() 循环节内部使用.
设定时间
(318, ...) // 于本波318cs生效
(after(110), ...) // 延迟110cs生效
(now, ...) // now 等价于 after(0)
大多数 Simple AvZ 函数的第一个参数为时间. after() 可以取负值, 但不推荐这样做, 因为会降低可读性.
2023年11月30日 21点11分 11
吧务
level 11
Crescendo 楼主
用炮
PP(318); // 炸(2,9)与(5,9), 318cs生效
PP(318, 8); // 炸(2,8)与(5,8)
PP(318, {8, 9}); // 炸(2,8)与(5,9)
PP(318, {2, 6}, 9); // 炸(2,9)与(6,9)
发射一组并炸炮. 若省略行数, 六行场地炸 2,5 路, 五行场地炸 2,4 路. 若省略列数, 默认炸 9 列.
PP(after(110), ...); // 用法同上, 延迟110cs生效
PP(now, ...); // now 与 after(0) 等价
用炮生效时机的变种. 其它函数也可使用.
DD(...); // 用法与PP相同
发射一组拦截炮. 若省略行数, 六行场地炸 1,5 路, 五行场地炸 1,4 路. 若省略列数, 默认炸 9 列.
P(318, 2, 9); // 炸(2,9), 318cs生效
B(...); // 分离炮, 用法与P相同
D(...); // 拦截炮, 用法与P相同
P(318, 1, 1, 2, 8); // 使用1-1炮炸(2,8)
发射一门炮. 可指明要用哪门炮. 可视情况选用 P, B, D 三种标签之一, 传达用炮意图.
ExcludeCob(3, 5); // 不使用3-5炮, 游戏开始时起效[外]
ExcludeCob(400, ...); // 400cs起效
ResetCob(400); // 重置为使用所有炮, 400cs起效
不使用特定炮, 或重置为使用所有炮.
CobOperator c1(1); // 只用炮尾在1列的炮
CobOperator c45(4, 5); // 只用炮尾在4或5列的炮
void Script() {
c1.PP(...); // 调用方法相同
}
在屋顶场合, 你可以声明多个 CobOperator, 然后使用以上函数.
2023年11月30日 21点11分 12
问个问题,如果我想要指定炮尾1-3的炮炸5-7,该怎么处理?
2023年12月21日 11点12分
@时间微元 假设你说炸5-7的意思是炸5路7列。那么就是先在Script()函数外定义CobOperator foo(1,2,3); 然后Script()内 foo.P(278, 5, 7)。foo可以换为任何变量名。
2023年12月22日 07点12分
@Crescendo 抱歉,是我表达不清。我说炮尾1-3指的是在一行三列的炮,请问如何指定?
2023年12月22日 08点12分
@时间微元 P(318, 1, 1, 2, 8); // 使用1-1炮炸(2,8) ————摘自本楼。
2023年12月22日 09点12分
吧务
level 11
Crescendo 楼主
用卡 / 用铲
冰, 核, 樱, 辣, 窝 默认使用炮等效时间, 见[基于炮的时间体系].
I(1, 2); // 于1-2放置原版冰, 601cs生效(完美预判冰)
I(after(210), 1, 2); // 延迟210cs生效(ice3), 推荐在激活炮后使用
I(359, 1, 2); // 359cs生效
M_I(...); // 用法同上, 使用复制冰
夜间用冰. 自带生效时机修正. 若不指定生效时间, 默认在本波 601cs 生效.
SetIce({{1, 1}, {1, 2}}); // 在1-1, 1-2存冰(优先使用1-2)[外]
SetIce(400, {...}); // 400cs生效
白昼设置存冰位置. 若不指定生效时间, 默认在 wave 1, -599cs 生效.
I(); // 点冰, 601cs生效(完美预判冰)
I(after(210)); // 延迟210cs生效(ice3), 推荐在激活炮后使用
I(359); // 359cs生效
白昼点冰. 自带生效时机修正. 若不指定生效时间, 默认在本波 601cs 生效.
C(359, CHERRY, 2, 9); // 于2-9放置樱桃, 359cs生效
C(400, {PUFF, SUN}, {1, 2}, 9); // 于1-9放置小喷, 2-9放置阳光菇
C(359, {LILY, DOOM, COFFEE}, 3, 9); // 于3-9放置荷叶, 核武, 咖啡豆
用卡. 可提供单一坐标, 多行同列, 或多卡同坐标.
C(after(110), ...); // 用法同上, 延迟110cs生效
C(exact(800), ...); // 不使用炮等效时间, 800cs生效
C(exact(after(..)), ...); // 以上两者的结合
用卡生效时机的变种.
C(400, keep(266), ...); // 生效后266cs铲
C(400, until(1036), ...); // 1036cs铲
指定用卡后的铲除时机.
RM(400, SUNFLOWER); // 于400cs铲除场地上所有小向
RM(400, PUMPKIN, 1, 1); // 铲除1-1南瓜(没有则不铲)
RM(400, 1, 1); // 铲除1-1, 优先铲除非南瓜
RM(400, {1, 2, 5, 6}, 9); // 铲除1,2,5,6路9列, 优先铲除非南瓜
RM(after(751), ...); // 用法同上, 延迟751cs生效
铲除植物. 可提供单一坐标, 多行同列. 也可指定要铲除的植物种类.
2023年11月30日 21点11分 13
问下怎么逐波设置9列存冰位,有的会和灰烬垫材重合
2023年12月11日 08点12分
@大国工匠🐎斯克 9列存冰位,一般就不需要自动存冰了,手动设置点冰/存冰的时间点比较好。
2023年12月11日 10点12分
吧务
level 11
Crescendo 楼主
演示功能
EnsureExist(GIGA); // 确保红眼出现在所有合理行
EnsureExist({GIGA, 2, 3}); // 确保红眼出现在第2,3行
EnsureExist({{GIGA, 2, 3}, {ZOMBONI, 4}}); // 确保红眼出现在第2,3行, 冰车出现在第4行
确保本波某类僵尸出现在某行, 主要用于录制演示视频.
请勿在实际冲关或批量测试中使用.
智能用卡
C_IF(exist(ZOMBONI), 400, SPIKEWEED, 1, 9); // 若本行存在冰车, 于400cs在1-9放置地刺
C_IF(pos({GARG, GIGA}, 680), 400, POT, 1, 8); // 若本行存在int(x)≤680的白眼或红眼, 于400cs在1-8放置花盆
根据本行僵尸情况决定是否用卡. 提供"僵尸是否存在", 以及"僵尸x是否小于某值"两种判断方式. 主要用于实际冲关或批量测试.
录制演示视频时, 更推荐用 EnsureExist, 因为这样可以展现最复杂的情况.
2023年11月30日 21点11分 14
请问能不能判断核坑位置,比如4-9有核坑就如何如何,没有就如何如何?
2023年12月29日 09点12分
@时间微元 不能。SimpleAvZ主要服务于键控演示视频场景,而演示视频中一般不应该出现【不知道某个格子有没有核坑】的情况(节奏应该是事先就计算确定过了的)。当然原生AvZ是自带这个功能(而且允许在SimpleAvZ里写原生语句,这个并不冲突)。
2023年12月29日 11点12分
@Crescendo 哦这样,好的,谢谢
2023年12月29日 12点12分
@Crescendo 所以原生AVZ指的是AVZ1是吗
2023年12月29日 13点12分
吧务
level 11
Crescendo 楼主
脚本示例: cv26755396
了解更多
要查看 Simple AvZ 开发幕后的碎碎念, 请参阅gitlab.com/avzlib/AvZLib/-/blob/main/crescendo/SimpleAvZ/docs/About.md.
全贴完。
2023年11月30日 21点11分 15
吧务
level 15
这个帖子有点像黑洞
2023年12月03日 11点12分 23
1 2 尾页