splendith   06-12-2015, 01:27 AM
#1
พื้นฐานการโม Script เบื้องต้น

บทความนี้เป็นบทความเบื้องต้น อย่างไรก็ตาม เนื้อหามีความยาวถึงยาวที่สุด เหมาะสำหรับผู้ที่ต้องการเขียน script อย่างจริงจังในอนาคต

บทความนี้ตั้งใจเขียนมาก พยายามอธิบายให้ง่ายที่สุด อย่างไรก็ตาม หากไม่เข้าใจ มีข้อสงสัยหรือข้อเสนอแนะ โปรดคอมเมนต์ด้วยนะครับ หรือถ้าไม่รู้เรื่องตรงไหนบอกได้เลยครับ หรือหากมีข้อผิดพลาด แจ้งได้เลยนะครับ

แม้ในบทความนี้จะใช้ RGSS3 เป็นหลัก แต่หลักการสอนในบทความนี้สามารถนำไปประยุกต์ใช้ได้ทุกเวอร์ชันครับ หรือแม้แต่นำหลักการไปใช้ทำอย่างอื่นนอกจากใช้ใน RPG Maker ก็ได้ครับ



เคยไหม บางทีอยากได้ระบบตามที่ต้องการ ในบางกรณีการแก้ด้วย event หรือ database นั้นยังมีขีดจำกัดอยู่ จึงไม่สามารถเปลี่ยนแปลงได้ดั่งใจ ทำให้ต้องหวังพึ่งการใช้ script ในการทำระบบที่ต้องการ ซึ่งหลายๆ คนเมื่อเปิดหน้าจอ script editor ดูก็รู้สึกเอียน มึนหัว ตาลาย ไม่อยากไปแตะต้องเลย...

ถ้าโชคดี เจอ script ที่มีคนเขียนมาก่อน ก็โหลดมาลงแล้วใช้งานได้เลย แต่ถ้าเราต้องการ script ที่มันเฉพาะเจาะจงจริงๆ ทักษะการโม script ก็ทำให้เราได้เปรียบไม่ใช่น้อย

จริงๆ แล้วก่อนที่จะทำการโม script นั้น แนะนำให้ศึกษาพื้นฐานการเขียน Ruby script ก่อน เพราะจะทำให้เราเข้าใจ script ได้อย่างรวดเร็วมากขึ้น แต่อย่างไรก็ตาม ในบทความนี้จะพยายามยกตัวอย่างที่ทุกท่านเข้าใจได้ไม่ยาก

ซึ่งบทเรียนจะมีดังนี้ครับ จะมาราธอนสอนตั้งแต่ต้นจนจบในกระทู้นี้เลยครับ
  • เข้าใจส่วนต่างๆ ในหน้าจอ script ของ RGSS3
  • RPG Maker VX Ace Database Module
  • แนวคิดในการโม script
  • เข้าใจการ alias method และ overwrite script สิ่งสำคัญก่อนจะเป็นนักเขียน script ตัวยง!
  • แบบฝึกหัด
ทำความเข้าใจก่อนว่าอ่านบทความนี้จบ ท่านจะได้แนวคิดและหลักในการโมโค้ด แต่ไม่ถึงกับทำ script แจกเป็นเรื่องเป็นราวได้ อย่างไรก็ตาม บทความนี้เป็นการปูพื้นฐานที่ดีในการยืนอยู่จุดนั้นครับ ^^

เข้าใจส่วนต่างๆ ในหน้าจอ script ของ RGSS3
สิ่งสำคัญที่ต้องรู้เป็นอันดับแรกเลยนั่นคือ ต้องรู้ว่าส่วนต่างๆ ของ script ในหน้า script editor นั้นมีหน้าที่อะไรบ้าง เพื่อจะนำไปสู่การคาดเดาเพื่อโม script ในอนาคต

ใน RGSS3 นั้น ทีมพัฒนาได้เขียนโค้ดอ่านเข้าใจง่าย และเป็นระเบียบมากๆ มีการพัฒนาจากรุ่นก่อนๆ อย่างเห็นได้ชัด ให้ท่านลองปุ่ม F11 ดู จะมีหน้าจอ script editor ปรากฎขึ้นมา มองไปทางซ้าย สังเกตว่ามันจะแบ่งเป็นส่วนๆ ชัดเจน ให้ลองดูตามไปเลยนะครับ

1. ส่วนของ Modules
ส่วนนี้จะอยู่ด้านบนซ้ายสุดของหน้าจอ แบ่งเป็นสองส่วนย่อย

1.1 ส่วนของการจัดการข้อมูลที่ใช้ในเกม
  • Vocab: เก็บข้อความในเกมแทบทั้งหมด ซึ่งมีทั้งข้อความที่แก้ใน script และข้อความที่ดึงมาจาก database ในหน้า Terms
  • Sound: เสียงประกอบต่างๆ ที่ดังข้อมูลมาจาก database ที่เราตั้งไว้ในหน้า System
  • Cache: การดึงข้อมูลที่อ่านไปใส่ลงหน่วยความจำหลัก เพื่อทำให้เกมทำงานเร็วขึ้น (เรื่องมันยาว หากอยากเข้าใจส่วนนี้จริงๆ หลังไมค์ได้ครับ)
1.2 ส่วนของการควบคุมโดยรวมของเกม
ส่วนนี้จะส่วนที่คอยควบคุมข้อมูลต่างๆ ในเกมครับ เทียบได้กับ "ผู้จัดการ" ที่สั่งพนักงานทำงานต่างๆ นั่นเอง
  • DataManager: ในส่วนนี้จะควบคุมการใช้งานข้อมูลในเกมเป็นหลัก เช่น ข้อมูลเซฟ ข้อมูลจาก database ข้อมูลระหว่างการเล่นเกมอยู่ เป็นต้น
  • SceneManager: ใช้ควบคุมการเข้าถึงฉากต่างๆ ของเกม เช่น เมื่อกดเข้าเมนู SceneManager ก็จะมีหน้าสั่งให้เปลี่ยนจาก หน้าจอเกม (Scene_Map) เป็นหน้าจอเมนู (Scene_Menu) เป็นต้น
  • BattleManager: ส่วนควบคุมในกระบวนการต่อสู้แทบทั้งหมดตั้งแต่เริ่มเข้าฉากยันจบการต่อสู้ได้ exp ได้ของ

2. ส่วนของ Game Objects
ในส่วนนี้จะเป็นส่วนของการเก็บข้อมูลต่างๆ ในเกมในขณะที่เล่นอยู่ เช่น ข้อมูลปาร์ตี้ ข้อมูลศัตรู หรืออื่นๆ โดยข้อมูลจะเป็นข้อมูลที่ถูกสร้างระหว่างที่อยู่ในเกม ไม่เกี่ยวข้องกับข้อมูลในฐานข้อมูลแต่อย่างใด เช่น เมื่อเดินเจอศัตรูปุ๊บ ข้อมูลศัตรูที่เจอก็จะถูกสร้าง แล้วก็มีข้อมูล hp, mp, atk, เป็นต้น ซึ่งสังเกตว่าข้อมูลบางอย่างจะมีการเปลี่ยนแปลงได้ตลอดเวลา เช่น เราโจมตี มอนสเตอร์ hp ลด เป็นต้น ในส่วนนี้แบ่งออกเป็นไฟล์ต่างๆ มากมาย และจะขึ้นต้นด้วย Game_ เพื่อแบ่งแยกประเภทชัดเจน

3. ส่วนของ Sprites
ในส่วนนี้จะเป็นส่วนของการจัดการสิ่งของในเกมที่เกี่ยวกับภาพทั้งหมด ไม่ว่าจะเป็นท่าเดินของตัวละคร ภาพตัวละคร ภาพศัตรู รูปภาพ ฉากต่างๆ หรือเอฟเฟกต์ต่อสู้ เป็นต้น

4. ส่วนของ Windows
ในส่วนนี้จะเป็นส่วนของหน้าต่างที่ใช้สื่อสารกับผูเล่นทั้งหมดในเกม ไม่ว่าจะเป็น กล่องข้อความ หน้าต่างตัวเลือก หรือหน้าต่างแสดงรายการเมนู หน้าหน้าต่างแสดงรายละเอียดผู้เล่น หน้าต่างแสดงข้อมูลเครื่องสวมใส่ เป็นต้น พูดง่ายๆ อะไรที่เป็นกล่องๆ มีเส้นขอบขาวๆ พื้นหลังสีน้ำเงิน (ในกรณีที่ไม่ได้ปรับแต่งอะไรเพิ่มเติม) มีข้อความข้างใน จะอยู่ในส่วนของ Windows หมด

5. ส่วนของ Scenes
ในส่วนนี้จะเป็นส่วนของการเก็บฉากต่างๆ ในเกม ไม่ว่าจะเป็นฉาก Title, ฉาก Map (ฉากขณะเล่นเกม), ฉากเมนู, ฉากต่อสู้, ฉาก Game Over เป็นต้น

อย่าสับสนกับส่วนของ Windows นะ หลายคนงงว่าทำไมส่วนของ Windows ก็มี Menu ส่วนของ Scene ก็มี Menu ในที่นี้ส่วนของ Scene จะหมายถึงการเข้าฉากที่เป็นเมนูเกม ซึ่งในเมนูเกมนั้นจะประกอบไปด้วย หน้าต่างเลือกเมนู หน้าต่างแสดงข้อมูลปาร์ตี้ หน้าต่าง หน้าต่างแสดงจำนวนเงิน ซึ่งหน้าต่างทั้งหลายเหล่านี้จะอยู่ใน ฉากของ Menu อีกทีนั่นเอง

RPG Maker VX Ace Database Module
นอกจากส่วนที่อยู่ในหน้าจอ script editor แล้ว ยังมีข้อมูลอีกส่วนหนึ่งที่สามารถเรียกใช้ได้เช่นกัน แต่ไม่มีบอกในหน้าจอดังกล่าว นั่นคือ RPG Module ซึ่งเป็นโมดูลที่เก็บข้อมูล Database เกมทั้งหมด และส่วนใหญ่จะดึงข้อมูลจาก database editor (F9) เมื่อนำไปใช้ในเกม ในส่วนนี้จะเป็นค่าที่เรียกใช้ข้อมูลอย่างเดียว ไม่สามารถเปลี่ยนแปลงแก้ไขขณะอยู่ในเกมได้เลย

แนวคิดในการโม script
เอาล่ะ เมื่อรู้ข้อมูลเบื้องต้นแล้ว ในตอนนี้เราจะสามารถคาดเดาได้บ้างแล้ว ว่าอยากแก้แบบนี้ ควรจะไปแก้ที่ไหน ทุกส่วนที่กล่าวมาล้วนมีความจำเป็นในการโม script ทั้งสิ้น แนวคิดหลักๆ เลยคือ
  1. คาดเดาก่อนเลยว่าการแก้ปัญหาของเรานั้นเข้าเค้าในส่วนไหนของ script ในฝั่งซ้ายของ script editor ชื่อไฟล์แต่ละ script จะบ่งบอกถึงการทำงานในส่วนนั้น
  2. เมือเลือก script ฝั่งซ้ายได้แล้วลองคาดเดาว่าโค้ดส่วนไหนทำงานอะไร ลองค้นหาสิ่งที่เกี่ยวข้อง หากโค้ดมีหลายบรรทัด ให้ลองกด Ctrl+F หาข้อความ
  3. อ่านคอมเมนต์ และคำสั่งของโค้ดให้ดี ทุกอย่างล้วนมีความหมายแฝง
  4. หากไม่เจอ ให้ลองเปลี่ยนคำค้น หรือเปลี่ยน script ฝั่งซ้ายดู เราอาจเลือกผิดก็เป็นได้
  5. หากเข้าตาจน หรือแก้ไม่ได้ Google และเว็บบอร์ดต่างประเทศช่วยท่านได้
เรามาลองทายโจทย์ง่ายๆ กันก่อน ^^

คำถาม อยากแก้ข้อความ Buy, Sell, Cancel ใน shop ทำอย่างไร
[Image: 7capture.jpg]
วิธีการคาดเดา เรารู้ว่าใน Module Vocab นั้นใช้เก็บข้อความในเกมแทบทั้งหมด ฉะนั้นรออยู่ไย ลองเข้าไปหากันเลย แล้วลองสำรวจว่าบรรทัดไหนที่มีข้อความทำนองนั้น ให้แก้โดยพลัน ~
[Image: 7capture.jpg]

คำถาม อยากลบเมนูเซฟเกมในหน้าจอเมนูออกไปเลย ให้ไม่แสดงในหน้าจอเมนู
[Image: 6capture.jpg]
วิธีการคาดเดา ก็ต้องดูก่อนว่าคำสั่งเซฟเกมควรจะอยู่ในส่วนไหนของ script ซึ่งแน่นอนว่ามันอยู่ใน window object อะไรสักอย่างแน่ๆ (เพราะมีลักษณะเป็นกล่องๆ) เมื่อไล่ดูแล้วก็จะพอเดาได้ว่าอยู่ใน Window_MenuCommand ต่อมาลองพิจารณาประมาณบรรทัดที่ 40 ซึ่งเขียนว่า add_save_command โอ้โห! โป๊ะเชะ น่าจะอันนี้แหละ แต่จะลบทิ้งก็ยังไงอยู่ แนะนำให้ลองใส่ # ด้านหน้าบรรทัดดังกล่าวเพื่อ comment แทนการลบ จากนั้นลองรันเกมแล้วเปิดเมนูดู ถ้าเมนูเซฟหายไป แปลว่า ท่านเดาถูกแล้วล่ะ Smile
[Image: 7capture.jpg]

คำถาม เรือ (boat) ในเกมวิ่งช้าจุงเบย อยากให้มันเร็วกว่านี้
วิธีการคาดเดา ในข้อนี้เป็นการแก้ข้อมูลของตัวเกม ดังนั้นมีความเป็นไปได้สูงสุดที่จะอยู่ในส่วนของ Game Objects เราก็ลองไล่ๆ ดู อ๊ะ อันนี้น่าจะเข้าเค้าสุดละ Game_Vehicles นั่นเอง เข้าไปแล้วลองไล่ๆโค้ดดูอย่างใจเย็นๆ บรรทัดประมาณ 34 จะเห็นโค้ด @move_speed = 4 if @type == :boat อ่านแล้วค่อนข้างเข้าใจง่ายมากๆ ว่าแล้วก็ลองแก้จาก 4 เป็น 10 แล้วลองวางเรือ เข้าเกมไปลองขึ้นเรือดู ว้าว เห็นผล วิ่งเร็วยังกับจรวด!!!
[Image: 8capture.jpg]

ในช่วงแรกๆ อาจจะยังเดาได้ไม่คล่อง หรือรู้สึกยาก อย่าท้อครับ ให้พยายามไปเรื่อยๆ เราจะเริ่มจับทางได้เอง ยิ่งใครเคยเขียนโปรแกรมมาก่อน ยิ่งได้เปรียบเลยครับ

จากโจทย์ด้านบน สังเกตว่าเราแก้ปัญหาโดยไปเปลี่ยนโค้ดในส่วนต่างๆ ที่ต้องการ ซึ่งในการใช้จริงในอนาคต การแก้แบบด้านบนเป็นตัวอย่างที่ไม่ดี และไม่แนะนำเป็นอย่างยิ่ง เหตุผลและวิธีการแก้ปัญหาอยู่ในหัวข้อถัดไปเลยจ้า

เข้าใจการ alias method และ overwrite method สิ่งสำคัญที่หลายคนมองข้าม!

ขอบอกล่วงหน้าว่าหัวข้อนี้ค่อนข้างยาวและซับซ้อน ค่อยๆ อ่านใจเย็นๆ นะครับ มันสำคัญมากๆๆๆ สำหรับผู้ที่ต้องการเขียน script อย่างจริงจังในอนาคต หากเข้าใจทั้งหมด มันคือกำไรชีวิตแน่นอนครับผมการันตี

ในหัวข้อก่อนหน้าเรามีคำแนะนำทิ้งท้ายว่าวิธีการแก้โค้ดในส่วนต่างๆ นั้น ไม่แนะนำอย่างยิ่ง สิ่งที่ผมต้องการจะสื่อจริงๆ นั่นคือ ไม่ควรเพิ่ม / ลบ / แก้ไข โค้ดต้นฉบับที่มีอยู่แล้วนั่นเอง (ยกเว้น module Vocab ที่พออนุโลมได้) เพราะมันมีผลกระทบดังนี้
  1. สมมุติท่านแก้ส่วนต่างๆ ของสคริปต์เยอะมากกกกกกกกกกกกกก วันดีคืนดีอยู่ดีๆ เกมพัง รันแล้วแฮงก์ หาสาเหตุไม่ได้ ไม่รู้จะไปแก้ที่ไหน จะเอาโค้ดต้นฉบับมาทับโค้ดที่แก้ไปแล้วก็ไม่ได้ เพราะสิ่งที่เคยแก้ไว้ก็หาย ในวันนั้นเกมของท่านอาจได้ลงสุสานทันที
  2. สมมุติท่านสร้างเกมหลายๆ เกม แล้วต้องการเอาระบบที่ท่านแก้บางส่วนไปใช้ในเกมอื่นๆ ของท่าน ท่านก็จะไม่รู้ว่าต้องเอาจาก script ไหนบ้าง
  3. อนาคตหาก RPG Maker มีการอัพเดทแพทช์ (หวังว่านะ 555+) มีแก้สคริปต์ต่างๆ บางแห่ง ในวันนั้นท่านจะต้องเอา script ของเวอร์ชั่นใหม่มาทับของเก่า แต่ของเก่าท่านปรับแต่งแก้ไขไว้เยอะแยะ ดังนั้นจึงยากที่จะจัดการสิ่งที่ท่านได้แก้ไว้
