創作內容

7 GP

[RMXP RGSS] 改造基礎知識 (最後更新20210116)

作者:未来ずら│2014-01-28 18:56:28│巴幣:1,012│人氣:2947
學腳本啊...我以前都嘛很不負責任的叫人去看電子說明書,那玩意對程式概念完全沒有的人來說就是個勸退用工具,而這篇的目標,就是建立看懂說明書的能力
看懂說明書很重要,因為就算到現在要寫腳本還是電子說明書開在旁邊需要再查,他就是個字典般的存在

以下內容為個人認為在寫RGSS時「只要知道這些,就能解決大多數的腳本問題」
參考了6R的RMVX說明+Ruby手冊的整合檔

某種程度上這算筆記,而且是需要時間來慢慢啃的東西

另外如果是沒碰過程式、而且也沒做過遊戲的經驗,請先別看這篇
先找個開源專案熟悉事件用法跟程式邏輯,像是小風大的勇者物語
不然整篇下來相信你只看得懂 a = 1


下列基本上朝「讓人會用」的方向解釋
原理的話...畢竟俺也不是很清楚,懂那些也只是更了解什麼叫程式,對使用上沒太大影響
若有求知欲,就自行鑽研吧

另外XP~VA的電子說明書也有基礎程式的教學,有時間看一下,會很有幫助
(MV那個根本放生使用者)

用語

類 (Class)

class Xxxx
(內容)
end
物件設計圖,寫在腳本當中那堆class開頭end結尾的東西就是一個一個的
裡面充滿各種變數與行為定義,做成物件後,該物件就能使用那些行為(也就是方法)

什麼時候該建立class呢?
當要處理的數據大到無法用一、兩個變數完成,或者會很多相同結構的數據時就可以考慮
比方說原本想用名稱(name)、年齡(age)、性別(sex)3個變數代表"人",
那在同個作用域內,有2個人就需要6個變數、有3個人就需要9個變數,而且要處理行為時(比方說改名字)也要寫條件分歧判斷是哪個變數要增加
不僅難管理,而且一定要取不同名稱區別這些變數,還要很清楚這個變數到底代表什麼
這時就可以把他們整理成class、然後生成物件
之後操作時不僅行數少,也能清楚區分這些變數和行為就是"人A"所擁有而不是"人B"

把變數寫在一起的情況:
@name1 = "小明"
@age1 = 16
@sex1 = "男"
@name2 = "小華"
@age2 = 18
@sex2 = "男"

# 定義改名字的方法
def change_name(who, new_name)
case who
when "小明"
@name1 = new_name
when "小華"
@name2 = new_name
end
end

# 把小明的名字改成大明
change_name(@name1, "大明")
# 看看是否有改名
p @name1 # <=大明


用class區分的情況
# 定義"人"的class
class Person
# 公開變數
attr_reader :name # 這樣做就可以用(物件.name來知道這個物件的@name值)
# 初始化
def initialize(name, age, sex)
@name = name
@age = age
@sex = sex
end
# 定義改名字的方法
def change_name(new_name)
@name = new_name
end
end

# 做出兩個人
person1 = Person.new("小明", 16, "男")
person2 = Person.new("小華", 18, "男")

# 更改小明的名稱
person1.change_name("大明")

# 看看是否有改名
p person1.name # <=大明

或許這樣還沒感覺到製作class的便利性,那麼你可以試著追加人數看看差別



父類 (SuperClass)
class 子類 < 父類
如果想讓某對像特定多出幾樣動作,就可以額外建立一個子類追加
由 Game_Battler 分出的 Game_Actor 和 Game_Enemy 就是如此

子類物件可以使用父類已定義方法,但父類無法使用子類額外定義的方法
想想也是理所當然的事



實例/實體(Instance)
類.new
叫實體比較好懂,以下叫實體
在進行「xxx.new」後產生的物件,有些東西還沒進行new是不會出現的(比方說實體變數、繼承父類)

RGSS處理上執行new的時候會一併執行 initialize 方法,一般都會把初始化要做的事寫在這

物件/對象 (Object)
後者中國用語
可以代表一切事物,簡單的數字、字串、乃至於其他阿貓阿狗做成的實體,甚至Class本身也是
很多時候會把他跟實體講在一起


