Besiege Guide

【中文指南】關卡編輯器: SetGet v6 如何讀寫變數 for Besiege

【中文指南】關卡編輯器: SetGet v6 如何讀寫變數

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了)

邏輯總覽

現在總和上述的邏輯事件:

當 變數(區域) “i >0”
 變數 “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”

寫入區
當 變數(區域) “C1 >37”
  停用
   變數 “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”
進位區
當 變數(區域) “limit >1443”
 變數 “i -1”, “SetGet v6”

當 變數(區域) “limit <-1443”
 變數 “i +1”, “SetGet v6”

限制區
當 變數(區域) “DG1 >0”
 變數 “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 >0”
  停用
   變數 “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

邏輯範本:SetGet v6

[link]
SteamSolo.com