อ้าว แล้วไม่แก้ที่โค้ดที่มี แล้วจะไปแก้ที่ไหน? คำถามนี้ต้องผุดในหัวของท่านแน่นอน
ซึ่งคำตอบมีอยู่สองหนทางก็คือ
  • การ overwrite script
  • การ overwrite script ด้วยวิธีการ alias method
ก่อนที่จะรู้จักทั้งสองอย่างด้านบน ต้องเข้าใจว่า class และ method คืออะไรเสียก่อน ซึ่งจะอธิบายให้เข้าใจคร่าวๆ เน้นเอาไปใช้งาน เพราะจริงๆ แล้วมันเป็นเรื่องที่ค่อนข้างซับซ้อนและเปิดคอร์สเรียนได้เป็นเทอมๆ เลย *0* [คนที่เขียนโปรแกรมเป็นอ่านแล้วอย่าเพิ่งหงุดหงิดนะครับ ผมเน้นอธิบายให้นำไปใช้ง่ายคร้าบ]

ให้พิจารณาโค้ดด้านล่างนี้
[Image: class.png]

โค้ดใน RGSS มักจะอยู่ในรูปแบบนี้เสมอ (ยกเว้นในส่วนของ Module จะเปลี่ยนจากคำว่า class เป็น module แทน) ซึ่งชั้นนอกจะเรียกว่า class และในคลาสจะประกอบไปด้วยสิ่งที่เรียกว่า method

ตัวอย่างเช่น โค้ดบรรทัดที่ 9 โค้ด @energy = -20 นั้นอยู่ใน method ชื่อ run และอยู่ใน class ชื่อ Person หรือโค้ดบรรทัดที่ 21 นั้นอยู่ใน method ชื่อ go_forward และอยู่ใน class ชื่อ Car เป็นต้น พอจะดูออกแล้วใช่ไหมครับ ทีนี้อยากให้ท่านลองดู script ต่างๆ ที่มีใน script editor สังเกตว่าแทบทุกไฟล์จะมีรูปแบบเหมือนกับภาพตัวอย่างเลยใช่ไหมครับ นั่นคือมี class มี method

ต่อมาอยากให้ท่านกด F11 แล้วในฝั่งซ้าย เลื่อนลงมาล่างๆ จะเจอกับส่วนที่เรียกว่า Materials ลองคลิกขวา ตรงคำว่า ( Insert here ) แล้วเลือก Insert จะได้ช่องเปล่าเพิ่มขึ้นมา 1 ช่อง ในส่วนของ Name ให้ตั้งชื่ออะไรก็ได้ จากตัวอย่างนี้ ให้ตั้งเป็น My Script ละกันครับ

สิ่งที่ท่านได้ทำไปคือการสร้างไฟล์ใหม่ขึ้นมานั่นเอง ซึ่งเป็นไฟล์เปล่าๆ ที่จะใช้เขียน script อะไรก็ได้ลงไป เราจะใช้ที่ว่างใหม่นี้ในการเขียนโค้ดเพิ่มเติมโดยไม่ไปยุ่งกับโค้ดส่วนเก่าอีกเลย

เมื่อเข้าใจกระจ่างแล้ว ย้อนกลับไปที่การ overwrite script และการ alias method ดีกว่า

การ Overwrite Script
วิธีการนี้จะเป็นการเขียนโค้ดทับโค้ดเก่าแบบดื้อๆ เพื่อให้ตัวเกมอ่านโค้ดใหม่ของเราเป็นหลักแทนที่จะอ่านโค้ดเดิมที่มีอยู่ ซึ่งการที่จะ overwrite script ได้นั้นจำเป็นต้องรู้ว่าอยู่ใน method ไหนและอยู่ใน class อะไรเสมอ

ตัวอย่างจากคำถามข้อ 2 ในหัวข้อที่ผ่านมา

คำถาม อยากลบเมนูเซฟเกมในหน้าจอเมนูออกไปเลย ให้ไม่แสดงในหน้าจอเมนู

เราจะไม่ลบ add_save_command เหมือนที่ผ่านมาแล้ว แต่ให้ท่านสังเกตว่า add_save_command นั้นอยู่ใน method อะไร และใน class อะไร (อย่าเพิ่งอ่านต่อนะ ลองคิดเองก่อน หุหุ)

ซึ่งจะพบว่าอยู่ใน method make_command_list และ class Window_MenuCommand < Window_Command ใช่ไหมครับ (เครื่องหมาย < คืออะไรไม่ต้องสนใจในจุดนี้ เอามันมาทั้งบรรทัด เหมือนเดิม อธิบายที่นี่ยาวแน่นอน *0*)

ให้เราไปที่ script ที่เพิ่งสร้างขึ้นใน Materials เมื่อตะกี๊ แล้วเขียนโค้ดดังนี้
[shcode=rails]
class Window_MenuCommand < Window_Command
def make_command_list
add_main_commands
add_formation_command
add_original_commands
add_game_end_command
end
end
[/shcode]

สังเกตว่าเราดึง class และ method มาเขียนลงไฟล์ใหม่นั่นเอง และใน method ที่เขียนใหม่ของเรานั้นมีโค้ดเหมือนอันเก่าทุกประการ แต่ได้เอา add_save_command ออกไป (ต้องมีโค้ดใน method ส่วนเดิมให้ครบนำ สำคัญมาก เพราะเกมจะไม่อ่านโค้ดเดิมอีกแล้ว)

เมื่อเรารันเกม เกมก็จะมาอ่าน method make_command_list ใน class Window_MenuCommand < Window_Command ที่เราเขียนใหม่ แทนที่จะไปอ่านของเดิม