變數(Variable)
a = xxx
這篇釋放解釋有稍微提到,總之物件需要活動空間,
變數就是負責向電腦記憶體提出空間要求。
不過這種深奧的計算機概論不用懂沒關係(我也不懂,上面是看wiki)
在RGSS中只要知道它是一種物件的識別標籤就好。
同個物件可以貼上各式各樣的變數標籤,物件也至少要有一個變數才能操作它
所以雖然說是操作物件,但實際上都是:
代表某物件的變數.方法
例如:actor1.attack
這樣

因為內容物是隨時在變的,所以叫變數

另外就是,腳本中的變數不像事件的公共變數只能代入單純的數字
公共變數很常做的一件事就是記憶另一個變數的數字,但如果直接套用到其他比較複雜的物件會有很大的問題
比方說:
a = [100,200,300,400,500]
b = a # b 代入 a
a[0] = 0 # a的第0項,也就是100那欄代入0
p b[0] # 查看b的第0項,也跟著變0了
如果代入對象結構不是像數字那麼單純,那只會代入對象的位址,而不是進行複製的動作
b = a只代表之後可以從 a 或 b 變數來操作同一個Array物件

那...我要記憶這些值怎麼辦?
只能仿照結構代入最單純的值:
b = []
a.each {|obj| b.push(obj) } # 照順序代入每項的值

假設那個Array物件裡面裝的是其他物件,也是一樣,
用最上面的Person類假設要記憶每個人的姓名:
a = [Person.new("小明"), Person.new("小華"), Person.new("小美") ]
b = []
a.each {|obj| b.push(obj.name) } # 照順序代入每項物件的name變數

有在翻說明書的或許會問不能用dup或clone嗎?也是可以,不過效果只能複製一層,也就是和這個一樣:
a.each {|obj| b.push(obj) }

要先想清楚到底要記憶什麼



另外用電子說明書看內部類的方法時,通常會提到該方法有無破壞性,如果有,就是直接變更原始物件,相反的話,得到的值會是一個新物件(ex:A + B = C)


沒變數不能操作物件的示範
總之先隨便抓個內建的Class生成:
Game_Battler.new
來,下一步,查看它的object_id (p 物件.object_id)

.....沒辦法對不對,我也不知道要怎麼辦
不要跟我說「p Game_Battler.object_id」 就好,這樣是看那個Class的object_id,不是你new出來的實體

這樣懂了吧,一個物件至少要一個對應變數

※Ruby其實有辦法追蹤,但那個太深入先不講


方法(Method)
def xxx(參數1,參數2...)
(內容)
end
把經常反覆使用的一套計算式給一個名稱方便使用
即物件的行為、可以做什麼,用事件比喻就是屬於那個Class的公共事件


只要用下面的方式就能讓物件進行已定義的某件事:
物件.方法名稱(參數1,參數2...)
定義名稱如果有參數,調用時就必須丟參數進去
因為不是所有運算都能靠本身已有的數值完成,
有時候就必須定幾個參數把別人的數值丟進去運算

另外說明書有時候會看到這樣:
方法名稱(參數1,參數2[, 參數3])
被 [] 框起來的部分為可選參數,即可以省略不寫
一般來說這些參數都會講預設值是什麼,省略時就是使用預設值


另外雖然這個不重要,不過方法名稱可以用英文以外的文字,用中文命名也是No problem
看過有遊戲方法名稱都是日文的


如果調用的方法是沒定義的會出現NoMethodError
錯誤訊息的白話翻譯就是:沒這方法,出錯啦


再定義(Override / Redefinition)
Class People
# 定義一個名叫say_hello的方法
def say_hello
p "Hi"
end
# 對say_hello再定義
def say_hello
p "Hey"
end
end
同個Class中只允許一名稱一方法,若定義兩個以上的同名方法,後者將會取代前者
a = People.new # 作成對像
a.say_hello # 出現訊息框顯示Hey,不會出現Hi

再定義是腳本衝突的主因,可能是方法內容更動、所需參數更動等等導致調用出錯
ArgumentError(所需參數數量有誤)NoMethodError(調用方法不存在) 都是很常出現的錯誤,這兩個錯誤其實比對一下腳本間的差異,補個兩、三行搞不好就能解決
好好的腳本如果因為這樣放棄掉不是很可惜嗎?


