最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

解釋一下AvZ的IQ/NIQ

2022-11-25 13:28 作者:Crescebdo  | 我要投稿

僅為群友而寫。


AvZ里,有一個神奇的東西叫“InsertOperation”。


對萌新而言,是完全用不上這個東西的。以經(jīng)典12腳本為例:


無非就是一直SetTime,然后pao_operator.pao,再配合C++自帶的循環(huán)語法就夠了。


不用InsertOperation,你可以滿足99%的鍵控需求,至少把炮陣一百選或者我空間里絕大多數(shù)視頻打一遍毫無問題。


那么這個InsertOperation又是何方神圣呢?


舉個??,假設(shè)你知道avz_more(一個AvZ擴展)里提供了讀取當(dāng)前陽光的函數(shù):



現(xiàn)在你想在wave11刷新時,調(diào)用這個函數(shù),輸出當(dāng)前陽光。


萌新可能會這么寫:


然而實際上,這段代碼會輸出本次選卡開始前的陽光數(shù),而非實時數(shù)值。


這是不是很令人迷惑?畢竟,輸出語句的確是wave11刷新時執(zhí)行的。它怎么會輸出一個舊的值呢?


要理解這個事情,你只需要記住一句話:


AvZ腳本里所有代碼在進入生存無盡的一瞬間就運行完了。

AvZ腳本里所有代碼在進入生存無盡的一瞬間就運行完了。

AvZ腳本里所有代碼在進入生存無盡的一瞬間就運行完了。


這件事非常重要!不理解的話請換個姿勢多讀幾遍。


上面這個例子里:


GetSun()是代碼,沒錯吧?


前面那句話說,AvZ的所有代碼都是在進入生存無盡的一瞬間運行的。


因此,GetSun()是進入生存無盡的一瞬間運行的。


由于你點進游戲生存無盡的一瞬間是本次選卡開始前,所以GetSun()的值當(dāng)然就是選卡開始前的陽光數(shù)(比如8000),而非實時數(shù)值咯。


如果你在腳本里加一句 SetErrorMode(CONSOLE),當(dāng)AvZ注入完畢后,點開游戲時會跳一個黑色調(diào)試窗口。實際上跳出這個黑色窗口的瞬間,所有代碼就都運行完畢了。



等等……


你逗我呢?


如果所有代碼都是一開始就運行完了,那AvZ是怎么發(fā)炮的?



如圖,pao_operator.pao(2, 9)也是代碼啊。那它豈不也是剛點進游戲就運行了?可是實際上它明明是在我們指定的時間點才會發(fā)炮。


原因很簡單……?


運行代碼,不等于現(xiàn)在就執(zhí)行操作,也可能是過一會執(zhí)行操作。


打個比方,“運行”就像是定罪,但定罪后不一定立即執(zhí)行,也可以是緩刑?。ǎ?/p>



這一段代碼,的確是一進入游戲就運行的。但由于SetTime的作用,它的實際含義為:

  • 我決定,在未來的一個時間點(wave1刷新前95cs),發(fā)射一門炮


請記?。哼@個決定,是進入游戲的瞬間就完成了的。它只是過一段時間才執(zhí)行,看似有“延遲”,像是“wave1快要刷新了才發(fā)炮”,但其實發(fā)炮這件事早就定了,你把玉米炮全挖了它一樣會執(zhí)行(順便報個錯),不存在任何取消的方式。



正題——InsertOperation


理解了以上內(nèi)容后,就很容易理解InsertOperation的意義了。


它的作用是:將我內(nèi)部的所有代碼,推遲到最近一次SetTime設(shè)定的時間點執(zhí)行。



這個最近一次SetTime,是根據(jù)代碼運行的順序來的,也就是進入游戲的那一瞬間發(fā)生的事。


AvZ里許多函數(shù)都封裝了InsertOperation。比如,pao_operator.pao()實際內(nèi)容是這樣的:



有沒有看到那個熟悉的InsertOperation?


它的作用,就是讓紅框里所有的代碼,都等到最近一次SetTime設(shè)定的時間點再執(zhí)行,而非立刻執(zhí)行。