ผลลัพธ์การรันเกมจะเหมือนตัวอย่างที่ทำอันที่แล้วทุกประการ

นี่แหละที่เรียกว่า การ overwrite script ซึ่งการเขียน overwrite ใหม่นั้น ไม่จำเป็นว่าในคลาสต้องมีเพียง method เดียว อาจจะ overwrite โดยเขียนหลายๆ method ไว้ใน class เดียวเลยก็ได้ (หากแก้หลายที่) และที่สำคัญ อาจสถาปนา method ขึ้นใหม่ด้วยชื่อใหม่เองก็ได้ (แต่การเขียน method ขึ้นใหม่เองอาจยังไม่เหมาะกับมือใหม่ จะไม่กล่าวในบทความนี้)

แล้วโค้ดเดิมไปไหน ทำไมจึงเป็นเช่นนั้น?

หลักการของภาษา Ruby นั่นคือ หากเจอ class ซ้ำกัน หรือ method ซ้ำกันที่อยู่ใน class เดียวกัน มันจะใช้งานโค้ดที่อยู่ด้านล่างเป็นหลัก ซึ่งหากเราพิจารณาแล้ว script ส่วนของ Materials ที่เราเขียนเพิ่ม มันแทบจะอยู่ล่างสุดเลยใช่ไหมครับ มันจึงเป็นเหตุผลว่าทำไมโปรแกรมถึงจัดวางที่เขียนโค้ดให้เราด้านล่างนั่นเอง ^^

นอกจากนี้ยังสามารถ overwrite โค้ดใน class นอก method ได้อีกด้วย แต่ช่างมันเต๊อะ ไว้จะเขียนให้ในบทความที่ advance กว่านี้นะคับ แหะๆ

การ Alias Method
หลังจากที่รู้จักการ overwrite script ไปแล้ว ยังมีอีกสิ่งหนึ่งเรียกว่า การ alias method ซึ่งขอเกริ่นนำด้วยตัวอย่างโจทย์เลยละกันครับ

คำถาม: อยากให้เลเวลอัพแล้วฟื้นฟูเลือดจนเต็ม
ลองหาวิธีก่อนนะครับ อาจจะยังทำไม่ได้ไม่เป็นไร ลองมาดูเฉลยครับ

ขอทำด้วยวิธีการ overwrite เหมือนอันที่แล้วเพื่อให้เห็นภาพก่อนครับ

ข้อนี้มี keyword ตรง level up ลองนึกดูว่าอะไรที่สามารถ level up ได้ นั่นก็คือตัวละครนั่นเอง ซึ่งตัวละครใน RPG Maker จะใช้คำว่า Actor ซึ่งมี script ที่เข้าเค้าคือ Game_Actor (ไม่ใช่ Game_Actors นะ ดูดีๆ) เข้าไปแล้วหากโค้ดมีหลายบรรทัดลองกด Ctrl+F เพื่อหาเอาเลยครับ ลอง search ว่า level แล้วไล่ดูเรื่อยๆ จะพบ method ที่น่าสนใจคือ method level_up ประมาณบรรทัดที่ 426 งวดนี้จะไม่ได้แก้ข้อมูลด้านใน แต่ละเพิ่มคำสั่งเข้าไปใน method แทน ให้ทำการหา class ของ method นี้ด้วย เพื่อจะทำการเขียนโค้ด overwrite ใหม่

ไปที่ โค้ดที่สร้างขึ้นใน Materials เหมือนเดิม ไฟล์เดิมก็ได้ครับ จากนั้นก็อปโค้ดส่วน method level_up ที่เราหามาได้ แล้วอย่าลืมใส่ class ที่หามาครอบด้วยนะ เขียนต่อโค้ดเก่าที่มีได้เลย (ไฟล์นึงจะมีกี่ overwrite ก็ได้ แต่หากเขียนโค้ดเยอะขึ้น แยกให้เป็นหมวดหมู่ก็ดีครับ)

ทำแล้วได้เหมือนผมไหมครับ

[shcode=rails]
class Game_Actor < Game_Battler
def level_up

# โค้ดเดิมก็อปมาใส่ใหม่
@level += 1
self.class.learnings.each do |learning|
learn_skill(learning.skill_id) if learning.level == @level
end

# โค้ดใหม่
@hp = mhp #ตั้ง hp ของเรา ให้มีค่าเท่ากับ max hp
@mp = mmp #ตั้ง mp ของเรา ให้มีค่าเท่ากับ max mp

end
end
[/shcode]

@hp กับ @mp เป็นตัวแปรที่ใช้แทน hp, mp ปัจจุบันของตัวละครดังกล่าว ส่วน mhp, mmp เป็นตัวแปรอ้างถึง max hp, max mp ครับ (ส่วนรู้ได้ยังไงว่าหาจากไหน อาศัยประสบการณ์การแกะโค้ดและการหาข้อมูลจาก google เอาครับ หาเรื่อยๆ อ่านเรื่อยๆ เดี๋ยวก็เข้าสมองเองครับ หุหุ)

สังเกตว่าการ overwrite นั้นจำเป็นต้องใส่โค้ดเก่าด้วยเสมอ (เพราะอย่าลืม มันไม่อ่านโค้ดเดิมอีกแล้ว) แล้วในข้อนี้เราแค่เติมโค้ดเพิ่มเข้าไปสองบรรทัด ซึ่งในการทำ overwrite นั้น มีข้อเสียอยู่เช่นกัน (แต่ยังไงก็ดีกว่าแก้โค้ดเดิมแน่นอนครับ)

ข้อเสียของการเขียน overwrite
  1. เราต้องเขียนโค้ดเก่าซ้ำๆ ซึ่งอาจเกิดปัญหาหากเผลอไปแก้โค้ดเก่าที่มี (ยกเว้นเจตนาแก้)
  2. ในกรณีที่โหลดโค้ดของคนอื่นมาใช้ โค้ดอาจตีกันกับของเราได้