注意,如果是對已定義過的 Class 進行再定義,
會判斷成給該 Class 追加內容(不然每次都要把整個class內容照搬不就煩死,衝突更不用講 )


初始化(Initialize)

生成實體(類.new,之後不再提)的動作,也是生成時會自動調用的方法(如果有定義的話)
因此在 .new 後不用再特地使用「該實體.initialize 」
進行各種變宣告通常為initialize在做的事

注意只有生成實體這動作才會自動調用 initialize

宣告變數
基本,在看到這篇之前應該其他教學也看到爛了,就簡單的帶過
只要遵守命名規則就能宣告,宣告變數需要注意作用域,避免撞名

局部變數:
a = 1
只有變數名,前面沒任何符號,只會維持到方法(同一層)結束
(如果寫在最外層,就會一直存在)

實體變數:
@a = 1
名稱前面有@記號,在物件消失前都能使用,物件需要長期記憶特定數值時用
最常用的變數

事件 來說它就是 獨立開關,獨立於物件自己,不影響別人也不會被影響


※類變數:
@@a = 1 # <= 這不是表符,來先跟我說三次
這個比較冷門,不過部分內建腳本有用到。前面有兩個「@」
和實體變數的差別是:同個Class生成的物件,類變數是共用的

就是說假設現在有兩個Game_Actor的實體,而Game_Actor有定義一個 @@a 的類變數
只要其中一個改了 @@a 的內容,另一個實體也會被影響
(想想看,如果做個類變數來代表角色血量會發生什麼事呢?)

總之可以當作相同Class實體們的全域變數


全域變
$a = 1
名稱前面有$記號,可在任何時機宣告(遊戲途中也行)
除非關閉遊戲否則不會消失,即使按下F12也是。

事件 來說它就是 事件的公共開關/變數
所有事件都可利用,也因此會影響所有用到它的事件


常數:
A = 1
名稱是大寫英文開頭的變數,用來統一指定某部份的數值(比方說視窗寬度)
當有很多處需要相同的數值時就會用到,常數在生成後就不能變更了,也無法寫在方法中
在遊戲中要調用就使用「常數所在Class::常數」


偽變數self:
代表物件自己,正確來說是正在執行這個方法的物件
因為物件在自己所屬Class中調用其他方法時可以像這樣調用:
refresh
這和局部變數的宣告很像,後面加個 = xxx 就更像了

所以自身的有些計算需要使用「self.自身方法」才可以,
比方說修改可見狀態:
visible = false
self.visible = false
第一行程式會當作你宣告一個名為 visible 的局部變數,值為false
得用第二行的方式修改才行
總之就是避免誤判



常用對像
下列提到的是個人在寫腳本時最常使用的幾種對像,
這些對象能使用哪些方法請看電子說明書。


真偽判斷(true / false)
false是偽,就像事件開關的off
true是真,就像事件開關的on

和事件開關不同的是,除非是比較結果或是強制設定
如果只是單獨判斷一個變數「if 變數...end」只要有值存在,結果就是true


字串(String)
a = "abc"
用兩個「"」或「'」包起來部分就會變成字串

字串的作用是讓Bitmap能用描繪文字(draw_text)的方法將字串物件顯示在遊戲畫面
換句話說要讓變數顯示在畫面前要先轉化為字串

但請不要作出直接把變數名稱用「"」包起來的蠢事,我們要輸出的是變數內容、不是名稱
要把內容轉成字串可以用「to_s」(如果它不是字串物件、而且有to_s方法)
或是使用 字串插值/內嵌表達式(string interpolation,後者中ㄍ...) :
"#{a}"
注意內嵌表達式一定要用「"」來包,用「'」會失效


陣列/數組(Array)
a = ["abc","def","ghi"]
數組是中國用語,但我已經講習慣了

當有一系列物件需要有系統的管理就能用數組
每一格當中都能放置一個物件,當然也可以再放另一個數組

數組裡面的物件被稱為元素(element)
取用時只要知道物件放在哪個位置(index)就好,以上面為例就是:
a[0] # "abc"
a[1] # "def"
a[2] # "ghi"
(注意:index起始值為 0)


