splendith   06-14-2015, 01:37 PM
#1
Script Workshop - มาสร้างไอเท็ม Exp, Gold X2 ในฉากต่อสู้กัน

บทความนี้จะสอนการเขียน script ขึ้นมา ซึ่งจะเล่าแนวคิดการเขียนตั้งแต่ต้นจนจบ หากฝึกจนชำนาญแล้ว ท่านสามารถนำไปประยุกต์ใช้ทำ script อื่นๆ แจกจ่ายได้เลย ^^ (เขียนสลับไปมากับบทความพื้นฐาน เดี๋ยวคนมีความรู้อยู่แล้วจะเบื่อซะก่อน แหะๆ)

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

ในบทความนี้จะทำการเขียน script สร้างไอเท็มดังนี้
  1. Rich Potion - ใช้แล้ว Gold X2 ในฉากต่อสู้ เป็นระยะเวลา 1000 ก้าว
  2. Master Potion - ใช้แล้ว Exp X2 ในฉากต่อสู้ เป็นระยะเวลา 1000 ก้าว
[Image: 8capture.jpg]

ซึ่งเมื่อใช้งานไอเท็มแล้ว จะมีสถานะบอกที่มุมบนขวาของจอด้วย

[Image: 8capture.jpg]

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

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

1. สร้างไฟล์เปล่าขึ้นมาก่อนเลย
แน่นอนว่าการนำ script ไปแจกคนอื่นนั้น จะต้องสร้างไฟล์ script ขึ้นมาเพื่อให้ผู้อื่นนำไฟล์ script เราไปใช้ในอนาคต ให้คลิกขวาสร้างไฟล์เปล่าขึ้นมา แล้วตั้งชื่อว่า Bonus Exp, Gold
หมายเหตุ: เราจะไม่แก้โค้ดเดิมเด็ดขาดนะครับ ให้จำเอาไว้ว่าทุกครั้งที่ให้เขียนโค้ดหรือแก้โค้ด มันคือการเขียนที่ไฟล์ที่เราสร้างใหม่นี้เสมอครับ

2. ทำทีละอย่าง
หากยังไม่ชำนาญแล้ว แนะนำให้แก้โจทย์ทีละอย่างครับ เพื่อง่ายต่อความเข้าใจ
ดังนั้นในส่วนแรกนี้ผมจะทำแต่ไอเท็ม gold X2 โดยยังไม่ไปยุ่งกับ exp นะครับ

3. หาโค้ดส่วนที่ได้รับ gold หลังการต่อสู้
ผมก็จะวิเคราะห์ก่อนว่า ถ้าเราจะให้ gold x2 ก็ควรจะต้องคูณมันตอนเราได้รับเงินหลังต่อสู้ใช่ไหมครับ ซึ่ง script ที่จัดการเกี่ยวกับการต่อสู้ทั้งหมดนั้น อยู่ใน module BattleManager (ไฟล์ประมาณบนซ้าย) ว่าแล้วผมก็กดเข้าไปทันที ลองหาๆ ด้วย Ctrl + F ดูแล้ว ก็จะได้โค้ดที่เข้าเค้าที่สุด อยู่ที่ประมาณบรรทัดที่ 316 ดังรูป

[Image: 9capture.jpg]

ว่าแล้วก็ทำการ 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+
[Image: 6capture.jpg]
ในบรรทัดที่ 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 ตามภาพเลย
[Image: 8capture.jpg]

จากภาพ เราได้สั่งตัวแปร $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 ที่เราสร้างขึ้น
[Image: 9capture.jpg]

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 ทำให้เรารู้ว่าคำสั่งที่เราเรียกใช้นั้นทำงาน
[Image: 7capture.jpg]

ทั้งนี้เพราะใน method bonus_gold_start นั้น เราได้เขียน puts "gold X2" ลงไปด้วย

นี่แหละครับ สิ่งที่ผมอยากจะบอกว่า console นั้นสำคัญไฉน ทำให้ระหว่างการดีบั๊กเกมนั้น เราสามารถตรวจสอบได้ว่า ขณะนี้คำสั่งที่เราต้องการเรียก มันทำงานหรือเปล่า ลองนึกดูว่าถ้าเราไม่ puts ออกมาดู เวลาเราลองใช้ไอเท็มมันก็จะไม่มีข้อความอะไรบอก ทำให้เราไม่รู้ว่ามันใช้ได้หรือไม่ได้กันแน่ ถูกไหมครับ

เมื่อผ่านมาถึงขั้นตอนนี้แล้ว ท่านจะพบว่าเมื่อใช้ไอเท็มแล้วไปสู้กันมอนสเตอร์ จะได้เงิน X2

อธิบายการทำงาน
  1. ก่อนใช้ไอเท็ม สู้กับมอนสเตอร์ ได้ 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
  2. ใช้ไอเท็ม
  3. ไอเท็มดังกล่าวไปเรียกใช้ common event ที่เราสร้าง
  4. common event ไปเรียกใช้ script $game_party.$game_party.bonus_gold_start
  5. method bonus_gold_start ถูกเรียกใช้งาน ทำให้ตัวแปร @bonus_gold มีค่าเป็น 2 และ @bonus_gold_step มีค่าเป็น 50
  6. เมื่อสู้กับมอนสเตอร์ จะได้ 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 กระทู้นี้ครับ)

###มาแก้ไขกระทู้###
เนื่องจากตอนนี้งานเยอะมาก ขออภัยในความล่าช้านะครับ หากว่างแล้วจะกลับมาเขียนต่อทันทีครับ -/\-


.
This post was last modified: 08-11-2015, 05:17 AM by splendith.
Mary   06-14-2015, 03:15 PM
#2
ขอบคุณมากๆค่ะ กำลังอยากได้แนวศึกษาสคริปอยู่พอดีเลย

[Image: 150530082811.jpg]
jojo741963   06-14-2015, 04:09 PM
#3
เป็นประโยชน์มากเลยครับ

.
[Image: bzkfm.gif] เวลาที่เล่นเกม ต้องเปิดไฟให้สว่าง และนั่งให้ไกลจากจอพอประมาณด้วย นะ[Image: bzkfm.gif]
.
slost   10-21-2015, 08:49 PM
#4
ขอบคุณมากครับ เอาไปประยุกต์ได้หลายอย่างเลยทีเดียว แมวหน้าแดง


 "กาก"
[Image: bujuroll.gif] แอดเพื่อน Steam จิ้มแรงๆเลย >>> [Image: AddFriend.png]
[Image: 76561198091389336.png]




Mysticphoenix   10-22-2015, 12:58 PM
#5
ขอบคุณคับ น่าเอาไปใช้มาก

[Image: webboard%20signature1_zpskhtut2jg.png]
การทำอาหารที่อร่อยที่สุด และเดือดร้อนชาวบ้านมากที่สุด กำลังจะเริ่มขึ้น
  
Users browsing this thread: 5 Guest(s)
Powered By MyBB, © 2002-2024 MyBB Group.
Made with by Curves UI.