อธิบายข้อที่สองสักหน่อยละกัน ว่ามันตีกันยังไง สมมุติเราแก้โค้ดเลเวลอัพของเราให้มีเลือดเต็มตามตัวอย่างเมื่อกี๊ แล้วเรามีโค้ดของคนอื่นที่โหลดมาลงใน Material ด้วย แต่บังเอิ๊ญญญ โค้ดของคนอื่นที่โหลดมานั้นดันมีส่วนที่เขียนว่า หากเลเวลอัพแล้วได้ตัง 5000G ดังนี้

[shcode=rails]
class Game_Actor < Game_Battler
def level_up
@level += 1
self.class.learnings.each do |learning|
learn_skill(learning.skill_id) if learning.level == @level
end
$game_party.gain_gold(5000) # คนอื่นใส่โค้ดนี้เพิ่มมา
end
end
[/shcode]

ลองทายดูสิครับว่า หากมีทั้งโค้ดของเรา และโค้ดของคนอื่นดังกล่าว ผลจะเป็นอย่างไรครับ...
แน่นอนว่า จากกฎการ overwrite มันจะทำงานเฉพาะอันที่อยู่ล่างสุดใช่ไหมครับ ^^
ดังนั้น หากโค้ดของเราอยู่ด้านล่าง เมื่อเลเวลอัพตัวละครก็จะเลือดเต็มเท่านั้น และหากโค้ดของคนอื่นอยู่ด้านล่าง เมื่อเลเวลอัพก็จะได้เงินเพิ่ม 5000G เท่านั้น...

วิธีการ alias method จะมาแก้ปัญหาข้างบนนี้

การประกาศ alias method หมายถึงการสร้าง method ใหม่ขึ้นมาให้มีโค้ดเหมือน method เดิม และสามารถตั้งชื่อ method ใหม่ที่ก็อปมาได้ โดยมีรูปแบบการเขียนดังนี้
alias_method :copied_method_name, :current_method_name

เช่น
[shcode=rails]
def run
p "Go go!"
p "Wow, very quickly."
p "Run Run Run!"
end
[/shcode]

จากนั้นบรรทัดถัดมาผมเพิ่ม

[shcode=rails]
alias_method :run_copied, :run
[/shcode]

จากโค้ดด้านบน เป็นการ copy method run_copied เพิ่มมาอีกอัน และมีคำสั่งด้านในเหมือน method run ในปัจจุบัน ดังนั้น มันจะแอบไปเพิ่มโค้ดด้านล่างนี้ขึ้นมาเอง (เราไม่ต้องเขียนนะ)

[shcode=rails]
def run_copied
p "Go go!"
p "Wow, very quickly."
p "Run Run Run!"
end
[/shcode]

แล้วมีประโยชน์อย่างไร
สมมุติผมมีโค้ดด้านบนแล้ว ผมต้องการ overwrite method run ด้านบน ปรกติผมเขียนแบบนี้ใช่ไหม

[shcode=rails]
def run
p "Go go!"
p "Wow, very quickly."
p "Run Run Run!"
p "YEAHHHHHHHHHH!!!" # เพิ่มเข้ามา
end
[/shcode]

เนื่องจากมีการ copy method ไปใส่ใน run_copied แล้ว ผมสามารถเขียนใหม่เป็นแบบนี้ได้

[shcode=rails]
def run
run_copied # เรียก method ชื่อ run_copied
p "YEAHHHHHHHHHH!!!" # เพิ่มเข้ามา
end
[/shcode]

ซึ่งหลักการทำงานจะเป็นดังนี้
[Image: 9untitled-3.jpg]

ในครั้งนี้ เราได้ทำการ override method run โดยใช้การเรียก method run_copied ด้านใน แล้วต่อด้วยคำสั่งที่ต้องการเพิ่ม ทำให้การ overwrite เราไม่จำเป็นต้องพิมพ์คำสั่งทั้งหมดที่อยู่ใน method run เดิมอีกต่อไป ซึ่งทำให้ลดความซ้ำซ้อนลงได้เป็นอย่างมาก

ทีนี้มันแก้ปัญหาโค้ดตีกันกับชาวบ้านได้อย่างไร มาดูกันครับ
กลับมาที่โค้ดเลเวลอัพเหมือนเดิม ผมแก้โค้ดของผมจากโค้ดเดิมเป็นอันนี้

[shcode=rails]
class Game_Actor < Game_Battler
alias_method :level_up_copied, :level_up
def level_up
level_up_copied
# โค้ดใหม่
@hp = mhp #ตั้ง hp ของเรา ให้มีค่าเท่ากับ max hp
@mp = mmp #ตั้ง mp ของเรา ให้มีค่าเท่ากับ max mp
end
end
[/shcode]

แล้วผมเอาไปไว้ใต้โค้ดของคนอื่น (ที่เลเวลอัพแล้วเพิ่ม 5000G) ย้ำว่าเอาไว้ข้างใต้นะครับ!
ลองรันเกมดู จะพบว่าเมื่อเลเวลอัพ เราจะได้ทั้งเงิน 5000G และเลือดตัวละครที่เลเวลอัพเต็มไปพร้อมกัน

เพราะอะไร ฝากไปคิดเป็นการบ้านนะครับ Big Grin Big Grin Big Grin
ฝากการบ้านอีกข้อครับ ถ้าหากเราเอาโค้ดของเราไว้ด้านบนโค้ดของคนอื่น (ที่เลเวลอัพแล้วเพิ่ม 5000G) แทนล่ะ จะเกิดอะไรขึ้น เพราะอะไร Big Grin

โอโหวววว alias method ดีขนาดนี้ ทำไมไม่ใช้มันทุกครั้งไปเลย
แม้ว่าการแก้ปัญหาด้วยวิธีการ alias method นั้นจะเป็นไปได้ด้วยดี แต่ว่ามันมีข้อจำกัดคือ เราสามารถใช้วิธีได้ หากเป็นกรณีที่เราแทรกโค้ดเพิ่มเท่านั้น เราไม่สามารถลบของได้เลย