如果調用的物件也是個數組,然後又要取用其中一個物件,就是繼續追加取用位置而已:
a = [[1,2,3], "def", "ghi"]

a[0][1] # 調用[1,2,3]中的「數字2」
當然,越多層就會越亂,這時建議用下面的 Hash 會比較清楚



雜湊/哈希表(Hash)

一樣是之前提到的東西,另一種的數組,使用例:
person1 = {
:name => "小明",
:age => 13,
:sex => "男"
}

p person1[:name] # <=顯示「小明」
當你覺得想幫index定名稱、這樣比較好作業的時候就用Hash吧

範例中前面加冒號的東西是符號(symbol)物件,下面會講


Sprite、Bitmap
一樣見這篇最後

視口(Viewport)
中國用語
既然講到Sprite就順便說一下
腳本的Sprite說明可以在類方法的地方看到:

生成 Sprite 對象。必須要指定對應的視口

......這翻譯是
正確說明是:如果需要的話可指定對應的視口
(原文:必要に応じてビューポート (Viewport) を指定します。)
紅字部分直接扔google翻譯就行了

如果是必要,那為什麼省略視口參數卻不會出現 ArgumentError 呢?這樣肯定很奇怪啊
唉,人有失神馬有亂蹄...

咳好,那什麼是視口?
簡單說就是另外設一個螢幕大小
比方說做一個(0,0,320,160)的viewport物件
如果Sprite物件和它對應,那麼超過這範圍的圖像會顯示不出來

內建戰鬥,敵方和場地用的@viewport1高度就被砍半了,
所以要把戰鬥場地改成滿版會發現「咦?我明明放了640x480的圖怎麼下面還是黑的?」
因為viewport高度沒改


可惜的是 Viewport 只能設定矩形,沒辦法做斜的,想做成像UL的必殺技cut in應該沒辦法

不要跟我說一張一張弄,一招如果20張、四招就要80張,再乘上角色數...開什麼玩笑
欸等等,我沒說我要用RM搞UL啊
多妮讓我舔

如果有誰會寫斜向viewport,我會很感謝你


視窗(Window)
RGSS新增
為了做UI而特化的Class,由許多Sprite構成,並且已弄好背景圖
能直接產生視窗是很方便,但因為結構已經寫死了,
所以顯示內容的「self.contents」必定要比視窗本身小32像素,不然會出現箭頭
看需求決定要用 Window 還是 Sprite


範圍(Range)
0..5 # 0~5
0...10 # 0~9
通常用在循環處理或條件分歧
如範例所示,有兩個點和三個點的差別,為什麼要這麼分我也不知道

符號 (Symbol)
「:」開頭的值,在VX ACE大量使用

任何物件在建立時會隨機分配一個識別id代表不同物件(可用object_id查看),即使內容看起來一致。就好比兩個同名同姓同長相的人,但還是不同的兩個個體
但符號物件只要名稱相同就會視作是相同物件
ex:
a = :"abc"
b = :"abc"
p a.object_id, b.object_id # 兩個物件同ID

c = "abc"
d = "abc"
p c.object_id, d.object_id # 兩個物件不同ID
執行腳本後會看到彈出兩次視窗,第一次兩個數值相同,第二次則不同

已被定義過的符號名稱會被保存直到遊戲結束,可用Symbol.all_symbols查看
如果只是需要一個判斷用的標籤(比方說Hash的key),就可以使用符號物件節省資源

因為目前腳本有需求,所以特別提
若專案需要積極的處理Hash,這個會很有幫助
不過因為符號的表達式到VX ACE才有上色,VX以前的版本會有點辨識上的麻煩

數字(Numeric)
內裏定義「數字對像」的基礎方法
數字對像就是1、2、3...這種整數或3.1415926...這種小數


好,重點是Numeric的子類(Integer、Bignum、Fixnum、Float)和上面講的Symbol有個共通點:

無法使用.new做成實體

也就是他們的 物件ID 是唯一的,對應到的永遠是相同的值(一個數字1...就只是個數字1)

ex:
a = ""
b = ""
c = ""
p a.object_id, b.object_id, c.object_id
→ 生成三個「不同的」空字串物件,由a、b、c三個變數代入

