ก่อนอื่นควรศึกษาการเขียนโปรแกรมเชิงวัตถุก่อนครับ
http://www.no-poor.com/JavaandAi/chapter1-java.htm
(อันนี้คือแผนผังแบบสรุป
https://www.mindmeister.com/198142531/ob...amming-oop)
**หมายเหตุ: Java กับ JavaScript เป็นคนละภาษากันแค่ต้องการให้ทราบหลักการการเขียนโปรแกรมเชิงวัตถุเท่านั้น
จากนั้นก็ลงมือครับ
เมนูจะประกอบด้วยตัวเมนู กับ คำสั่งจะที่จะทำเมื่อผู้เล่นกดเมนูนั้นๆครับ
ตัวเมนูนั้นสร้างมาจาก class Window_Command ก็ได้ครับ (ดูไฟล์
rpg_windows.js)
ซึ่งเราจะพบว่า Window_Command สืบทอดมาจาก Window_Selectable อีกที และคลาสที่เป็นต้นสายจริงๆคือ Window_Base
ทีนี้ถ้าเราอยากลัดขั้นตอน ให้ลองหา class ที่สืบทอดจาก Windows_Command มาแก้ดูครับ
ตัวอย่างที่น่าจะใกล้เคียงกับที่ท่าน bezblue อยากทำมากที่สุดน่าจะเป็น Window_MenuCommand
Window_MenuCommand ตัวนี้ก็คือเมนูตอนที่เรากด x ในเกมนั่นแหละครับ (เมนูหลัก) จากภาพคือเมนูที่อยู่ในกรอบด้านซ้าย มาดูโครงสร้างซักนิด
ส่วนต้นแบบคลาส
Code:
function Window_MenuCommand() {
this.initialize.apply(this, arguments);
}
Window_MenuCommand.prototype = Object.create(Window_Command.prototype);
Window_MenuCommand.prototype.constructor = Window_MenuCommand;
Window_MenuCommand.prototype.initialize = function(x, y) {
Window_Command.prototype.initialize.call(this, x, y);
this.selectLast();
};
โค้ดด้านบนนี้จะเป็นคุณสมบัติการสืบทอดของคลาส Window_MenuCommand ว่าสืบทอดมาจากคลาส Window_Command โดยสังเกตได้ ซึ่งก็คือโค้ด Window_MenuCommand.prototype = Object.create(Window_Command.prototype); ถ้าสังเกตดีๆจะเห็นว่าในโค้ดมีคำว่า prototype เต็มไปหมด ถ้าจะอธิบายง่ายๆให้เรานึกภาพว่ามีโรงงานแห่งหนึ่งเป็นโรงงานผลิตคลาส ซึ่งแน่นอนว่าเขาจะต้องมีต้นแบบหรือแม่แบบ (prototype) จริงไหมครับ เพื่อให้ผลิตออกมาได้วัตถุที่มีคุณสมบัติเหมือนกันทุกประการ อันนี้ก็เหมือนกันครับ ตรงโค้ดส่วนนี้ยังไม่ใช่การสร้าง Window_MenuCommand เลย แต่เป็นการเขียนต้นแบบของ Window_MenuCommand ขึ้นมาซึ่งเราจะเอาไปสรเางเป็นวัตถุภายหลัง
ทีนี้วัตถุที่เราจะสร้างมันก็ควรจะถูกกำหนดค่าเริ่มต้นใช่ไหมครับ ในขณะที่ถูกสร้าง ซึ่งส่วนนี้จะอยู่ในฟังก์ชัน initialize นั่นเอง
แนะนำว่าท่าน bezblue ควรศึกษาการเขียนโปรแกรมเชิงวัตถุก่อนนะครับจะได้เข้าใจที่อธิบายเพราะมันอธิบายยากจริง ถ้าเข้าใจหลักการเขียนโปรแกรมเชิงวัตถุก็จะเข้าใจโค้ดได้ง่ายๆเลย เหมือนอย่างโค้ด Window_Command.prototype.initialize.call(this, x, y); ซึ่งอยู่ในฟังก์ชัน initialize ของคลาส Window_MenuCommand นั้น เป็นการเรียกใช้ฟังก์ชัน initialize ของคลาสแม่(Window_Command) เป็นต้น
เอาเป็นว่าอธิบายต่อน่าจะยาว เดี๋ยวผมจะใบ้ส่วนสำคัญให้ลองโมเพิ่มนะครับ ลองดูโค้ดของคลาส Window_MenuCommand ไปเรื่อยจะเป็นเห็นว่าประกอบด้วยฟังก์ชันมากมายลองมาดูฟังก์ชันนี้กันครับ
Code:
Window_MenuCommand.prototype.addMainCommands = function() {
var enabled = this.areMainCommandsEnabled();
if (this.needsCommand('item')) {
this.addCommand(TextManager.item, 'item', enabled);
}
if (this.needsCommand('skill')) {
this.addCommand(TextManager.skill, 'skill', enabled);
}
if (this.needsCommand('equip')) {
this.addCommand(TextManager.equip, 'equip', enabled);
}
if (this.needsCommand('status')) {
this.addCommand(TextManager.status, 'status', enabled);
}
};
ส่วนนี้เป็นส่วนเพิ่มรายการเมนูนั่นเอง TextManager.item คือชื่อเมนูไอเทมที่จะแสดงให้ผู้เล่นเห็นนั่นเอง ซึ่งผู็พัฒนา RMMV ได้เขียนโค้ดให้มีความเป็นระเบียบอย่างมาก และเพื่อให้สามารถใช้ร่วมกับ Editor ได้ เลยให้มันเรียกจาก TextManager ซึ่งเป็นคลาสๆหนึ่งนั่นเอง กรณีทำเมนูเองเราาสามารถเขียนเป็น this.addCommand('เมนูของฉัน', 'mymenu', enabled); ได้ ส่วนตรงที่เป็น 'mymenu' หรือ 'item' (ถ้าดูจากโค้ดด้านบน) เป็นส่วนที่ผมกำลังจะอธิบายต่อจากนี้ครับ
ส่วนสร้างวัตถุจากต้นแบบ
มาถึงขั้นตอนการสร้างวัตถุจริงๆแล้ว ให้ดูที่ไฟล์
rpg_scene.js ครับ โดยมาดูที่ฟังก์ชัน createCommandWindow ของ Scene_Menu
Code:
Scene_Menu.prototype.createCommandWindow = function() {
this._commandWindow = new Window_MenuCommand(0, 0);
this._commandWindow.setHandler('item', this.commandItem.bind(this));
this._commandWindow.setHandler('skill', this.commandPersonal.bind(this));
this._commandWindow.setHandler('equip', this.commandPersonal.bind(this));
this._commandWindow.setHandler('status', this.commandPersonal.bind(this));
this._commandWindow.setHandler('formation', this.commandFormation.bind(this));
this._commandWindow.setHandler('options', this.commandOptions.bind(this));
this._commandWindow.setHandler('save', this.commandSave.bind(this));
this._commandWindow.setHandler('gameEnd', this.commandGameEnd.bind(this));
this._commandWindow.setHandler('cancel', this.popScene.bind(this));
this.addWindow(this._commandWindow);
};
จากโค้ด this._commandWindow = new Window_MenuCommand(0, 0); ก็คือการสร้างวัตถุ Window_MenuCommand นั่นเอง อธิบายโค้ดง่ายๆก็เราไปสั่ง new (สร้างใหม่) มันนั่นแหละครับ โดยจะเห็นว่ามีการใส่ (0, 0) ด้วย นั่นคือการรับพารามิเตอร์ (ถ้าไม่ทราบว่าคืออะไรควรศึกษาการเขียนฟังก์ชันภาษา C เบื้องต้น) จากฟังก์ชัน initialize ที่ผมได้อธิบายไว้ตอนต้นนั่นเอง
ทีนี้คำถามอาจจะเป็น this._ คืออะไร ก็คือ Scene_Menu จัดเป็นวัตถุๆหนึ่งเหมือนกัน และในวัตถุนั้น สามารถมีวัตถุย่อยๆอยู่ภายในตัวมันได้ ก็เหมือนคนเราที่มี ปอด หัวใจ ตับ เป็นส่วนประกอบภายในล่ะครับ ทีนี้การใช้คำว่า this คือการเรียกตัวเองครับ เช่นถ้าเราต้องการเรียกฟงัก์ชั่น move() ที่อยู่ในคลาสนั้นเองก็ใช้ this.move() ส่วน _ เป็นการเรียกใช้ตัวแปร หรือฟังก์ชันที่มีการประกาศเป็น private (ถ้าไม่ทราบว่า private คืออะไรกลับไปศึกษาด้านบน) ซึ่งตัวแปรหรือฟงัก์ชันประเภทนี้จะถูกเรียกจากคลาสอื่นไม่ได้
ต่อมา มาดูที่ this._commandWindow.setHandler('item', this.commandItem.bind(this)); กันครับ ตรงนี้ล่ะที่จะต่อจากเมื่อกี้ ที่ผมได้กล่าวว่าจะอธิบายว่า 'mynemu' หรือ 'item' เอามาใช้ตรงไหน ก็เรามาใช้ตรงนี้ไงครับ
โค้ดนี้เป็นการ bind คำสั่ง อธิบายง่ายๆคือ เมื่อผู้เล่นกดเลือกเมนูไอเทมแล้วจะไปไหนต่อ โดยชื่อจะต้องตรงกับตอนที่เรา addCommand ด้วยนะครับ (กลับไปดูด้านบน) ส่วนสิ่งที่เราต้องการใช้ทำก็คือ this.commandItem.bind(this) นั่นเอง จริงๆตรงนี้เราใส่ฟังก์ชันอะไรลงไปก็ได้ครับเช่นถ้าผมจะใช้ฟังก์ชัน move() ซึ่งอยู่ในคลาสเดียวกัน ก็จะเขียนเป็น this._commandWindow.setHandler('mymenu', this.move());
แต่ถ้าถามว่า this.commandItem.bind(this) มันจะไปเรียกฟังก์ชันไหน ก็ตอบว่าฟังก์ชันนี้ครับ
Code:
Scene_Menu.prototype.commandItem = function() {
SceneManager.push(Scene_Item);
};
จริงๆมีอะไรอธิบายอีกเยอะเลย แต่เอาแบบเร็วๆไปก่อนละกันครับ
มีอะไรสงสัยถามในนี้ได้เลย