เช่น จากคำถามเมื่อปีมะโว้ ถ้าเราต้องการเอาเมนูเซฟออก ก็ไม่สามารถใช้วิธี alias method ได้ เพราะเราต้อง ลบโค้ดบางส่วนออกจากของเดิมนั่นเอง (แต่จริงๆ มันก็ได้แหละ แต่อาจจะตองใช้กระบวนท่าซับซ้อน)

สรุปข้อดีของการ overwrite script
  • ง่ายต่อการตรวจบั๊ก
  • หากเจอ error ในเกม จนเกมพัง หาสาเหตุไม่เจอ อย่างมากก็แค่นำ script ในส่วน material ออกให้หมด หรือเอาออกเป็นตัวๆ เพื่อหาสาเหตุ
  • เพียงแค่ Copy Paste ไฟล์ที่ท่านเขียนเพิ่มใน Materials ก็สามารถเอาไปใช้กี่เกมก็ได้
  • หากเขียนจนคล่องแล้ว สามารถรวบรวมสคริปต์เป็นไฟล์เดียวแล้วแจกคนอื่นได้ เหมือนกับที่คนอื่นเขียน script แจกทุกวันนี้นั่นเอง
  • ไม่ต้องกลัวปัญหาเรื่อง RPG Maker อัพเดต (แต่อาจมีปัญหาหาก RPG Maker ดันไปแก้ script ที่เรา overwrite แต่ถ้าใช้ alias method ได้จะปราศจากปัญหาทั้งปวง)

สรุป
  • หากเป็นไปได้ ให้ใช้ alias method เอาไว้ก่อนเลย เพราะนอกจากโค้ดจะสะอาด ไม่ตีกันแล้ว ยังแสดงถึงมารยาทที่ดีในการเขียนโค้ดเพื่อนำไปแจกผู้อื่นด้วย เพราะเราการันตีได้ว่าโค้ดของเราจะไม่ไปทับของคนอื่นอย่างแน่นอน
  • ถ้าใช้ไม่ได้จริงๆ ค่อยเขียน overwrite แบบธรรมดา แม้อาจจะเกิดปัญหาโค้ดตีกันกับโค้ดคนอื่นหากนำไปแจกผู้อื่น แต่มันก็เป็นเรื่องช่วยไม่ได้จริงๆ
  • จงจำเอาไว้ว่าไม่ควรไปแตะต้องโค้ดเหนือส่วน Material (ยกเว้น module Vocab พออนุโลม) ควรใช้วิธี overwrite ให้ติดเป็นนิสัยนะครับ อย่าคิดว่าแก้นิดหน่อยแก้ทับโค้ดเดิมก็ได้ เพราะมันจะทำให้ปัญหาบานปลายภายหลัง ลองสังเกตบอร์ดต่างประเทศดูครับ มีคนมาขอ script แม้จะแก้บรรทัดเดียวเขาก็ตอบด้วยการใช้วิธี overwrite แล้วไปใส่ใน Materials ครับ

สรุปทั้งหมด
สิ่งที่บทความนี่ต้องการสื่อคือ บอกแนวทางการโม script และการเขียน script ให้เป็นระเบียบ ดังนั้นหากอ่านจบแล้วยังรู้สึกว่าโมอะไรไม่ได้เลย อย่าเสียใจหรือท้อแท้นะครับ เพราะสิ่งที่ท่านได้รับในบทความนี้คือพื้นฐาน แนวทางและทฤษฎี ยังไม่ได้ลองปฏิบัติก็ไม่แปลกที่ยังทำไม่ได้ครับ อนึ่ง สังเกตว่าสิ่งที่แก้ในบทความนี้นั้น มักจะเป็นการ เดา เดา และเดา ใช่ครับ การแก้โค้ดของคนอื่นไม่ใช่เรื่องง่าย ไม่ว่าจะเป็น RGSS หรือโค้ดภาษาอะไรในโลกก็ตาม ดังนั้นหากเป็นครั้งแรกที่ท่านทำอะไรแบบนี้แล้วไม่รู้เรื่อง งง ก็อย่าแปลกใจครับ อาศัยประสบการณ์ฝึกฝนเอาครับ เราฟันธงไม่ได้หรอกว่าโค้ดส่วนไหนคืออะไร แต่เนื่องจากโครงสร้างที่ผู้สร้าง RGSS ออกแบบมาดีมาก รวมถึงมีคอมเมนต์สีเขียวที่อ่านเข้าใจง่าย เชื่อผมว่า ฝึกไม่นานครับ ^^

และแน่นอนว่า ท่านก็อาจไม่รู้เหมือนกันว่าจะเก็บประสบการณ์จากไหน เพราะไม่รู้จะฝึกอย่างไร ในจุดนี้หากมีคนสนใจบทความนี้เป็นจำนวนหนึ่ง ผมจะตั้งกระทู้ใหม่เรื่อยๆ เป็น WORKSHOP ให้ทำ ตั้งแต่การตั้งโจทย์ แนวคิด วิธีแก้ไขปัญหา ไปจนถึงการเขียนโค้ดทุกขั้นตอน ดังนั้นไม่ต้องกลัวครับ ผมมีโจทย์มาให้ฝึกแน่นอน ^^

และผมยังคงบอกได้คำเดิมว่า เนื้อหาในบทความนี้เป็นเพียงเนื้อหาเบื้องต้นเท่านั้น ในการฝึกช่วงแรกๆ อย่าไปโมอะไรที่มันหลุดโลกเกินไป เพราะในบางเคสนั้น การเดาโค้ดอาจต้องกระโดดไปมาดู 4-5 ไฟล์ถึงจะเข้าใจว่าโค้ดทำงานอย่างไร ทำไม่ได้จะท้อเปล่าๆ ซึ่งหากมีเวลาว่างพอ ผมจะมาเขียนบทความในส่วนของเทคนิคการเดาโค้ดแบบกระโดดข้ามไฟล์อีกครั้งครับ ตอนนี้เอาส่วนนี้ให้แม่นก่อนละกันนะคร้าบ