a = 1
b = 1
c = 1
p a.object_id, b.object_id, c.object_id
→ a、b、c三個變數代入「同樣的」數字1物件


debug時,有時候會需要由物件id來判斷自己到底有沒有做對(改錯物件之類的)


另外為了省資源,可以先把某些容易生成的實體(字串、數組)代入一個變數
像字串,常會用來進行比較 (ex:actor.name == "阿爾西斯")
若先 「@name = "阿爾西斯"」 、判斷改成 「actor.name == @name」
能有類似這樣的做法會比較好
不然每次判斷「 actor.name == "阿爾西斯"」的話,都會另外生成一個「"阿爾西斯"」的字串物件



顏色(Color)、色調(Tone)
a = Color.new(紅, 綠, 藍[, 不透明度])
a = Tone.new(紅, 綠, 藍[, 灰階程度])
# 用 "[]" 框起來的部分為可選參數,即可以省略
RGSS新增
兩個都是控制色彩的類,但是Color的三色範圍是0~255,Tone的範圍則是-255~255
想臨時對遊戲圖像進行色彩變化就要使用它們(會有對應變數可代入)



控制結構

if 條件分歧
if 條件1
(內容)
elsif 條件2
(不符合條件1,但符合條件2的內容)
elsif 條件3
(不符合條件1和2,但符合條件3的內容)
else
(除此以外的內容)
end
和事件大致上一樣,只差事件沒有「不滿足條件A,但滿足條件B」的設定
只能一直疊在else裏面,分歧多一點的後面就看不到內容了

else 和 elsif 可省略


unless 條件分歧
if 分歧的顛倒版,「如果不是xxx的情況下 」
我個人很少用這個,就算要判定 false 的情況大多是用「 if !(a==b)」
加個驚嘆號就能判定相反狀況了



if、unless修飾符
如果分歧內容只要一行,可以簡化成如下的方式
a = 5 if a < 5


case
case a
when 0..5 # a的值為0~5
(內容)
when 6...10 # a的值為6~9 (注意,範圍表示多了一個「.」)
(內容)
else
(除此之外的內容)
end
只判斷某變數,當某變數符合when的條件就執行內容
缺點是沒辦法用複合條件(oo and xx...)


for循環
for a in [1,2,3]
(內容)
end
指定一個範圍和一個局部變數開始運算,運算次數就是指定的範圍
其中可用 next 跳過這次運算,或者用 break 結束整個迴圈

例子中因為數組有3個單元,所以算3次,局部變數a會分別代入數組的1、2、3
你也可以無視那些變數只當作計數器使用(但Ruby其實可以用times方法)



返回(return)

初期讓我很頭大的東西,從字面上很難理解是什麼
簡單說它的作用就是「中斷方法」,用事件指令講就是「中斷事件處理
名字的由來我也是心血來潮看了C語言教學才知道,不過太佔篇幅,就略過吧

必要時可以在return後面給一個值,讓它作為方法的「返回值」
(方法其實就是個計算式,最後會有個計算結果)

說明書上寫「返回OO」可以理解成「從某方法取得OO這個計算結果」
大概就是這樣,另外因為 Ruby 的特性,會自動將方法的最後一行當作返回值
所以在一些場合可以省略用 return 指定返回值

另外用return時,如果後面沒指定數值則返回值是 nil
def abc
var = "abc"
end

def abc2
var = "abc"
var2 ="cba"
end

def abc3
return 123
var = "abc"
end
p abc, abc2, abc3
p出來的結果:
abc得到 "abc"
abc2則被後來的 "cba" 取代了
abc3一開始用了return 123,所以到這裡就停了,並且得到指定的數字 123


至於在 RM 中的用法,
可以參考一下 Game_Battler 及它的子類看怎麼定義 HP、SP 的


常用方法

p、print (VX ACE為msgbox、msgbox_p)

p 物件, 物件2, 物件3....
把物件內容輸出,並彈出訊息框顯示
基本上是除錯時才會用到的功能,畢竟遊戲中突然冒出訊息框很突兀

大部分用在兩種場合:
查看物件狀況(有無被生成、返回值有沒有錯)
確認方法有沒有運行到這裡 (如果沒有就看不到訊息框了)

所以常常在說,p看看ooo變數,p看看p看看

