Overview
SetGet v6 是一個能讓使用者輕鬆輸入或輸出變數的變數系統。我允許任何人依教育用途去翻譯、改寫本指南至任何形式。本指南所使用的用詞參考了CCC與Anvil共同翻譯的《圍城》台灣繁體中文語言套件。///2021年(民國110年)3月12號更新後有三個變數名稱被改變了,詳見SetGet v6。
前言
我們能用事件「變數」來寫入(也等於儲存)一個變數。但讀取一個變數則較麻煩,因為Besiege裡並沒有「取變數」這個事件,這就是為甚麼SetGet被創造出來了,它被設計得能輕鬆讀取變數。事實上讀取變數並非只有一種方法,SetGet v6只是第一個被完善了的型號而已。舉例來說,SetGet Bv1是一種用與 v6版完全不同的計算法來讀寫變數的邏輯系統。
如果你不想讀我長篇大論地解釋SetGet v6的運作原理的話,你可以直接到「操作」的章節尋找讀寫變數的方法,或者到「進位及限制器」的「限制器」了解如何用不同的方法設計變數的上限限制器。
若對本文有任何疑問或指南內容有我未注意到的錯誤,可以到留言區或Besiege官方Discord來找我:Official Besiege Discord[discord.gg](Nice Name#2895)
輸入及輸出
要在Besiege裡讀寫一個變數,SetGet v6的辦法是「迴圈」,也就是偵測所儲存的變數是否大於0:如果是,迴一次使該變數減去「1」,並重複迴圈至到該變數歸零。這樣一來迴圈的次數便會等於所儲存的變數。
示例(這裏給予變數名為DG1):
當 變數 “DG1 >0”
(以某方式輸出一次)
變數 “DG1 -1”
(通常,「以某方式輸出一次」是指輸出「變數」、「關卡進度」」或「座標變換」,例如當我要利用SetGet所記錄的變數來移動一個物件時,我就會使用「座標變換」來做為輸出方法。)
但是上述讀取變數方法有一個問題,這種讀取方法會在讀取值時消耗掉變數本身,這樣一來這個變數也就只能被取一次而已。為了彌補這個被消耗掉的變數,我們可以在讀取變數的同時輸出一份副本a,這個副本a的值將會跟正本一模一樣,並在正本被消耗掉之後被讀取、消耗並再次輸出一個副本b,而這個副本b即成為了正本,以此循環。
也就是說剛剛的邏輯閘會變成:
當 變數 “DG1 >0”
(以某方式輸出一次)
停用 <──註*1
變數 “dg1 +1” <──副本a
啟用
變數 “DG1 -1”當 變數 “DG1 =0”
變數 “dg1 +0”當 變數 “dg1 >0”
停用
變數 “DG1 +1” <──副本b
啟用
變數 “dg1 -1”
///
註*1:啟用與停用能決定事件、觸發事件能否被執行或觸發,也就是說若在輸出副本的前一刻進入「停用」狀態,並在輸出副本後的瞬間切回「啟用」狀態,這樣就能把輸出給隱藏起來、不觸發任何觸發事件。不這麼做的話必會產生無限迴圈。
進位及限制器
這段看不懂也沒關係,因為在大多時候的操作上是不需要動到進位系統和限制器的。
-
進位
這遊戲有著一個除錯系統,任何瞬間重複超過37次的邏輯迴圈會被強制停止(會顯示『偵測到無限迴路!』),因此上述邏輯只能讀取37(含)以內的值。
為了克服這個問題,一個38制進位系統是必須的,這個進位系統將在一值超過37時自動進位第38個值至下一單位,這個單位就叫做DG1(Digit Group #1)。
但是,DG1在被寫入時是無法被同時讀取的,因為變數DG1在被寫入時整個系統是處於停用狀態的。這樣一來就必須再新增一個變數「C1(進位carrier #1)」,一個專門協助「DG1」進位的變數:當 變數 “C1 >37”
停用
變數 “DG2 +1”
變數 “DG1 -38”
啟用
變數 “C1 -38”這樣我們在解決了「讀取」上限問題的同時也避免了在進位時意外觸發DG1的讀取閘。
個 -
限制器
如果沒有限制器的話,一旦C1、DG1、DG2的值都到達38時就會導致故障,因此我們會在輸入區另增一個變數「limit」,當這個變數到達臨界值(註*2)的時候便會抵消輸入,使得系統內的變數無法超過臨界值。限制器位於輸入區最上層:
當 變數(區域) “i >0”
變數 “limit +1” <──限制器
停用
變數 “DG1 +1”
啟用
變數 “C1 +1”
變數 “i -1”而限制器有兩種限制方式,一是讓變數保持不超過臨界值、二是當變數超過臨界值時歸零:
-
不超過臨界值
你可以如此編寫這種限制器:
當 變數 “limit >1443”
變數 “i -1”當 變數 “limit <-1443”
變數 “i +1”基本上就是變數「limit」一旦超過±1443就會被抵銷。
-
超過臨界值時歸零
在某些情況下玩家或許會希望變數能夠自動在超過臨界值時歸零,在此以100為臨界值示範,變數會在到達101(超過100)時歸零。但請記得,SetGet v6是一個38進位制的系統,別忘了以38進位制的數學規則來編寫歸零限制器:
當 變數 “limit >100” <──當變數大於100
停用
變數 “DG2 -2” <──100減去76(註*3)
啟用
變數 “i -24” <──再減去24(含限制器、進位變數C1、變數DG1)你會發現DG2在隱藏的情況下被減去了2、且負值輸入被執行了24次(共減去100),這是因為我們不能直接用下列邏輯:
變數 “i -100”
這會觸發無限迴路偵錯,不可行,所以必須借助DG2來歸零。
-
///
註*2:
SetGet v6的臨界值是「±1443」。臨界值的等比數列和公式解證明如下:
(c =最大值, a =37, r =38, n =位數數量)
|c| = a(1 -r^n) /(1 -r)
|c| = 37(1 -38^n) /(1-38)
|c| = 37(1 -38^n) /-37
|c| = -(1 -38^n)
|c| = 38^n -1
c = ±38^n -1
當位數數量等於2 時,c 就會等於±1443。
或者你也可以用暴力計算法:
|c| = 37 +37*38 +37*38² +37*38³…. +37*38ⁿ
註*3:
SetGet v6是一個38進位制的系統,而DG2又是DG1的下一個單位,因此可知單個DG2等於數字38,2個DG2也就等於數字76。
操作
SetGet v6能儲存及讀取,兩者皆只需一條邏輯事件就能操作。而當要輸出變數時我們還要知道如何編輯輸出。
-
儲存
需要「儲存」值時使用邏輯:
變數 “i +1”
以SetGet v6來說,單次輸入變數 i 的最大值是「±37」,若要輸入更大的值就必須使用其他方式,詳見註*4。
在介紹進位系統的地方有提到,由於變數C1只是進位輔助而已,它的值必須保持跟DG1一模一樣,因此在輸入值給系統時必須把它們兩個擺一起,只是DG1的輸入會被隱藏:
當 變數 “i >0” (變數「i」代表「input (輸入)」)
變數 “limit +1”
停用
變數 “DG1 +1”
啟用
變數 “C1 +1” (放在「停用」和「limit」之中也可以)
變數 “i -1” -
讀取
需要「讀取」值時使用邏輯:
變數 “DG1 +0”
「+0」基本上就是讓DG1的觸發條件重新檢查一遍當下的變數是多少。
在讀取區內(詳見「邏輯總覽」)的迴圈中,最上層都有預設輸出:
變數 “o +1”
在範本中,這變數「o」的預設輸出共有「+1」、「-1」、「+38」或「-38」四個輸出事件,若要修改輸出則必須將四個輸出事件一同修改。
舉「座標變換」為例,若要將寫入SetGet的變數「i」轉化成「物件A」在X軸上的移動距離,你可以把「+1」預設的編輯輸出改成:
座標變換 “x: 1”, 選取 “物件A”
把「-1」預設的編輯輸出改成:
座標變換 “x: -1”, 選取 “物件A”
把「+37」預設的編輯輸出改成:
座標變換 “x: 38”, 選取 “物件A”
把「-37」預設的編輯輸出改成:
座標變換 “x: -38”, 選取 “物件A”
這麼一來假設寫入的變數是「i = 100」並啟動SetGet,物件A在X軸上的座標會被移動100單位。同理可用於「旋轉」。
///
註*4:若要一次性的輸入大於正負37的值,你必須使用兩個或多個「變數事件」。或者你可以使用IO系統(建議用v2),它讓你只需用上一條變數事件就能輸入無限大的值,但前提是你知道你在做甚麼以及該怎麼做。或甚至就別用SetGet v6了,「B版SetGet」的SetGet Bv1基本上功能與v6一樣,雖然輸入、輸出的方式有些不同,但Bv1用一條變數事件就能直接輸入最大正負52059的變數了(無限大也不是不可能,但很少需要那麼大的數字就預設52095了)。
邏輯總覽
現在總和上述的邏輯事件:
變數 “limit +1”, “SetGet v6”
停用
變數 “DG1 +1”, “SetGet v6”
啟用
變數 “C1 +1”, “SetGet v6”
變數 “i -1”, “SetGet v6”
當 變數(區域) “i <0”
變數 “limit -1”, “SetGet v6”
停用
變數 “DG1 -1”, “SetGet v6”
啟用
變數 “C1 -1”, “SetGet v6”
變數 “i +1”, “SetGet v6”
停用
變數 “DG2 +1”, “SetGet v6”
變數 “DG1 -38”, “SetGet v6”
啟用
變數 “C1 -38”, “SetGet v6”
當 變數(區域) “C1 <-37”
停用
變數 “DG2 -1”, “SetGet v6”
變數 “DG1 +38”, “SetGet v6”
啟用
變數 “C1 +38”, “SetGet v6”
變數 “i -1”, “SetGet v6”
當 變數(區域) “limit <-1443”
變數 “i +1”, “SetGet v6”
變數 “o +1”
停用
變數 “dg1 +1”, “SetGet v6”
啟用
變數 “DG1 -1”, “SetGet v6”
當 變數(區域) “DG1 <0”
變數 “o -1”
停用
變數 “dg1 -1”, “SetGet v6”
啟用
變數 “DG1 +1”, “SetGet v6”
當 變數(區域) “DG1 =0”
變數 “DG2 +0”, “SetGet v6”
當 變數(區域) “DG2 >0”
變數 “o +38”
停用
變數 “dg2 +1”, “SetGet v6”
啟用
變數 “DG2 -1”, “SetGet v6”
當 變數(區域) “DG2 <0”
變數 “o -38”
停用
變數 “dg2 -1”, “SetGet v6”
啟用
變數 “DG2 +1”, “SetGet v6”
當 變數(區域) “DG2 =0”
變數 “dg1 +0”, “SetGet v6”
停用
變數 “DG1 +1”, “SetGet v6”
啟用
變數 “dg1 -1”, “SetGet v6”
當 變數(區域) “dg1 <0”
停用
變數 “DG1 -1”, “SetGet v6”
啟用
變數 “dg1 +1”, “SetGet v6”
當 變數(區域) “dg1 =0”
變數 “dg2 +0”, “SetGet v6”
當 變數(區域) “dg2 >0”
停用
變數 “DG2 +1”, “SetGet v6”
啟用
變數 “dg2 -1”, “SetGet v6”
當 變數(區域) “dg2 <0”
停用
變數 “DG2 -1”, “SetGet v6”
啟用
變數 “dg2 +1”, “SetGet v6”
當 變數(區域) “dg2 =0”
(系統結束或連結其它事件)
後記
所以… 這就是第六代SetGet,其實一開始的SetGet v1因為是十進制的,所以容量遠不及38進制的v2。SetGet v1、v2、v3、v4都是由三個物件所組成的,v5用了兩個,而今天寫的則是目前最精簡的v6,只需要一個物件就夠了。
有趣的是v1當初是為了瞬間轉正Minecraft的人物的頭才被我寫出來的,如果當初沒有做那張地圖的話或許就沒有今天的v6了吧ww