阻塞函数

上文中我们提到过在 AvZ 中由 Script 函数里的内容转成对应的队列是在一瞬间完成的,在我们目前看来,这种方式带来的好处就是时间点可以随意书写了,但是一个巨大的缺点就是操作被写死了,我们貌似无法在脚本运行过程中添加或者删除操作,这对无炮或者炮阵的一些"智能"判断操作来说简直就是灭顶之灾。而阻塞函数 WaitUntil 便是解决这一问题的利器。

为了说明阻塞函数的作用,我们首先展示一种在 AvZ 中看似非常正确的写法

SetTime(200, 1);
pao_operator.pao({{2, 9}, {5, 9}});
SetTime(200 + 373 + 1);
if(AvZ::GetMainObject()->refreshCountdown() <= 200){
    Card(XRK_1, 1, 1); // 刷新了种卡
}else{
    pao_operator.pao(2, 9); // 未刷新放炮
}

上述内容大概意思就是如果炮激活了刷新就放一张卡,如果没有就放一门炮,这看着非常正常,没啥毛病,但是其实是大错特错,因为在 AvZ 中的读内存函数是无法被录入队列的,也就是说 AvZ::GetMainObject()->refreshCountdown() (读内存相关内容会在后续教程中介绍,此处只是引用一下,大家只要能够看懂大概意思就好) 这个读取僵尸刷新倒计时的代码会在录入过程中被执行完成,而不会等到游戏时间进行到 (200 + 373 + 1) 再执行,那么此处我们应该怎么写呢?下面说明正确的做法

SetTime(200, 1);
pao_operator.pao({{2, 9}, {5, 9}});
WaitUntil(200 + 373 + 1); // 阻塞
if(AvZ::GetMainObject()->refreshCountdown() <= 200){
    Card(XRK_1, 1, 1); // 刷新了种卡
}else{
    pao_operator.pao(2, 9); // 未刷新放炮
}

WaitUntil 顾名思义,等待直到,意思就是说这条语句下面的代码将会一直处于等待状态,直到游戏时间到了才会运行,这个函数的作用和 PvZ / CvZ 中的 Prejudge 一模一样,但是其精准度仍为100%,因此使用这个函数上面的代码的运行结果就会和我们的预期一样,如果炮激活了刷新就放一张卡,如果没有就放一门炮。

当然,聪明的你肯定发现了 WaitUntil 一个巨大缺点,就是我们不能随心所欲的书写时间点了,例如下面的代码是会稳定报错的。

SetTime(200, 1);
pao_operator.pao({{2, 9}, {5, 9}});
WaitUntil(200 + 373 + 1);
Card(XRK_1, 1, 1);
SetTime(-400, 1);
Card(XRK_1, 1, 1);

原因很简单,WaitUntil 会阻塞他下方的代码,我们来用队列直观的说明其运行过程,时间点(200 ,1)之前的队列

队列名队列内容
队列1(200 pao)

注意此时 (-400,1)这个时间点的操作并没有进入队列,这是因为被阻塞了。

在(200 ,1)之后(200 + 373 + 1,1)之前的队列

队列名队列内容
队列1

在 (200 + 373 + 1,1)时的队列

队列名队列内容
队列1(-400 card) (200 + 373 + 1 card)

由于时间点已经到达,阻塞函数释放阻塞,其下面的代码得以运行,所以 -400 card 这个操作就进入了操作队列,但是很明显(-400,1)这个时间点早就过去了,所以 AvZ 此时会报错(-400,1)已经过去,这就是使用阻塞函数 WaitUntil 导致的问题。

总结:阻塞函数会一直阻塞语句的运行知道时间点到达,**因此请确保时间顺序书写正确,在阻塞时间点之前的操作一定要写在阻塞函数之前,**不然就会报错。

读到这里大家可能会有一个问题,就是读取内存函数为啥不能录入队列,为啥 pao card 这样的函数就可以进入操作队列,这个问题就是下篇文章我们即将要讨论的——AvZ 函数属性

上一篇 操作队列

目录

下一篇 函数属性