p~~~~~~~

除非不得已否則盡量不要把p腳本放在定期處理(每畫格執行1次)的方法中,不然會卡到死
真的需要我會建議另外做個簡易輸出數值的界面監視...

改造腳本沒意外都會用到的方法

隨機數
rand(100) # 隨機取得 0~99 中的值
和事件的亂數一樣,去獲取指定範圍「0~(指定數字-1)」中的某值
搭配增減固定數字可讓起始數字改成-1以下或1以上

loop 循環
(※重看了幾次電子說明書後,發現這不是控制結構,是一個內建方法。
和while、for等控制結構的差別在於:loop會建立新的「作用域」。
也就是說,loop內產生的臨時變數無法保留到迴圈外)
loop do
(內容)
end
和事件的「循環」一樣,每畫格執行一次,用來重複處理同樣的事情,
另外要設定 break 條件,不然就卡在這了


each
循環處理的方法,Ruby的「for...in...」 實際上會用這方法處理,使用例:
# 依序把 [1,2,3] 數組內元素代入val變數,然後p出來
[1,2,3].each { |val|
  p val
}
這例子寫成for...in...的話,就會是這樣:
for val in [1,2,3]
  p val
end
要用 each 理所當然該物件必須能支援,如果你要對數字用 each 那肯定報錯



公開實體變數

attr_writer :實體變數名           # 實體變數可改寫
attr_reader :實體變數名         # 實體變數可讀取
attr_accessor :實體變數名    # 上面兩種複合
(即所謂的屬性)

算是Ruby實現其他語言存取器(get、set)的方式
把實體變數變成一個「方法」,讓它可以在外部藉由調用的方式進行讀取或修改
所謂的外部就是不在自己所屬Class定義的方法中
當某物件要在其他類更動實體變數時,就要先做這件事
打開Game開頭的腳本就會看到一大串
不過你不會看到attr_writer,因為沒什麼用

比方說,如果你想臨時改變地圖場景(Scene_Map) viewport1 的色調(Game_Screen一改就是改全部,所以不改那邊),
就必須:
1.跑去Spriteset_Map把 @viewport1 宣告可寫
2.再跑去Scene_Map把 @spriteset (會代入Spriteset_Map的實體) 宣告可讀
3.之後才能在事件指令用$scene.spriteset.viewport1.tone = Tone.new(xxxx)...的方式改變色調

如果要在Scene_Map內部操作就可以少掉2的步驟變成:
@spriteset.viewport1.tone = Tone.new(xxxx) ...

隔得越多層,要公開的變數就越多
總之若想要修改別的Class的實體內容
首先要找目前所在的Class有無代表該實體的變數
沒有就去找最接近的全域變數,然後慢慢用調用的方式往下抓
這部分親自操作過幾次大概就曉得了,
也是改造腳本最麻煩的部分,越大型的腳本找變數會越痛苦,更不用說還會調用參數式丟來丟去


另外這三個其實是是把三個常用結構簡化了的方法,像attr_reader其實就是:
def 實體變數名
return @實體變數名
end
的簡化(其他電子說明書有寫)

而Ruby又有個特性是符合特定條件能省略括號,就變成上面那樣,
照平常寫法其實就是:
attr_writer(:實體變數名)
attr_reader(:實體變數名)
attr_accessor(:實體變數名)


順帶一提,事件指令的腳本指令所屬的Class為 Interpreter
如果需要用事件腳本調用Interpreter的方法,直接輸入方法名即可(不過裏面大部分需要事件指令的參數,你要知道那些方法需要什麼參數)


super
子類限定方法,子類拿父類方法再定義時,如果想要調用父類同名方法的內容就可使用super
若父類方法有參數時,可以用super(參數1,參數2...)這樣的方式調用
若只有super,就是把調用時的返回值丟給父類
若不想要帶任何參數調用父類,用super()

以下轉貼自6R看到的一個回應,因為太經典就拿來引用了:
星矢(父類) 的攻擊方法會使用 天馬流星拳,於是:
class 星矢
  def attack
    天馬流星拳
  end
end

星矢的兒子(子類) 的攻擊方法想在天馬流星拳的基礎上有所發展,於是:
class 星矢的兒子 < 星矢
  def attack
    super
    小強式回血
  end
