ETH官方钱包

切換
舊版
前往
大廳
主題

RM MV學(xué)習(xí)筆記(1) 創(chuàng)建場景跟視窗

路漫行 | 2018-01-17 11:31:03 | 巴幣 1042 | 人氣 5185


大概一個(gè)月前,下定決心把去年特價(jià)在Steam上買好的RPG MAKER MV拿出來玩,稍微找了一下資料,決定轉(zhuǎn)換跑道從VX跳到MV,由於兩者間差異頗大,所以VX上的羅小寶不能直接套進(jìn)MV裡面,那就想既然換新引擎,不如就來開個(gè)新專案來玩吧。

所以羅小寶可能會(huì)陷入無期限停工狀態(tài),至於新專案還在研究中,就先不公開了。

然後這系列主要是我為了學(xué)習(xí)MV而寫的筆記本,

首先我入門是看這系列:siakoMobi | RMMV

siakoMobi人真的很好,非常推薦去看

看完之後還有不懂的部分可以參考:JavaScript MDN


另外也有一篇巴哈小屋很適合新手去看

qootm2的小屋:[RMMV] 個(gè)人筆記用

後篇也讓我起了一些想法,其實(shí)我也可以把我自己的研究筆記整理一下,幫助自己記憶,也分享給其他人一起學(xué)習(xí),因?yàn)槭枪P記所以內(nèi)容可能有點(diǎn)隨性,而且我這人毫無程式基礎(chǔ),只會(huì)一堆小聰明去鑽漏洞直接COPY別人寫好的來用,所以應(yīng)該很適合給沒基礎(chǔ)的人看(花哈哈哈哈哈哈)。

WELL JUST HAVE FUN

-------------------------------------------------------------------------------------

在腳本的第一課,我們要先了解什麼叫做場景(Scene),還有什麼叫做視窗(Window)。

我們來看例圖,最外圈紫框就是場景,中間的紅框就是視窗。


換句話說,場景是整個(gè)遊戲畫面,視窗則是可以跟遊戲互動(dòng)的操作介面。每一個(gè)場景跟視窗都有自己的名字。選用標(biāo)題畫面當(dāng)作範(fàn)例是因?yàn)樗顔渭儯?/div>

比如說這個(gè)標(biāo)題畫面叫做: Scene_Title ,所有的預(yù)設(shè)好的場景都會(huì)放在 專案名稱\js\rpg_scenes.js 這個(gè)檔案裡面,所以如果我想修改標(biāo)題畫面該怎麼作呢?

用筆記本,或是其他文字編輯器去打開 rpg_scene.js 然後用Ctrl+F去搜尋Scene_Title

會(huì)找到像這樣的東西:


哇喔,好多喔,先不管他把這一整段COPY下來,貼到一個(gè)新的檔案裡面,隨便幫檔案取個(gè)名字吧,就叫做 Scene_Title_new.js 吧,並放到 專案名稱\js\plugins\ 資料夾的下面:


接著就把我們新的new掛進(jìn)遊戲裡面,在編輯器環(huán)境下按F10,開啟插件管理器:




並且設(shè)定為ON


好啦,這樣插件就設(shè)定好了,可以進(jìn)遊戲看看了!

什麼,你說有什麼不一樣?當(dāng)然是一樣的,因?yàn)檫€沒開始改嘛,先來改個(gè)背景圖試試看:

找到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);
};


阿,字太多了,再少一點(diǎn),改成下面這樣:


Scene_Title.prototype.createBackground = function() {
};

他是一個(gè)function,function就是函式,那函式又是甚麼呢...就是...可重複執(zhí)行的程式段落(By Google)。總之紅字的部分Scene_Title.prototype 表示這個(gè)function屬於Scene_Title

藍(lán)字的部分createBackground則是自定義的 function名稱,通常用來表達(dá)function的功用,顧名思義createBackground就是用來顯示背景圖片用的。至於裡面寫什麼呢?

this._backSprite1 = new Sprite(ImageManager.loadTitle1($dataSystem.title1Name));

// this._backSprite1:this._  這個(gè)開頭表示對自己,backSprite1是自定義的變數(shù)名稱
// new Sprite():預(yù)設(shè)好的類別,用來呼叫圖形處理。
//  ImageManager.loadTitle1($dataSystem.title1Name):讀入的圖片路徑,這一行會(huì)指向資料庫裡面設(shè)定的位置。



不過我現(xiàn)在不想要用資料庫設(shè)定,所以我來改寫一下,把$dataSystem.title1Name換成'Dragon' 結(jié)果如下:

然後試試看結(jié)果:


成功把背景圖換掉了!

如果不喜歡這個(gè)更動(dòng),再去插件管理器裡面把Scene_Title_new 設(shè)定改為Off ,就變回原本資料庫設(shè)定的樣子了,這樣做的目的是可以盡情的改寫插件內(nèi)容,同時(shí)避免把遊戲本體改壞!好處非常的多,然後JS的設(shè)定上,同名的函式會(huì)跑後面的那個(gè),所以兩個(gè)Scene_Tilte的時(shí)候,會(huì)顯示我們改過的而非內(nèi)定的。

這樣做的好處就可以把東西刪光光也不會(huì)壞掉

現(xiàn)在我們要來說明一下這個(gè)函式內(nèi)的細(xì)節(jié),再看一次程式,這次先把重複的內(nèi)容註解掉:

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() 是一個(gè)類別,專門用來管理圖形處理,第一行意思是將 this._backSprite1 指定成一個(gè)Sprite。ImageManager用來指定圖片的路徑。

ImageManager.loadTitle1('檔案名字')   ==>  專案資料夾\img\title1
ImageManager.loadTitle2('檔案名字')   ==>  專案資料夾\img\title2

最後的addchild則是用來將Sprite加進(jìn)來,add的順序會(huì)影響到圖片上下層,越後面讀入的圖片會(huì)在越上層。比如現(xiàn)在我們也把this._backSprite2給一張圖片

this._backSprite2 = new Sprite(ImageManager.loadTitle2('Floral'));

然後測試一下看結(jié)果:


this._backSprite2果然顯示到this._backSprite1的上面了,如果改成:

this.addChild(this._backSprite2);
this.addChild(this._backSprite1);

那就會(huì)看不到this._backSprite2了,因?yàn)?i>this._backSprite1比較大張,會(huì)把this._backSprite2整個(gè)蓋掉。

現(xiàn)在你想放幾張圖就可以放幾張圖,只要會(huì)複製貼上改檔名就行了!

想對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);
};

這裡是宣告,表示創(chuàng)建了一個(gè)叫做Scene_Title的場景,並且繼承了Scene_Base裡面所有的函式跟變數(shù)。如果想要?jiǎng)?chuàng)建自己的場景,只要Copy這段然後把Scene_Title的名字改掉即可。

下面兩段是環(huán)境初始化,用途在於預(yù)先讀入會(huì)用到的所有函式、圖片、物件:

Scene_Title.prototype.create = function() {
    Scene_Base.prototype.create.call(this);//繼承Scene_Base.prototype.create
    this.createBackground();// 這裡叫了讀背景的函式
    this.createForeground();
    this.createWindowLayer();
    this.createCommandWindow();// 這裡叫了命令視窗
};

Scene_Title.prototype.start = function() {
    Scene_Base.prototype.start.call(this);//繼承Scene_Base.prototype.start
    SceneManager.clearStack();
    this.centerSprite(this._backSprite1);// 這裡叫了背景用的圖1
    this.centerSprite(this._backSprite2);// 這裡叫了背景用的圖2
    this.playTitleMusic();// 這裡叫了背景音樂
    this.startFadeIn(this.fadeSpeed(), false);// 這裡設(shè)定淡入顯示
};

那為什麼要區(qū)分create跟start放在一起不好嗎?他們有什麼不一樣?除了名字不一樣以外,繼承的東西也不一樣,因?yàn)樗蠧all(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裡面的會(huì)自動(dòng)設(shè)定"啟動(dòng)",而create的不會(huì)。

其他函式的快速介紹:
Scene_Title.prototype.createBackground  = function()  //顯示背景,前面介紹過了

Scene_Title.prototype.createForeground = function()  //顯示前景,包括標(biāo)題文字等

Scene_Title.prototype.playTitleMusic = function()  //播放背景音樂

Scene_Title.prototype.drawGameTitle = function() //顯示標(biāo)題文字

大至上會(huì)需要改的就這些,裡面不難懂,隨便改改看結(jié)果大概就知道是什麼了,頂多可能會(huì)需要用到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幫你更新畫面用的,也就是說想讓圖片飛來飛去,音樂會(huì)隨時(shí)間更換之類的效果就要寫在update裡面。進(jìn)階做法就找Siako吧!幾乎各種想到的效果他都有教學(xué)了。


最後,真的是最後了,很快就要結(jié)束了,只剩下Window還沒說明了!在Scene_Title裡面跟Window有關(guān)的一共有四段,先看第一段:


Scene_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);
};

這段的內(nèi)容是創(chuàng)建一個(gè)視窗,名字是this._commandWindow

他是一個(gè)標(biāo)題命令視窗(Window_TitleCommand),Window_TitleCommand又是什麼?Ctrl+F搜尋一下,找到這個(gè):

Window_TitleCommand.prototype.initialize = function() {
    Window_Command.prototype.initialize.call(this, 0, 0);
    this.updatePlacement();
    this.openness = 0;
    this.selectLast();
};

原來Window_TitleCommand又是屬於Window_Command也就是說層級(jí)是這樣的:

Window_Command
    ↓
Window_TitleCommand
    ↓
this._commandWindow

什麼看不懂我在說什麼,沒關(guān)係我也搞不太懂,只要知道他們?nèi)齻€(gè)都可以可以設(shè)定「命令」以及「執(zhí)行命令的內(nèi)容」。

這個(gè)視窗有三個(gè)選項(xiàng),分別是

這三個(gè)選項(xiàng)有三個(gè)對應(yīng)的命令名稱,分別是:

'newGame'
'continue'
'options'

然後裡面這句:

this._commandWindow.setHandler( 'newGame' ,  this.commandNewGame.bind(this) );

//this._commandWindow.setHandler( '命令名稱' , 命令後執(zhí)行的對象函式) 

Scene_Title.prototype.commandNewGame = function() {
    DataManager.setupNewGame();
    this._commandWindow.close();
    this.fadeOutAll();
    SceneManager.goto(Scene_Map);
};

以上兩段翻譯成白話就是,當(dāng)我點(diǎn)了'newGame' 後,會(huì)執(zhí)行Scene_Title.prototype.commandNewGame = function()這個(gè)函式的內(nèi)容。內(nèi)容其實(shí)也很簡單,就關(guān)閉標(biāo)題視窗後移動(dòng)到Scene_Map去。

下兩段分別是對應(yīng) 'continue'  'options' 都會(huì)直接開另一個(gè)新場景,就不再說明

Scene_Title.prototype.commandContinue = function() {
    this._commandWindow.close();
    SceneManager.push(Scene_Load);
};

Scene_Title.prototype.commandOptions = function() {
    this._commandWindow.close();
    SceneManager.push(Scene_Options);
};



是不是好簡單阿,咦,那還忘了什麼?

對了,那要怎麼設(shè)定或更改視窗裡面的細(xì)節(jié)?可以在Create裡面做,比如說我新增了藍(lán)字的部分:

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);
};


視窗就移動(dòng)了!

再來改多一點(diǎn),像這樣:

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);
};

結(jié)果呢:


視窗變大,還換了skin了,如果想讓視窗移動(dòng)的話,也可以到update裡面去變更this._commandWindow.x以及this._commandWindow.y

這些.x .y的東西叫做「視窗的屬性」,那還有哪些屬性可以改呢?詳見這裡


現(xiàn)在我們會(huì)修改視窗大小位置SKIN了,還需要改什麼?

還有個(gè)很重要的,就是視窗的選項(xiàng)!

那視窗的選項(xiàng)要怎麼改呢?

要去他的上一層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( '選項(xiàng)顯示名稱',   '選項(xiàng)指令名稱'   );
選項(xiàng)指令名稱大小寫不可寫錯(cuò),會(huì)對應(yīng)到執(zhí)行的函式
如果想要新增選項(xiàng)的話,這裡面多寫幾行就可以了,比如像這樣:
Window_TitleCommand.prototype.makeCommandList = function() {
    this.addCommand(TextManager.newGame,   'newGame');
    this.addCommand(TextManager.continue_, 'continue', this.isContinueEnabled());
    this.addCommand(TextManager.options,   'options');
    this.addCommand( '選項(xiàng)3',   'command3');
    this.addCommand( '選項(xiàng)4',   'command4');
    this.addCommand( '選項(xiàng)5',   'command5');
    this.addCommand( '選項(xiàng)6',   'command6');
};

測試結(jié)果如下:


可是一般不建議更動(dòng)原生程式裡面的東西,簡單的做法是把「所有」Window_TitleCommand的內(nèi)容都COPY下來貼到自建Scene_Title_new.js裡面,Window_TitleCommand要放在Scene_Title的上面,因?yàn)镴avaScript是直譯式的語言。這樣才會(huì)先創(chuàng)建好視窗內(nèi)容再創(chuàng)建場景。

另外還有一種版面比較漂亮的做法:程式別名
不用把整段Window_TitleCommand貼進(jìn)來,只擴(kuò)充自己想要的部分。


不過因?yàn)槲抑挥凶约阂粋€(gè)人在寫,沒有多工問題,而且也想知道那些沒用到的程式碼的用途,所以通常還是全段貼過來慢慢玩弄他們。


好啦,真的要結(jié)束了,什麼,還沒開始創(chuàng)建視窗耶!?

下...下回吧...


目錄:
送禮物贊助創(chuàng)作者 !
0
留言

創(chuàng)作回應(yīng)

感謝您,真的對我有很大幫助!!(汪~
2019-10-22 00:52:56
小兔乖乖
真的太好了,好詳細(xì)~~連笨蛋如我都看得懂了!!
2019-11-28 02:53:08
路漫行
因?yàn)槲乙彩潜康鞍?/article>
2019-11-28 08:06:16

相關(guān)創(chuàng)作

更多創(chuàng)作