在你眼里,代碼是這樣的:


在電腦眼里,它其實是這樣的:


以上兩段完全等價。pao()函數(shù)的唯一作用,就是把這一大段東西(InsertOperation+一堆代碼)縮略一下。


其實pao也好,Card也好,各種常用鍵控函數(shù)底層都會用到InsertOperation。這也是理所當(dāng)然的——要不然所有操作都一上來就執(zhí)行了,還玩毛啊。


現(xiàn)在你知道了,為什么你可以一個SetTime后跟好多操作。



以上三個語句,都會在 (-95, 1) 這個時間點執(zhí)行。原因就在于,它們底層都用到了InsertOperation,而InsertOperation只看最近一次SetTime。因為這里只SetTime過一次,大家當(dāng)然就都共用 (-95, 1) 這個時間點咯。


你還知道了,為什么不SetTime直接用pao會翻車。



還是經(jīng)典12腳本,本來白框里是SetTime(-150, 20),也就是炮消珊瑚時機。


如果強行把這個SetTime去掉,會發(fā)生很奇怪的事…… 為什么?


原因在于,pao_operator.pao底層是InsertOperation,而InsertOperation永遠(yuǎn)會去找最近一次SetTime。在這里,就是上面那個循環(huán)里的最后一次SetTime:



這顯然不是我們想要的。但很可惜,SetTime就是認(rèn)這個死理。所以你的炸珊瑚炮會在 (300, 20) 這個謎の時間點發(fā)射,水路炮早就被啃光了,而你以為AvZ又出了bug怒錘鍵盤。



區(qū)分IQ和NIQ


所謂“IQ”,就是“In Queue”,指必須要配合SetTime使用的函數(shù)。操作在指定時間點進行。緩刑。


所謂“NIQ”,就是“Not In Queue”,指不需要配合SetTime使用的函數(shù)。操作立刻馬上執(zhí)行。


所有常規(guī)代碼都是NIQ。而IQ其實就是NIQ外面套了一層InsertOperation。


換句話說:IQ = InsertOperation + NIQ。


看個例子就懂了。AvZ里許多函數(shù)都分IQ和NIQ兩個版本(pao并沒有)。


我們看Card():



沒錯,你最喜歡的Card函數(shù),其實就是CardNotInQueue外面套了一層InsertOperation的皮…… 有沒有被騙了的感覺。Card這個函數(shù)并沒有任何實質(zhì)內(nèi)容。


ShowError當(dāng)然也是一回事啦:



總而言之,真正“干活”的代碼,都是NIQ。IQ函數(shù)只是方便你在SetTime后調(diào)用的工具人。


回到剛開始這個例子:



這一段代碼為什么不對,現(xiàn)在就很明顯了吧?


ShowError是AvZ官方函數(shù),內(nèi)部套了InsertOperation,所以它可以配合SetTime正確執(zhí)行。


但是GetSun()只是在讀取內(nèi)存啊親!它內(nèi)部才一行啊親!它當(dāng)然是立刻執(zhí)行的啊親!


解決方法自然就是把它丟進InsertOperation:



以上為正解。over。



你沒事吧?沒事別亂用IQ


眼尖的你可能發(fā)現(xiàn)了:“錯誤寫法”變?yōu)檎_寫法后,ShowError悄悄變成了ShowErrorNotInQueue:



解釋這件事并不難。


“錯誤寫法”里,我們試圖用【SetTime + 調(diào)用IQ函數(shù)】的一般套路,理應(yīng)用ShowError(雖然在GetSun上翻車了)。


正確寫法里,所有代碼都在InsertOperation內(nèi)部,而我們知道InsertOperation就是用來包裹NIQ的,所以理應(yīng)用ShowErrorNotInQueue。


可是有人就不服啊。他說,我就要IQ和NIQ反著用,會發(fā)生啥事?


CASE 1:我偏要在SetTime后用NIQ



這顯然是瞎折騰。NIQ函數(shù)就是一段普通的代碼,而普通代碼根本不鳥SetTime。它將在進入游戲的一瞬間立刻執(zhí)行,立刻輸出選卡前的陽光。



CASE 2:我偏要在InsertOperation里用IQ



相比之下,這個行為就非常重量級。


首先,AvZ是允許多重InsertOperation嵌套的。以上代碼,實際可以轉(zhuǎn)換為:



看上去,它就是犯了個蠢,賣了個萌,精靈球里又套了個精靈球,但好像沒啥實際影響?


錯!別忘了,InsertOperation永遠(yuǎn)會找上一個SetTime,這是死理。


對于第一個InsertOperation,它的上一個SetTime是(0, 11),沒毛病。


但對于第二個InsertOperation,由于它在第一個InsertOperation內(nèi)部,它會等到 (0, 11) 也就是wave11刷新這個時間點才執(zhí)行。


此時,AvZ腳本已運行完畢,因此它實際上會使用腳本里最后一個SetTime設(shè)定的時間點。


如果把無辜的炮消珊瑚加進來:


圖上的白色數(shù)字,是每行代碼的運行順序。其中,①、②、③、④是進入游戲的一瞬間運行的;⑤、⑥分別在各自InsertOperation設(shè)定的時間點運行。


不難看出,運行⑤時,最近一次SetTime其實是炮消珊瑚的時間點,也就是 (-150, 20)。


對電腦來說,它看到的是:



因而,這句輸出語句會一直等到 (-150, 20) 才執(zhí)行!你怎么等也等不到輸出,以為AvZ又出bug了然后怒砸鍵盤。


這個問題,應(yīng)該就是萌新亂用InsertOperation時最容易犯的錯誤了,也是很多人表示“無法理解InsertOperation”的根源。


它有三個解決方法:



1. 你沒事吧?沒事別亂用IQ


記住一句話:

IQ必須要配合SetTime用。

IQ必須要配合SetTime用。

IQ必須要配合SetTime用。


IQ函數(shù)的本質(zhì)是InsertOperation,而InsertOperation永遠(yuǎn)會去找上一個SetTime,這就是AvZ的死理。


因此,不用SetTime卻用InsertOperation的行為被稱作“裸奔”,踩香蕉皮滑到哪里是哪里,會造成一系列費解的bug。


除了InsertOperation,pao、Card等等函數(shù)也都可能“裸奔”,因為這些IQ函數(shù)在本質(zhì)上都使用的是InsertOperation。



在這個錯誤例子中,ShowError就是一個裸奔的IQ函數(shù),很輕易地就翻了車。



2. InsertOperation里先無腦SetNowTime()


SetNowTime()是一個鮮為人知卻非常好用的函數(shù)。


它的作用是:把當(dāng)前實際時間傳進SetTime。


再看上面那個例子:



加上SetNowTime后,腰也不酸了,腿也不痛了,代碼也正確執(zhí)行了。


我們知道,SetNowTime和ShowError一樣,都是在(0, 11)這個時間點才執(zhí)行。而SetNowTime會忠實地把當(dāng)前時間點傳進SetTime,供后續(xù)使用。


這樣一來,上面的代碼實際上就是先 SetTime(0, 11),然后再ShowError,完美解決“裸奔”問題。


總體而言,SetNowTime的確是個萬金油,因為它非常符合人類的自然邏輯。對于IQ函數(shù),它默認(rèn)讓它們在當(dāng)前時間點執(zhí)行,符合人類的預(yù)期;對于NIQ函數(shù),它沒有任何效果,不礙事。


當(dāng)然,如果某個函數(shù)有NIQ版本,那還是建議你直接用NIQ,而非SetNowTime + IQ…… 其實兩者沒啥大區(qū)別,就是后者看著略蠢。。。



3. 用InsertGuard


這個是AvZ官方推薦的方式,效果和上一種類似,但是略難理解。


寫出來是這樣的:



ig是變量名,取任何名字都行。


它的作用是:在當(dāng)前大括號括起的段落里,使所有InsertOperation失去原本效果,直接運行。那個false就代表失效,如果是true的話就是讓它重新生效。


過多的就不介紹了,如果你覺得難以理解的話,先試試看前兩種辦法吧。



一些理所當(dāng)然的補充...


理解了以上內(nèi)容后,以下幾點都是顯然易證自然成立的。僅作補充用意。



① 我要在XX時刻判斷OO僵尸狀態(tài),怎么寫?


“判斷場上僵尸”,其實就是讀內(nèi)存,一個for循環(huán)里來幾句if。這些都是普通代碼,也就是NIQ代碼,因此需要寫在InsertOperation里(你總不想一進游戲就判斷吧,啥僵尸都沒有呢)。


在22年6月之前的AvZ里,寫法是這樣的:



zombieTotal是僵尸總數(shù),zombieArray是僵尸數(shù)組,然后isDisappeared() 和 isDead() 檢查僵尸是否存在,最后檢查type是否為紅眼…… 這些你都可以在 pvzstruct.h 里搜到,可自行搜索。


重申:以上代碼需放進InsertOperation里。


別忘了,如果在這里要執(zhí)行pao啊Card之類的操作,記得SetNowTime或者InsertGuard,不理解的話請重讀前面一章。


22年6月版本起,你可以直接用“filter”功能:



AliveFilter自動遍歷所有還活著的生物。AliveFilter<Zombie>就是遍歷所有“活著”的僵尸。


同樣,以上代碼需放進InsertOperation里。


因為本文的重點是學(xué)會使用InsertOperation,所以這里就不更多說明怎么讀內(nèi)存了~ 如果有很多人好奇的話我可能會另寫一篇文章詳解。



② InsertTimeOperation是什么玩意?


直接上源碼:


template什么的看不懂可以無視,你只需要關(guān)注里面那個“InsertOperation”。


是的,“InsertTimeOperation”就是InsertOperation的套皮版。它額外接受兩個參數(shù)(time和wave),然后先 SetTime(time, wave),再正常執(zhí)行InsertOperation。


說到底,因為SetTime和InsertOperation必定要一起用(不然就裸奔了),所以AvZ干脆再提供了一個函數(shù),讓你可以把它們直接寫在一起。



這兩段代碼完全是一回事。


簡化了很多嗎……?好像也就那樣(


需要注意的是,InsertTimeOperation內(nèi)部自帶SetTime(可以再去看眼源碼,就在上面),這個SetTime當(dāng)然也是算在“最近一次SetTime”里的!好處是媽媽再也不擔(dān)心我忘了SetTime了,壞處是它是隱藏性SetTime,看代碼的時候容易忘了還有這回事,總之各有利弊吧~ 我覺得只用InsertOperation也挺好的。


請你不要問:如果SetTime和InsertOperation總要一起用,為啥不能只保留InsertTimeOperation?親,如果這樣的話,不就沒法SetTime一次InsertOperation多次了。。


下面這個寫法就不成立了:



沒人愿意把 -95, 1 寫三遍吧(




以上就是所有關(guān)于AvZ里IQ/NIQ的事啦~


其實這個事情本身沒有那么復(fù)雜,但可能是原先的教程有點難懂吧,有些人不太理解,那么希望這篇文章能幫到你。


一個小tip:AvZ目錄里inc文件夾是AvZ官方函數(shù)的頭文件,里面所有In Queue的函數(shù)都在注釋里標(biāo)明了,而其它的則是Not In Queue,你可以自行查看感受一下兩者的區(qū)別喔。




解釋一下AvZ的IQ/NIQ的評論 (共 條)

分享到微博請遵守國家法律
武宣县| 沙湾县| 留坝县| 河津市| 崇阳县| 西乌珠穆沁旗| 凤台县| 樟树市| 宝山区| 贡嘎县| 修文县| 江门市| 江西省| 沽源县| 云龙县| 利津县| 宣武区| 甘谷县| 来凤县| 敖汉旗| 筠连县| 尼木县| 韶关市| 城市| 广元市| 新竹市| 鹰潭市| 昌都县| 马边| 南投市| 勃利县| 崇阳县| 峨眉山市| 建始县| 广河县| 安义县| 平潭县| 常宁市| 南雄市| 东山县| 福海县|