end
於是星矢的兒子攻擊時會先放 天馬流星拳 然後發動 小強式回血

看,很簡單吧?


別名(alias)
為方法設定為別的名稱,格式為:
alias 新名稱 舊名稱
當你只是想擴充原始方法的內容,別名會很有用

比如說我想讓物件初始化的時候一開始先多宣告@a和@b變數,並在原本內容結束之後之後進行refresh
alias old_initialize initialize
def initialize
@a = 0
@b = 0
old_initialize # 調用被改過名稱的原方法內容
refresh
end
※old_initialize若不調用,則只會宣告兩個新變數和執行refresh,舊方法不會被執行
※alias需寫在原始方法之後,不然一樣會出現 NoMethodError (沒方法改毛)


這樣可以緩和很多腳本衝突的情形,
但因為只能在首尾補充內容,如果是改條件分歧內部或是原本的執行順序什麼的還是只能再定義了


常用變數
在RM內已經先用掉的名稱,和關鍵字一樣要避開它們


測試標誌
if $DEBUG # 測試模式中
(內容)
end
如果用測試模式進行遊戲,$DEBUG這個全域變數就會自動設為true
可用來實現只有測試模式中才能做到的事(內建的 F9選單 就是這樣)

幫忙某人製作的遊戲有很多地方用了這個判定跳過漫長的戰鬥
因為只在測試模式下才會跳過所以對一般遊戲沒影響

只是後面有人拆了加密檔用測試模式玩然後出問題了
所以之後只好在開頭補上這張圖:


腳本內容(寫在main腳本之前):
# 用測試模式,而且沒用F12重開遊戲過
if $DEBUG and not $warning_read
Graphics.freeze
# 顯示警告圖片
@warning = Sprite.new # < 其實這裡用局部變就可以
    @warning.bitmap = RPG::Cache.picture("DEBUGWARNING")
    Audio.se_play("Audio/SE/002-System02",80,100)
    Graphics.transition(40)
    # 停在這畫面,等待按鍵
    loop do
      Graphics.update
      Input.update
      # 如果按下確定或取消鍵就消除圖片,開始遊戲
      if Input.trigger?(Input::C) or Input.trigger?(Input::B)
        Graphics.freeze
        @warning.bitmap.dispose
        @warning.dispose
        # 設置一個全域變,防止F12又要再看一次
         $warning_read = true
         Graphics.transition(40)
         break
       end
    end    
  end     

喔我要澄清一下,如果是為了學習而拆檔我是蠻歡迎的,我覺得獨立創作還是重在交流學習(最新版本也沒加密了)
只是當時發生這種狀況好像也不是我們的問題啊


戰鬥測試標誌
if $BTEST # 戰鬥測試中
(內容)
end
嗯...一樣是測試模式限定,但只限「戰鬥測試
因為條件的關係所以「$DEBUG」也會跟著為on

測試戰鬥能持有全道具、不會接到標題畫面就是用了這個變數判斷

當前場景(Scene)
$scene = Scene_Menu.new # 切換至選單畫面
$scene.update # 執行目前場景的update方法

$scene是代表當前場景的變數(XP限定,VA開始有SceneManager)
根據Main腳本的結構:
  while $scene != nil
    $scene.main
  end
只要 $scene 不是nil,遊戲就能繼續運行(遊戲結束就是 $scene = nil 而已)

既然他是全域變數,就表示可以在任何地方使用
不過使用時要注意過程中會不會發生場景變化,因為一旦調用目前場景不存在的方法會出錯

(比方說在選單畫面中,某對像會定期使用$scene.xxx,而這xxx是其他場景沒有的,
這時要注意切換畫面時要把這處理中斷)



資料庫對象
Data資料夾各種資料庫的存檔在遊戲中對應的變數
全部都是數組,位置與資料庫設定的ID相同,因為資料庫沒有ID為0的數據,因此數組在0的位置都是 nil
$data_actors # 角色
$data_classes # 職業
$data_skills # 技能
$data_items # 道具
$data_weapons # 武器
$data_armors # 防具
$data_enemies # 敵人
$data_troops # 敵方隊伍
$data_states # 狀態
$data_animations # 戰鬥動畫
$data_tilesets # 地圖元件
$data_common_events # 公用事件
$data_system # 系統
比方說「p $data_animations[1]」 就能取得資料庫中1號戰鬥動畫的資料,依此類推...

