大概一個月前,下定決心把去年特價在Steam上買好的RPG MAKER MV拿出來玩,稍微找了一下資料,決定轉換跑道從VX跳到MV,由於兩者間差異頗大,所以VX上的羅小寶不能直接套進MV裡面,那就想既然換新引擎,不如就來開個新專案來玩吧。
所以羅小寶可能會陷入無期限停工狀態,至於新專案還在研究中,就先不公開了。
然後這系列主要是我為了學習MV而寫的筆記本,
首先我入門是看這系列:siakoMobi | RMMV
siakoMobi人真的很好,非常推薦去看
看完之後還有不懂的部分可以參考:JavaScript MDN
另外也有一篇巴哈小屋很適合新手去看
qootm2的小屋:[RMMV] 個人筆記用
後篇也讓我起了一些想法,其實我也可以把我自己的研究筆記整理一下,幫助自己記憶,也分享給其他人一起學習,因為是筆記所以內容可能有點隨性,而且我這人毫無程式基礎,只會一堆小聰明去鑽漏洞直接COPY別人寫好的來用,所以應該很適合給沒基礎的人看(花哈哈哈哈哈哈)。
WELL JUST HAVE FUN
-------------------------------------------------------------------------------------
在腳本的第一課,我們要先了解什麼叫做場景(Scene),還有什麼叫做視窗(Window)。
我們來看例圖,最外圈紫框就是場景,中間的紅框就是視窗。
換句話說,場景是整個遊戲畫面,視窗則是可以跟遊戲互動的操作介面。每一個場景跟視窗都有自己的名字。選用標題畫面當作範例是因為他最單純!
比如說這個標題畫面叫做: Scene_Title ,所有的預設好的場景都會放在 專案名稱\js\rpg_scenes.js 這個檔案裡面,所以如果我想修改標題畫面該怎麼作呢?
用筆記本,或是其他文字編輯器去打開 rpg_scene.js 然後用Ctrl+F去搜尋Scene_Title
會找到像這樣的東西:
哇喔,好多喔,先不管他把這一整段COPY下來,貼到一個新的檔案裡面,隨便幫檔案取個名字吧,就叫做 Scene_Title_new.js 吧,並放到 專案名稱\js\plugins\ 資料夾的下面:
接著就把我們新的new掛進遊戲裡面,在編輯器環境下按F10,開啟插件管理器:
並且設定為ON
好啦,這樣插件就設定好了,可以進遊戲看看了!
什麼,你說有什麼不一樣?當然是一樣的,因為還沒開始改嘛,先來改個背景圖試試看:
找到Scene_Title_new.js 裡面這一段:
Scene_Title.prototype.createBackground = function() {this._backSprite1 = new Sprite(ImageManager.loadTitle1($dataSystem.title1Name));this._backSprite2 = new Sprite(ImageManager.loadTitle2($dataSystem.title2Name));this.addChild(this._backSprite1);this.addChild(this._backSprite2);};
阿,字太多了,再少一點,改成下面這樣:
Scene_Title.prototype.createBackground = function() {};
他是一個function,function就是函式,那函式又是甚麼呢...就是...可重複執行的程式段落(By Google)。總之紅字的部分Scene_Title.prototype 表示這個function屬於Scene_Title
藍字的部分createBackground則是自定義的 function名稱,通常用來表達function的功用,顧名思義createBackground就是用來顯示背景圖片用的。至於裡面寫什麼呢?
this._backSprite1 = new Sprite(ImageManager.loadTitle1($dataSystem.title1Name));
// this._backSprite1:this._ 這個開頭表示對自己,backSprite1是自定義的變數名稱
// new Sprite():預設好的類別,用來呼叫圖形處理。
// ImageManager.loadTitle1($dataSystem.title1Name):讀入的圖片路徑,這一行會指向資料庫裡面設定的位置。
不過我現在不想要用資料庫設定,所以我來改寫一下,把$dataSystem.title1Name換成'Dragon' 結果如下:
然後試試看結果:
成功把背景圖換掉了!
如果不喜歡這個更動,再去插件管理器裡面把Scene_Title_new 設定改為Off ,就變回原本資料庫設定的樣子了,這樣做的目的是可以盡情的改寫插件內容,同時避免把遊戲本體改壞!好處非常的多,然後JS的設定上,同名的函式會跑後面的那個,所以兩個Scene_Tilte的時候,會顯示我們改過的而非內定的。
這樣做的好處就可以把東西刪光光也不會壞掉
現在我們要來說明一下這個函式內的細節,再看一次程式,這次先把重複的內容註解掉:
Scene_Title.prototype.createBackground = function() {this._backSprite1 = new Sprite(ImageManager.loadTitle1('Dragon'));// this._backSprite2 = new Sprite(ImageManager.loadTitle2($dataSystem.title2Name));this.addChild(this._backSprite1);// this.addChild(this._backSprite2);};
Sprite() 是一個類別,專門用來管理圖形處理,第一行意思是將 this._backSprite1 指定成一個Sprite。ImageManager用來指定圖片的路徑。
ImageManager.loadTitle1('檔案名字') ==> 專案資料夾\img\title1
ImageManager.loadTitle2('檔案名字') ==> 專案資料夾\img\title2
最後的addchild則是用來將Sprite加進來,add的順序會影響到圖片上下層,越後面讀入的圖片會在越上層。比如現在我們也把this._backSprite2給一張圖片
this._backSprite2 = new Sprite(ImageManager.loadTitle2('Floral'));
然後測試一下看結果:
this._backSprite2果然顯示到this._backSprite1的上面了,如果改成:
this.addChild(this._backSprite2);this.addChild(this._backSprite1);
那就會看不到this._backSprite2了,因為this._backSprite1比較大張,會把this._backSprite2整個蓋掉。
現在你想放幾張圖就可以放幾張圖,只要會複製貼上改檔名就行了!
想對Sprite了解更多的話,可以來看這裡:幫助文件
再來我們要介紹一下Scene_Title裡面其他東西,從上面開始看好了
function Scene_Title() {this.initialize.apply(this, arguments);}Scene_Title.prototype = Object.create(Scene_Base.prototype);Scene_Title.prototype.constructor = Scene_Title;Scene_Title.prototype.initialize = function() {Scene_Base.prototype.initialize.call(this);};
這裡是宣告,表示創建了一個叫做Scene_Title的場景,並且繼承了Scene_Base裡面所有的函式跟變數。如果想要創建自己的場景,只要Copy這段然後把Scene_Title的名字改掉即可。
下面兩段是環境初始化,用途在於預先讀入會用到的所有函式、圖片、物件:
Scene_Title.prototype.create = function() {Scene_Base.prototype.create.call(this);//繼承Scene_Base.prototype.createthis.createBackground();// 這裡叫了讀背景的函式this.createForeground();this.createWindowLayer();this.createCommandWindow();// 這裡叫了命令視窗};
Scene_Title.prototype.start = function() {Scene_Base.prototype.start.call(this);//繼承Scene_Base.prototype.startSceneManager.clearStack();this.centerSprite(this._backSprite1);// 這裡叫了背景用的圖1this.centerSprite(this._backSprite2);// 這裡叫了背景用的圖2this.playTitleMusic();// 這裡叫了背景音樂this.startFadeIn(this.fadeSpeed(), false);// 這裡設定淡入顯示};
那為什麼要區分create跟start放在一起不好嗎?他們有什麼不一樣?除了名字不一樣以外,繼承的東西也不一樣,因為他有Call(this),所以我們可以往上一層Scene_Base裡面去找他的來源,太棒了連說明都有:
/*** Create the components and add them to the rendering process.** @method create* @instance* @memberof Scene_Base*/Scene_Base.prototype.create = function() {};
/*** Start the scene processing.** @method start* @instance* @memberof Scene_Base*/Scene_Base.prototype.start = function() {this._active = true;};
不過我看不懂英文,所以就不解釋了。總之就是放在start裡面的會自動設定"啟動",而create的不會。
其他函式的快速介紹:
Scene_Title.prototype.createBackground = function() //顯示背景,前面介紹過了
Scene_Title.prototype.createForeground = function() //顯示前景,包括標題文字等
Scene_Title.prototype.playTitleMusic = function() //播放背景音樂
Scene_Title.prototype.drawGameTitle = function() //顯示標題文字
大至上會需要改的就這些,裡面不難懂,隨便改改看結果大概就知道是什麼了,頂多可能會需要用到Google翻譯,再不行就問我吧。
最後介紹一下update:
Scene_Title.prototype.update = function() {if (!this.isBusy()) {this._commandWindow.open();}Scene_Base.prototype.update.call(this);};
看一下Base裡對update的說明:
/*** Update the scene processing each new frame.** @method update* @instance* @memberof Scene_Base*/Scene_Base.prototype.update = function() {this.updateFade();this.updateChildren();};
就是每frame幫你更新畫面用的,也就是說想讓圖片飛來飛去,音樂會隨時間更換之類的效果就要寫在update裡面。進階做法就找Siako吧!幾乎各種想到的效果他都有教學了。
最後,真的是最後了,很快就要結束了,只剩下Window還沒說明了!在Scene_Title裡面跟Window有關的一共有四段,先看第一段:
這段的內容是創建一個視窗,名字是this._commandWindowScene_Title.prototype.createCommandWindow = function() {this._commandWindow = new Window_TitleCommand();this._commandWindow.setHandler('newGame', this.commandNewGame.bind(this));this._commandWindow.setHandler('continue', this.commandContinue.bind(this));this._commandWindow.setHandler('options', this.commandOptions.bind(this));this.addWindow(this._commandWindow);};
他是一個標題命令視窗(Window_TitleCommand),Window_TitleCommand又是什麼?Ctrl+F搜尋一下,找到這個:
Window_TitleCommand.prototype.initialize = function() {Window_Command.prototype.initialize.call(this, 0, 0);this.updatePlacement();this.openness = 0;this.selectLast();};
原來Window_TitleCommand又是屬於Window_Command也就是說層級是這樣的:
Window_Command
↓
Window_TitleCommand
↓
this._commandWindow
什麼看不懂我在說什麼,沒關係我也搞不太懂,只要知道他們三個都可以可以設定「命令」以及「執行命令的內容」。
這個視窗有三個選項,分別是
這三個選項有三個對應的命令名稱,分別是:
'newGame''continue''options'
然後裡面這句:
this._commandWindow.setHandler( 'newGame' , this.commandNewGame.bind(this) );//this._commandWindow.setHandler( '命令名稱' , 命令後執行的對象函式)Scene_Title.prototype.commandNewGame = function() {
DataManager.setupNewGame();this._commandWindow.close();this.fadeOutAll();SceneManager.goto(Scene_Map);};
以上兩段翻譯成白話就是,當我點了'newGame' 後,會執行Scene_Title.prototype.commandNewGame = function()這個函式的內容。內容其實也很簡單,就關閉標題視窗後移動到Scene_Map去。
下兩段分別是對應 'continue' 跟 'options' 都會直接開另一個新場景,就不再說明
是不是好簡單阿,咦,那還忘了什麼?
Scene_Title.prototype.commandContinue = function() {this._commandWindow.close();SceneManager.push(Scene_Load);};Scene_Title.prototype.commandOptions = function() {this._commandWindow.close();SceneManager.push(Scene_Options);};
對了,那要怎麼設定或更改視窗裡面的細節?可以在Create裡面做,比如說我新增了藍字的部分:
Scene_Title.prototype.createCommandWindow = function() {this._commandWindow = new Window_TitleCommand();this._commandWindow.x = 100;this._commandWindow.y = 120;this._commandWindow.setHandler('newGame', this.commandNewGame.bind(this));this._commandWindow.setHandler('continue', this.commandContinue.bind(this));this._commandWindow.setHandler('options', this.commandOptions.bind(this));this.addWindow(this._commandWindow);};
視窗就移動了!
再來改多一點,像這樣:
結果呢:Scene_Title.prototype.createCommandWindow = function() {this._commandWindow = new Window_TitleCommand();this._commandWindow.x = 100;this._commandWindow.y = 120;this._commandWindow.width = 300;this._commandWindow.height = 400;this._commandWindow.windowskin = ImageManager.loadSystem('Window_03');this._commandWindow.setHandler('newGame', this.commandNewGame.bind(this));this._commandWindow.setHandler('continue', this.commandContinue.bind(this));this._commandWindow.setHandler('options', this.commandOptions.bind(this));this.addWindow(this._commandWindow);};
視窗變大,還換了skin了,如果想讓視窗移動的話,也可以到update裡面去變更this._commandWindow.x以及this._commandWindow.y
這些.x .y的東西叫做「視窗的屬性」,那還有哪些屬性可以改呢?詳見這裡
現在我們會修改視窗大小位置SKIN了,還需要改什麼?
還有個很重要的,就是視窗的選項!
那視窗的選項要怎麼改呢?
要去他的上一層Window_TitleCommand裡面修改
在rpg_windows.js裡面找到下段:
Window_TitleCommand.prototype.makeCommandList = function() {this.addCommand(TextManager.newGame, 'newGame');this.addCommand(TextManager.continue_, 'continue', this.isContinueEnabled());this.addCommand(TextManager.options, 'options');};
//this.addCommand( '選項顯示名稱', '選項指令名稱' );
選項指令名稱大小寫不可寫錯,會對應到執行的函式
如果想要新增選項的話,這裡面多寫幾行就可以了,比如像這樣:
Window_TitleCommand.prototype.makeCommandList = function() {this.addCommand(TextManager.newGame, 'newGame');this.addCommand(TextManager.continue_, 'continue', this.isContinueEnabled());this.addCommand(TextManager.options, 'options');this.addCommand( '選項3', 'command3');this.addCommand( '選項4', 'command4');this.addCommand( '選項5', 'command5');this.addCommand( '選項6', 'command6');};
測試結果如下:
可是一般不建議更動原生程式裡面的東西,簡單的做法是把「所有」Window_TitleCommand的內容都COPY下來貼到自建Scene_Title_new.js裡面,Window_TitleCommand要放在Scene_Title的上面,因為JavaScript是直譯式的語言。這樣才會先創建好視窗內容再創建場景。
另外還有一種版面比較漂亮的做法:程式別名
不用把整段Window_TitleCommand貼進來,只擴充自己想要的部分。
不過因為我只有自己一個人在寫,沒有多工問題,而且也想知道那些沒用到的程式碼的用途,所以通常還是全段貼過來慢慢玩弄他們。
好啦,真的要結束了,什麼,還沒開始創建視窗耶!?
下...下回吧...
目錄: