Script Workshop - มาสร้างไอเท็ม Exp, Gold X2 ในฉากต่อสู้กัน
บทความนี้จะสอนการเขียน script ขึ้นมา ซึ่งจะเล่าแนวคิดการเขียนตั้งแต่ต้นจนจบ หากฝึกจนชำนาญแล้ว ท่านสามารถนำไปประยุกต์ใช้ทำ script อื่นๆ แจกจ่ายได้เลย ^^ (เขียนสลับไปมากับบทความพื้นฐาน เดี๋ยวคนมีความรู้อยู่แล้วจะเบื่อซะก่อน แหะๆ)
ความยาก: ปานกลาง
ความรู้พื้นฐานที่ควรมี
ลองอ่านๆ แล้วค่อยๆ ทำความเข้าใจดูนะครับ ถ้าพอเข้าใจคอนเซ็ปต์ก็เวิคเลย แต่ถ้าอ่านแล้วไม่รู้เรื่องไม่ต้องกังวลไปครับ วันไหนที่มีความรู้พื้นฐานแล้วกลับมาอ่านใหม่ ท่านจะเข้าใจมากขึ้น
ในบทความนี้จะทำการเขียน script สร้างไอเท็มดังนี้
- Rich Potion - ใช้แล้ว Gold X2 ในฉากต่อสู้ เป็นระยะเวลา 1000 ก้าว
- Master Potion - ใช้แล้ว Exp X2 ในฉากต่อสู้ เป็นระยะเวลา 1000 ก้าว
ซึ่งเมื่อใช้งานไอเท็มแล้ว จะมีสถานะบอกที่มุมบนขวาของจอด้วย
และเมื่อไอเท็มหมดฤทธิ์ กล่องข้อความก็จะหายไปอัตโนมัติ เพื่อไม่ให้รกจอนั่นเอง
แนวคิดของผม
แน่นอนว่าวิธีการเขียนอาจจะมีหลายวิธี ไม่มีผิดไม่มีถูกเสมอไป แต่ผมจะยึดแนวคิดของผมเป็นหลักในบทความนี้ สมมุติว่าผมอยากทำ script อันนึงเพื่อแจกจ่ายผู้อื่น หากเริ่มตั้งแต่ 0 ผมมีกระบวนการคิดอย่างไรในการเขียนมันขึ้นมา
1. สร้างไฟล์เปล่าขึ้นมาก่อนเลย
แน่นอนว่าการนำ script ไปแจกคนอื่นนั้น จะต้องสร้างไฟล์ script ขึ้นมาเพื่อให้ผู้อื่นนำไฟล์ script เราไปใช้ในอนาคต ให้คลิกขวาสร้างไฟล์เปล่าขึ้นมา แล้วตั้งชื่อว่า Bonus Exp, Gold
หมายเหตุ: เราจะไม่แก้โค้ดเดิมเด็ดขาดนะครับ ให้จำเอาไว้ว่าทุกครั้งที่ให้เขียนโค้ดหรือแก้โค้ด มันคือการเขียนที่ไฟล์ที่เราสร้างใหม่นี้เสมอครับ
2. ทำทีละอย่าง
หากยังไม่ชำนาญแล้ว แนะนำให้แก้โจทย์ทีละอย่างครับ เพื่อง่ายต่อความเข้าใจ
ดังนั้นในส่วนแรกนี้ผมจะทำแต่ไอเท็ม gold X2 โดยยังไม่ไปยุ่งกับ exp นะครับ
3. หาโค้ดส่วนที่ได้รับ gold หลังการต่อสู้
ผมก็จะวิเคราะห์ก่อนว่า ถ้าเราจะให้ gold x2 ก็ควรจะต้องคูณมันตอนเราได้รับเงินหลังต่อสู้ใช่ไหมครับ ซึ่ง script ที่จัดการเกี่ยวกับการต่อสู้ทั้งหมดนั้น อยู่ใน module BattleManager (ไฟล์ประมาณบนซ้าย) ว่าแล้วผมก็กดเข้าไปทันที ลองหาๆ ด้วย Ctrl + F ดูแล้ว ก็จะได้โค้ดที่เข้าเค้าที่สุด อยู่ที่ประมาณบรรทัดที่ 316 ดังรูป
ว่าแล้วก็ทำการ overwrite code นี้ออกมาไว้ที่ไฟล์เปล่าของเราที่สร้างในขั้นตอนที่ 1 เลย (ครอบด้วย module BattleManager ด้วยนะ ในกรณีที่เป็น module ไม่ใช่ class เราจะครอบด้วย module แทน)
[shcode=rails]
module BattleManager
def self.gain_gold
if $game_troop.gold_total > 0
text = sprintf(Vocab::ObtainGold, $game_troop.gold_total)
$game_message.add('\.' + text)
$game_party.gain_gold($game_troop.gold_total)
end
wait_for_message
end
end
[/shcode]
อยากให้ gold x2 ทำยังไงครับ ผมลองเดาโค้ดแล้วแก้ดูเป็นดังนี้
[shcode=rails]
module BattleManager
def self.gain_gold
if $game_troop.gold_total > 0
text = sprintf(Vocab::ObtainGold, $game_troop.gold_total * 2) # แก้บรรทัดนี้
$game_message.add('\.' + text)
$game_party.gain_gold($game_troop.gold_total * 2) # แก้บรรทัดนี้
end
wait_for_message
end
end
[/shcode]
ให้ลองรันเกมดู แล้วไปหาเรื่องสู้กับมอนสเตอร์ ตรวจสอบดูว่าได้เงินเพิ่มจริงหรือไม่ ถ้าเงินเพิ่มจริง แปลว่าเดาถูกแล้วล่ะ
4. ควบคุมเงื่อนไขการคูณ gold ด้วยบงการอะไรซักอย่าง
ทีนี้สิ่งที่ผมอยากได้นั้นไม่ใช่ gold X2 ตลอดกาลแบบนี้ แต่ต้องการให้ gold X2 เฉพาะเวลาที่ใช้ไอเท็ม และมีเวลาจำกัดเป็นจำนวนก้าว ดังนั้น ผมจะไม่เขียน * 2 ไปตรงๆ แบบนั้นแล้ว แต่จะนำไปคุณตัวแปรอะไรสักอย่างที่คอยบงการอีกที
ซึ่งถ้าเราอ่านโค้ดบรรทัดที่ 6 ดูดีๆ แล้ว เราจะเดาได้ว่ามันคือคำสั่งเพิ่มเงินให้กับปาร์ตี้ของเราด้วยจำนวนที่ระบุในวงเล็บ และมีตัวแปร $game_party ในการควบคุมข้อมูลปาร์ตี้อยู่ ดังนั้น ผมจะเพิ่มเจ้าตัวแปรบงการการคูณเงินของเราในข้อมูลปาร์ตี้เช่นกัน ซึ่งเราก็ต้องไปดูว่าตัวแปร $game_party นั้นมันไปอ่านข้อมูลจากโค้ดที่ไหน ในขั้นตอนนี้ให้ไปดูที่ไฟล์ script ใน module DataManager ครับ ให้สังเกตประมาณบรรทัดที่ 82+
ในบรรทัดที่ 91 เราจะเห็นว่ามีการประกาศตัวแปร $game_party ให้มีค่าเท่ากับ Game_Party.new ในบรรทัดนี้ถ้ามีความรู้การเขียนโปรแกรมเชิงวัตถุ จะทราบว่า ให้เป็นการสร้าง object $game_party ขึ้นมาด้วยคลาส Game_Party ดังนั้น เรารู้แล้วว่าข้อมูล $game_party มาจากคลาส Game_Party ให้เราตรวจสอบดูรายการ script ด้านซ้ายดูครับ เราก็จะเห็นไฟล์ Game_Party ที่มี class Game_Party ด้านใน
การเก็บข้อมูลอัตราการคูณเงิน กับจำนวนก้าวที่เหลือ เราควรเก็บข้อมูลในคลาสดังกล่าว เพราะเหมาะสมในการเป็นข้อมูลที่เกี่ยวกับปาร์ตี้ที่สุดแล้ว
ในขั้นตอนนี้เราจะทำการเพิ่มตัวแปรในคลาส Game_Party ด้วยวิธีการ overwrite ครับ ให้ไปที่ไฟล์ของเราที่สร้างขึ้นในขั้นตอนที่ 1 แล้วเขียนโค้ดต่อจากเดิมดังนี้ (ไม่ต้องลบของเก่านะครับ เขียนต่อลงมาด้านล่างเลย)
[shcode=rails]
# ----------------------------------------------------------
# โค้ดเก่าในส่วนของ module BattleManager ละไว้ในฐานที่เข้าใจ
# ----------------------------------------------------------
class Game_Party < Game_Unit # ก็อบหัวมาจากไฟล์ Game_Party
# ส่วนนี้เป็นการบอกว่าตัวแปร @bonus_gold, @bonus_gold_step สามารถถูกอ่านค่าจากภายนอกได้
attr_reader :bonus_gold
attr_reader :bonus_gold_step
# ส่วนนี้เหมาะกับการกำหนดค่าเริ่มต้นของตัวแปร
alias_method :initialize_copied, :initialize
def initialize
initialize_copied
@bonus_gold = 1
@bonus_gold_step = 0
end
end
[/shcode]
โค้ดดังกล่าว เราจะทำการเพิ่มตัวแปร @bonus_gold, @bonus_gold_step ขึ้นมา ซึ่งเป็นตัวแปรประเภท class variable กล่าวคือตัวแปรนี้จะมีขอบเขตการใช้งานได้ในคลาสนี้เท่านั้น (มี @ นำหน้า)
- @bonus_gold - ใช้เก็บข้อมูลอัตราส่วนการได้เงิน เช่น ถ้า @bonus_gold = 2 คือ gold X2 เป็นต้น ซึ่งควรมีค่าเริ่มต้นเป็น 1 (gold x1)
- @bonus_gold_step - เป็นตัวแปรที่เก็บจำนวนก้าวที่เหลือก่อนที่ @bonus_gold จะกลับมาเป็น 1
ซึ่งควรมีค่าเริ่มต้นเป็น 0 เพราะเรายังไม่ได้ใช้งานไอเท็ม
method initialize นั้น เป็น method ที่จะถูกเรียกใช้งานอัตโนมัติทันทีที่ทำการประกาศ object ขึ้น (initialize เป็นชือเฉพาะ) เราจะตั้งค่าเริ่มต้นให้ @bonus_gold = 1 และ @bonus_gold_step = 0 จากเหตุผลที่กล่าวไปด้านบน
ทีนี้เราก็มีตัวแปรคอยควบคุมการ X เงินของเราแล้วครับ ให้เราเปลี่ยนโค้ดเก่า จาก * 2 เป็นดังนี้
[shcode=rails]
module BattleManager
def self.gain_gold
if $game_troop.gold_total > 0
text = sprintf(Vocab::ObtainGold, $game_troop.gold_total * $game_party.bonus_gold) # แก้บรรทัดนี้
$game_message.add('\.' + text)
$game_party.gain_gold($game_troop.gold_total * $game_party.bonus_gold) # แก้บรรทัดนี้
end
wait_for_message
end
end
# ----------------------------------------------------------
# โค้ดในส่วนของ class Game_Party ละไว้ในฐานที่เข้าใจ
# ----------------------------------------------------------
[/shcode]
สังเกตว่าเราเปลี่ยนจาก * 2 เป็น * $game_party.bonus_gold แทน ซึ่งค่าของ $game_party.bonus_gold นั้นจะขึ้นอยู่กับตัวแปร @bonus_gold ด้านใน object $game_party นั่นเอง
5. สร้างคำสั่งให้ gold X2 จำนวน 50 ก้าว
ในโค้ดเก่าที่เราสร้าง ใน Game_Party ให้เพิ่ม method ขึ้นมาอีกอันหนึ่ง
[shcode=rails]
# ----------------------------------------------------------
# โค้ดในส่วนของ module BattleManager ละไว้ในฐานที่เข้าใจ
# ----------------------------------------------------------
class Game_Party < Game_Unit # ก็อบหัวมาจากไฟล์ Game_Party
# ----------------------------------------------------------
# โค้ดเก่าที่ให้เขียนในขั้นตอนที่ผ่านมา ละไว้ในฐานที่เข้าใจ
# ----------------------------------------------------------
# โค้ดที่เพิ่มเข้ามา
def bonus_gold_start
puts "gold X2"
@bonus_gold = 2
@bonus_gold_step = 50
end
end
[/shcode]
ในโค้ดนี้เราจะสร้าง method ขึ้นมา เพื่อสั่งให้ ทำการ X2 Gold และเพิ่มจำนวนก้าวเป็น 50 ก้าว (จริงๆ ต้อง 1000 ก้าว แต่เราลองที่ 50 ก่อนเพื่อความง่ายในการตรวจสอบ)
6. สร้าง common event เรียกคำสังที่สร้างในข้อ 5
ให้เราสร้าง common event ขึ้นมาครับ แล้วสร้าง event command และใส่ script ตามภาพเลย
จากภาพ เราได้สั่งตัวแปร $game_party ให้เรียก method ชื่อ bonus_gold_start ซึ่งเรารู้จากขั้นตอนที่ผ่านมาว่าตัวแปร $game_party เป็น object ของ class Game_Party ทำให้การเรียกใช้งานแบบนี้ไม่มีปัญหา และเมื่อเรียกใช้งานแล้ว ตัวแปร @bonus_gold และ @bonus_gold_step ที่อยู่ใน object $game_party จะมีค่า 2 และ 50 ตามลำดับ (ตอนแรกเป็น 1 และ 0 จากค่าเริ่มต้นที่ตั้งไว้)
7. ทดลองสร้างไอเท็มดู
ให้ใส่รายละเอัยประมาณรูปภาพ สีแดงคือส่วนที่เน้นเป็นพิเศษ โดยเฉพาะตรง Effects เราต้องเลือกใช้งาน common event ที่เราสร้างขึ้น
8. ทบทวนโค้ดของเรา และลองทดสอบเกมดูก่อน
โค้ดที่เขียนจนถึงขั้นตอนนี้ต้องเป็นแบบนี้
Code:
module BattleManager
def self.gain_gold
if $game_troop.gold_total > 0
text = sprintf(Vocab::ObtainGold, $game_troop.gold_total * $game_party.bonus_gold)
$game_message.add('\.' + text)
$game_party.gain_gold($game_troop.gold_total * $game_party.bonus_gold)
end
wait_for_message
end
end
class Game_Party < Game_Unit
attr_reader :bonus_gold
attr_reader :bonus_gold_step
alias_method :initialize_copied, :initialize
def initialize
initialize_copied
@bonus_gold = 1
@bonus_gold_step = 0
end
def bonus_gold_start
puts "gold X2"
@bonus_gold = 2
@bonus_gold_step = 50
end
end
มาถึงตอนนี้ให้เราลองทดสอบเกมดูก่อน โดยให้เสกไอเท็มดังกล่าวเข้าตัว ก่อนใช้ไอเท็ม ลองไปสู้กับมอนสเตอร์ที่มีการดรอบเงินดู (อาจจะสร้างอีเว้นท์สู้กับมอนง่ายๆ ไปเลย) ให้จำเงินที่ได้เอาไว้ หลังจากนั้นให้ลองใช้ไอเท็ม และลองไปสู้ใหม่ สังเกตผลลัพธ์ที่ได้
ให้เราสังเกตดูว่า เมื่อกดใช้ไอเท็มที่เราสร้างขึ้นแล้ว จะมีข้อความ "gold X2" แสดงออกมาทาง console ทำให้เรารู้ว่าคำสั่งที่เราเรียกใช้นั้นทำงาน
ทั้งนี้เพราะใน method bonus_gold_start นั้น เราได้เขียน puts "gold X2" ลงไปด้วย
นี่แหละครับ สิ่งที่ผมอยากจะบอกว่า console นั้นสำคัญไฉน ทำให้ระหว่างการดีบั๊กเกมนั้น เราสามารถตรวจสอบได้ว่า ขณะนี้คำสั่งที่เราต้องการเรียก มันทำงานหรือเปล่า ลองนึกดูว่าถ้าเราไม่ puts ออกมาดู เวลาเราลองใช้ไอเท็มมันก็จะไม่มีข้อความอะไรบอก ทำให้เราไม่รู้ว่ามันใช้ได้หรือไม่ได้กันแน่ ถูกไหมครับ
เมื่อผ่านมาถึงขั้นตอนนี้แล้ว ท่านจะพบว่าเมื่อใช้ไอเท็มแล้วไปสู้กันมอนสเตอร์ จะได้เงิน X2
อธิบายการทำงาน
- ก่อนใช้ไอเท็ม สู้กับมอนสเตอร์ ได้ gold x1 ตามคำสั่ง $game_party.gain_gold($game_troop.gold_total * $game_party.bonus_gold) ที่เรา overwrite ใน module BattleManager ซึ่งค่า $game_party.bonus_gold ของเราจะเป็น 1 เพราะเป็นค่าเริ่มต้นที่เราตั้งไว้ใน class Game_Party
- ใช้ไอเท็ม
- ไอเท็มดังกล่าวไปเรียกใช้ common event ที่เราสร้าง
- common event ไปเรียกใช้ script $game_party.$game_party.bonus_gold_start
- method bonus_gold_start ถูกเรียกใช้งาน ทำให้ตัวแปร @bonus_gold มีค่าเป็น 2 และ @bonus_gold_step มีค่าเป็น 50
- เมื่อสู้กับมอนสเตอร์ จะได้ gold X2 ตามคำสั่ง $game_party.gain_gold($game_troop.gold_total * $game_party.bonus_gold) ที่เรา overwrite ใน module BattleManager ซึ่งค่า $game_party.bonus_gold ของเราจะเป็น 2 จากเหตุผลข้อที่แล้ว
ยินดีด้วย!!! คุณสามารถสร้างไอเท็มที่ใช้แล้ว gold x2 ตอนต่อสู้ได้แล้ว
แต่ทั้งหมดที่ผ่านมานี้เป็นเพียงครึ่งทางเท่านั้น!!!
เพราะท่านจะพบว่าเมื่อใช้ไอเท็มแล้วไปสู้กันมอนสเตอร์ จะได้เงิน X2 แต่มันจะ X2 ไปตลอดกาล ทั้งนี้เพราะเรายังไม่ได้เขียนระบบนับก้าวนั่นเอง และที่สำคัญ เรายังไม่มีกล่องข้อความแจ้งเตือนว่าเหลืออีกกี่ก้าวอีกด้วย และที่สำคัญกว่า เรายังไม่ได้เริ่มเขียนไอเท็ม Exp X2 กันแม้แต่นิดเดียว 5555+ ดังนั้น หนทางยังอีกยาวไกลนัก
ซึ่งผมจะมาอธิบายต่อไป (edit กระทู้นี้ครับ)
###มาแก้ไขกระทู้###
เนื่องจากตอนนี้งานเยอะมาก ขออภัยในความล่าช้านะครับ หากว่างแล้วจะกลับมาเขียนต่อทันทีครับ -/\-
.