沒什麼好講的,建議不要進行修改動作,以免影響後續運行(如果需要請用dup複製)
改了內容其實也沒意義,重開遊戲就會再重載原檔一次


Game 對象
針對預設腳本中的所有名稱為Game開頭的Class做成的對象

$game_temp # 暫存
$game_system # 遊戲系統
$game_switches # 事件公共開關
$game_variables # 事件公共變數
$game_self_switches # 事件的自用(獨立)開關
$game_screen # 畫面數值管理(色調、震動、閃爍)
$game_actors # 我方角色
$game_party # 我方隊伍
$game_troop # 敵方隊伍
$game_map # 地圖
$game_player # 地圖場景(Scene_Map)中的玩家(就是能被你操控、到處走的角色)

比較容易理解的應該就是事件開關和變數,其他的...要講也會佔很多篇幅
這裡只要先知道除了 $game_temp 以外全部會被儲存就好
另外實際上要檢查遊戲中的角色狀況要調用 $game_actors[角色ID]
不用 $data_actor 的原因是角色是個會變動的數據,做成角色時還得先宣告些有的沒的數值,
$data_actor 只會看到最原始的設定(成長度、經驗需求...etc.)

這就是為何改變資料庫的角色圖像後無法反映在舊存檔的原因,
如果要重新取得資料庫的狀態,請重新讓角色加入隊伍並勾選「初始化」,當然資料會洗白

※ 敵人數據在內建情況不會隨著遊戲進行變動,所以直接使用 $data_enemies 取得即可
如果要判斷目前血量和狀態用 $game_troop.enemies(因為通常是要看該戰鬥中的敵人數據)

因上述對象除了 $game_temp 以外全部看記錄檔,
所以如果是已發布的遊戲最好不要再對其他的Game類的初始化新增內容,這動作幾乎代表玩家必須重玩,如果是新增物件變數可以寫個「xxx = 0 if xxx == nil」來補救,不過不建議大量使用(因為很醜)


Game類的物件需要什麼物件變數請在發布遊戲前都確定好,
如果想省時間用舊存檔測試可以暫時用上述的防錯法,等變數宣告後存檔、移除宣告的式子。

你看不小心就會打這麼多


額,大概就這樣(爆



引用網址:https://home.gamer.com.tw/TrackBack.php?sn=2325335
All rights reserved. 版權所有,保留一切權利

相關創作

同標籤作品搜尋:RGSS|RM

留言共 4 篇留言

先行者
一堆落落長阿[e17]
不過有些我自己都不知道受教了[e6]

01-28 22:32

未来ずら
好羨慕簡明扼要的教學文啊 [e26]
什麼,居然還有你不知道的,看來還不夠基礎(欸01-28 23:16
先行者
像是符號 (Symbol)這個我就不常用也不常在腳本中看到[e18]
其他的都知道[e6]
因為一次的資訊量太大了所以打的才會比較多吧[e29]

01-29 09:10

未来ずら
喔,Symbol是到VX ACE大概是官方有意推廣這玩意,於是預設腳本用了大量Symbol,甚至特地給Symbol表達式上色。

不過問題來了,因為按鍵判定也改成Symbol所以VX以前的全按鍵腳本不能直接用了[e26]我也是因為這樣才留意到這個類01-29 14:47
白羽優莉奈
其實我很懶的,還是vb.net好學

01-31 22:08

未来ずら
OK的,我也很懶。不過怎麼突然和我說這個呢?(゚д゚;)01-31 22:32
白羽優莉奈
我也不知道(喂)

01-31 22:33

未来ずら
(´ ゚д゚`)エー01-31 22:41
我要留言提醒:您尚未登入,請先登入再留言

7喜歡★qootm2 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:[RGSS雜談] 程式去... 後一篇:[專案進度] 邪鬼的復仇...

追蹤私訊切換新版閱覽

作品資料夾

colanncolann
【繪圖創作】【科嵐實驗室】九週年! 2024/4/1 https://home.gamer.com.tw/creationDetail.php?sn=5909407看更多我要大聲說23小時前


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】