แต่ถ้ามั่นใจว่าทำได้ ลุยเลยครับผม!

สุดท้ายนี้ ขอให้สนุกกับการเขียนโค้ดทุกคนครับ Big Grin

แบบฝึกหัด
ทุกข้อต้องใช้วิธีการ overwrite / alias method ตามความเหมาะสม
ให้สร้างโปรเจกต์ใหม่ขึ้นมา โดยไม่ต้องใส่ script อื่นใด
  1. จากคำถามสามข้อที่ผ่านมาในหัวข้อ "แนวคิดในการโม script" จงทำให้อยู่ในรูป overwrite / alias method ตามความเหมาะสม
  2. ในหน้าจอโหลดเกม เซฟเกม จะมีการไล่ไฟล์โดยมีข้อความ File 1, File 2, ... อยากเปลี่ยนเป็น Slot 1, Slot 2, ... ต้องทำอย่างไร
  3. จำนวนช่องเซฟเกมมีมากเกินไป อยากให้เหลือ 8 ช่องพอ
  4. โดยปกติแล้ว การขายไอเท็มจะขายได้ในราคาครึ่งหนึ่งของราคาซื้อ รู้สึกว่ามันน้อยเกินไปจังเลย อยากให้ขายได้ในราคา 75% ของราคาซื้อ แก้อย่างไรดีน้า...
  5. ในหน้าจอเปลี่ยนชื่อตัวละคร เมื่อกดปุ่ม Page แล้วมันจะพาไปยังหน้าภาษา Latin อื่นๆ ที่ไม่ใช่ภาษาอังกฤษ (ลองดูได้) ไม่อยากได้หน้านั้นเลย ต้องทำอย่างไร
  6. ในฉากต่อสู้ทั่วไป สามารถกด Escape เพื่อหนีศัตรู ซึ่งเดิมจะมีโอกาสที่จะหนีไม่พ้น อยากทราบว่าการหนีพ้นหรือไม่พ้นขึ้นกับปัจจัยใด และถ้าหากต้องการให้โอกาสหนีเป็น 100% จะต้องทำอย่างไร
  7. อยากให้ตัวละครเดินกลับทิศกับลูกศรคีย์บอร์ด (กดขึ้นเดินลง กดซ้ายเดินขวา เป็นต้น) ทำอย่างไร
  8. อยากให้การแสดงชื่อแผนที่เป็นแบบนี้ ทำอย่างไร (ปกติจะอยู่ริมซ้าย) (เฉพาะ RGSS3)
    [Image: 10capture.jpg]
This post was last modified: 06-12-2015, 03:17 PM by splendith.
Neoz Kaho   06-12-2015, 03:07 AM
#2
ชอบมากครับบทความนี้ เกลียดสุดๆ เลยการต้องโมสคริปต์แล้วมานั่งงงตายแปป พอมีอธิบายแบบนี้ค่อยเข้าใจง่ายขึ้นเยอะเลย

[Image: 7wDGQYA.png][Image: 76561197983021669.png]
Mysticphoenix   06-12-2015, 08:02 AM
#3
มีประโยชน์มากเลยคับ

[Image: webboard%20signature1_zpskhtut2jg.png]
การทำอาหารที่อร่อยที่สุด และเดือดร้อนชาวบ้านมากที่สุด กำลังจะเริ่มขึ้น
dreamknight   06-12-2015, 08:29 AM
#4
;3

ปักหมุดไว้เลยครับ กระทู้แบบนี้ ;w;b

May the flames guide your way. Every ending will make you stronger.

Nazuth Away   06-12-2015, 08:30 AM
#5
เยี่ยมครับเดี๋ยวปักหมุดกระทู้ไว้ให้คนศึกษาเลย

[Image: 76561198134933497.png]
Show ContentFanPage:


anime13master   06-12-2015, 08:57 AM
#6
โคตรจะมีประโยชน์เลยครับ ท่านอธิบายได้เข้าใจง่ายและเห็นภาพมากๆ

ส่วน Aliasing นี่ผมยังทำไม่เป็นเลย ใช้วิธี Overwrite เอาตลอด พออ่านบทความท่านแล้วเข้าใจหลักการ ที่นี้ก็ทำเป็นขึ้นมาทันทีเลยทีเดียว
This post was last modified: 06-12-2015, 09:00 AM by anime13master.
Muge9thD   06-12-2015, 09:20 AM
#7
อธิบายได้เข้าใจง่ายดีฮับ จากที่เคยเข้าใจอะไรผิดๆในส่วนของการ alias ก็เข้าใจได้ถูกต้องกว่าเดิมแล้ว

[Image: 3e1d83fcd8.png]
[Image: 76561198067540196.png][Image: AddFriend.png]
lottovvv   06-12-2015, 10:41 AM
#8
ขอบคุณมากๆ ค่ะ เดี๋ยวมีเวลาแล้วจะมานั่งศึกษา/ทดลองจริงๆ จังๆ ซะที

[Image: 76561198124900776.png]
zychrominny   06-12-2015, 02:00 PM
#9
กระทู้เลอค่า ต้องปริ้นเก็บไว้อ่านเสียแล้ว หวานจุงเบย
splendith   06-13-2015, 01:38 AM
#10
ขอบคุณทุกท่านสำหรับความเห็นนะครับ
และขอขอบคุณเป็นอย่างยิ่งที่เห็นความสำคัญและปักหมุดบทความเล็กๆ บทความนี้ -/\-

ถ้ามีโอกาสจะเขียนบทความเกี่ยวกับ พื้นฐาน Ruby และ Class โดยละเอียดอีกครั้งครับ Big Grin
  
Users browsing this thread: 6 Guest(s)
Powered By MyBB, © 2002-2024 MyBB Group.
Made with by Curves UI.