6 สิงหาคม 2562

Ren'Py พื้นฐาน | บทที่ 5 ตัวเลือกและทิศทางของเกม

อะไรนะ! มีเกมแนว Visual Novel ที่ไหนไม่มีตัวเลือกให้ผู้เล่นบ้าง? ก็เกมแนว Visual Novel ที่สร้างกันในบทที่แล้วน่ะสิ สำหรับผู้อ่านที่ยังไม่ได้อ่านบทความชุด "Ren'Py พื้นฐาน" ตั้งแต่บทที่ 1 ถึงบทที่ 4 ผู้เขียนแนะนำให้ท่านย้อนกลับไปก่อนอ่านบทนี้ ในบทนี้ท่านจะได้เรียนเรื่องทิศทางการทำงานของเกมด้วยวิธีต่าง ๆ ได้แก่ การข้ามการทำงาน, การตรวจเงื่อนไข, การทำงานซ้ำ, และปิดท้ายบทนี้ด้วยการสร้างตัวเลือกให้เกมแนว Visual Novel ที่ผู้เล่นคุ้นเคยกัน


Block: เว้นวรรคหน้าคำสั่ง

ก่อนเรียนเรื่องใหม่ผู้เขียนต้องอธิบายเรื่องบล็อก (Block) ให้ท่านเข้าใจก่อน จะได้ไม่ต้องมาอธิบายเรื่องนี้ซ้ำบ่อย ๆ บล็อกคือกลุ่มของคำสั่งที่อยู่ในระดับเดียวกัน ผู้อ่านที่เคยเขียนโปรแกรมด้วยภาษา C หรือ Java คงจะคุ้นเคยกับเครื่องหมาย { } ที่ครอบคำสั่งหลายตัว นั่นคือการบอกว่าคำสั่งเหล่านี้อยู่ในบล็อกเดียวกันหรือระดับเดียวกัน (เช่น กลุ่มคำสั่งที่ต่อจาก if-else, while, function)
บล็อกคืออะไร? บล็อกคือกลุ่มคำสั่งที่จะทำงานเมื่ออยู่ในเงื่อนไขที่กำหนดเท่านั้น คำสั่งที่อยู่ในบล็อกเดียวกันจะมีระดับเดียวกัน เรื่องนี้อธิบายให้มือใหม่เข้าใจยาก เอาเป็นว่าบล็อกคืออะไรช่างมันก่อน เรียนวิธีใช้บล็อกกันไปก่อน แล้วค่อยทำความรู้จักบล็อกกันในหัวข้อที่ต้องใช้บล็อกกันอีกที

ในภาษา Ren'Py ไม่ได้ใช้เครื่องหมาย { } ในการแบ่งบล็อก แต่จะใช้การเว้นวรรคหน้าคำสั่งเพื่อแบ่งบล็อก (ห้ามใช้ tab แทนการเว้นวรรค อ่านรายละเอียดใน "ข้อระวังท้ายบท" ใน Ren'Py พื้นฐาน | บทที่ 3 กล่องข้อความ) คำสั่งที่อยู่ในบล็อกเดียวกันต้องเว้นวรรคหน้าคำสั่งเท่ากัน การเว้นวรรคหน้าคำสั่งจะเว้นวรรคกี่ครั้งก็ได้ สำหรับบล็อกย่อยที่อยู่ภายในบล็อกใหญ่แล้ว บล็อกย่อยนั้นต้องมีจำนวนเว้นวรรคมากกว่าบล็อกใหญ่ ตัวอย่างเช่น


จากตัวอย่างข้างบนสังเกตว่าคำสั่งในบล็อกที่ 1 ไม่ได้เว้นวรรคหน้าคำสั่ง (หน้าบรรทัด) ถือว่าเป็นบล็อกที่ใหญ่ที่สุด บล็อกที่ 2 เป็นบล็อกย่อยที่อยู่ในบล็อกที่ 1 มีการเว้นวรรคหน้าบล็อกที่ 2 พอควร ต่อมาคือบล็อกที่ 3 เป็นบล็อกย่อยที่อยู่ในบล็อกที่ 2 อีกที สังเกตจากคำสั่งของบล็อกที่ 3 อยู่ต่อจากบล็อกที่ 2 และมีการเว้นวรรคมากกว่าบล็อกที่ 2

ถ้ามีหลายบล็อกแล้วคำสั่งที่อยู่ในบล็อกที่ใหญ่ที่สุดจะทำงานเป็นลำดับแรก (ในตัวอย่างคือบล็อกที่ 1) ทำงานจากบรรทัดบนไปยังบรรทัดล่าง ส่วนบล็อกย่อยจะทำงานเมื่อตรงตามเงื่อนไขเท่านั้น เช่น ถ้าไม่ตรงเงื่อนไขของบล็อกที่ 2 เกมจะข้ามบล็อกที่ 2 ทั้งหมด รวมทั้งบล็อกที่ 3 ซึ่งอยู่ในบล็อกที่ 2 อีกทีด้วย หมายความว่าเกมจะทำงานแค่สองบรรทัดแรกและบรรทัดสุดท้ายเท่านั้น เพราะสามบรรทัดนี้อยู่ในบล็อกที่ 1 ส่วนบรรทัดอื่นเกมจะมองเหมือนว่าไม่มีตัวตนอยู่

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

Pass

ในกรณีที่ภาษา Ren'Py บังคับให้ใส่บล็อกย่อย แต่เราไม่มีคำสั่งที่ต้องการใส่ในบล็อกย่อยนั้น ภาษา Ren'Py ไม่อนุญาตให้ปล่อยเป็นบล็อกเปล่าได้ วิธีแก้คือใส่คำสั่ง pass ในบล็อกย่อยนั้น คำสั่ง pass เป็นคำสั่งที่ไม่ทำอะไรเลย ทำหน้าที่เป็น Pseudo Statement หลอกว่าในบล็อกย่อยมีคำสั่งแล้วทั้งที่จริงไม่มีคำสั่ง ตัวอย่างการใช้คำสั่ง pass คู่กับคำสั่ง if-else เช่น


Label & Jump: กำหนดเพื่อข้าม

Label

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


เช่น label check: หมายถึงตั้งชื่อ check ให้แก่บรรทัดนั้น (บรรทัด label check) คำสั่ง label ไม่มีประโยชน์เมื่อใช้งานเดี่ยว ๆ เพราะไม่มีความจำเป็นที่ต้องตั้งชื่อให้แก่คำสั่งที่ตั้งชื่อให้ตัวเอง เปลืองบรรทัดเปล่า ๆ คำสั่ง label จะใช้คู่กับคำสั่ง jump

start คือชื่อเฉพาะที่โปรแกรม Ren'Py สงวนไว้ เกมจะเริ่มต้นทำงานที่ label start: เป็นลำดับแรกเสมอ (เปรียบเหมือนฟังก์ชัน main ในภาษา C) ดังนั้นคำสั่งทุกอย่างในเกมต้องอยู่ต่อจากบรรทัด label start: เสมอ เพื่อให้คำสั่งเหล่านั้นสามารถทำงานในเกมได้
รูปที่ 5.1 การทำงานของคำสั่ง label และ jump

Jump

jump คือคำสั่งที่ข้ามไปทำงานบรรทัดที่มีชื่อเฉพาะ หมายความว่าเราต้องตั้งชื่อเฉพาะให้แก่บรรทัดเป้าหมายด้วยคำสั่ง label ก่อน แล้วเราจึงสามารถข้ามไปยังบรรทัดเป้าหมายด้วยคำสั่ง jump ได้ เมื่อข้ามไปยังบรรทัดเป้าหมายแล้ว เกมจะทำงานต่อจากบรรทัดเป้าหมายไปเรื่อย ๆ ไม่กลับมาบรรทัดที่ต่อจากคำสั่ง jump อีก (เป็นการข้ามแบบถาวร) รูปแบบของคำสั่ง jump คือ


ตัวอย่างการข้ามด้วยคำสั่ง jump เช่น


สิ่งที่ต้องระวังคือคำสั่ง label ต้องตามท้ายด้วยเครื่องหมาย : แต่คำสั่ง jump ไม่มีเครื่องหมาย : ต่อท้าย อีกเรื่องที่ควรจำคือถ้าคำสั่งไม่ถูกข้าม เกมจะทำงานจากบรรทัดบนไปยังบรรทัดล่าง คำสั่งที่ต่อจากบรรทัด label สามารถทำงานได้โดยไม่ต้องเรียกใช้ด้วยคำสั่ง jump (เช่น คำสั่งที่ต่อจากบรรทัด label always: ในตัวอย่างข้างบน) นอกจากนี้ยังสามารถใช้คำสั่ง jump เพื่อข้ามไปยังบรรทัดที่อยู่ในไฟล์สคริปต์อื่นได้อีกด้วย เนื่องจากโปรแกรม Ren'Py มองไฟล์สคริปต์ทุกไฟล์รวมเข้าด้วยกัน


If-Else: ตรวจเงื่อนไข

if คือคำสั่งที่ตรวจเงื่อนไขที่ต่อท้าย ถ้าเงื่อนไขนั้นเป็นจริง บล็อกย่อยที่ต่อจากคำสั่ง if จะถูกทำงาน ถ้าเงื่อนไขนั้นเป็นเท็จ บล็อกย่อยที่ต่อจากคำสั่ง else จะถูกทำงานแทน ในกรณีที่ไม่มีคำสั่ง else เกมจะข้ามไปทำงานคำสั่งต่อไปที่อยู่นอกบล็อกของ if รูปแบบของคำสั่ง if มี 2 แบบได้แก่ รูปแบบที่ไม่มีคำสั่ง else


และรูปแบบที่มีคำสั่ง else


รูปที่ 5.2 การทำงานของคำสั่ง if-else

นอกจากนี้ยังสามารถตรวจเงื่อนไขซ้อนกันหลายเงื่อนไขได้ด้วยคำสั่ง if-elif-else รูปแบบนี้จะเริ่มตรวจเงื่อนไขแรกก่อน (เงื่อนไขหลัง if) ถ้าเงื่อนไขแรกเป็นจริง บล็อกของ if จะถูกทำงาน ถ้าเงื่อนไขแรกเป็นเท็จ จะตรวจเงื่อนไขที่สอง (เงื่อนไขหลัง elif) และทำต่อไปแบบเดียวกันไปเรื่อย ๆ จนถึงเงื่อนไขสุดท้าย (elif ตัวสุดท้าย) ถ้าเงื่อนไขทั้งหมดเป็นเท็จ บล็อกของ else จะถูกทำงาน


ตัวอย่างการตรวจสอบเงื่อนไข เช่น


เรากำหนดให้ตัวแปร dead เป็นจริง เกมจะเลือกทำงานในบล็อก if โดยไม่ทำงานในบล็อก else จะได้ดังรูปที่ 5.2
รูปที่ 5.3 ตรวจเงื่อนไขด้วยคำสั่ง if-else


While: วนซ้ำ

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


การวนซ้ำด้วยคำสั่ง while ต้องระวังเรื่องการวนซ้ำที่ไม่มีสิ้นสุด (Infinity Loop) การใช้คำสั่ง while ทุกครั้งต้องแน่ใจแล้วว่าเกมจะสามารถออกจากการวนซ้ำได้ ภาษา Ren'Py ไม่มีคำสั่ง break, continue, และ for สำหรับคำสั่ง break และ continue สามารถใช้คำสั่ง jump แทนได้ ส่วนคำสั่ง for สามารถใช้คำสั่ง while ที่กำหนดจำนวนรอบแทนได้
รูปที่ 5.4 การทำงานของคำสั่ง while

ตัวอย่างการใช้คำสั่ง while เพื่อแสดงข้อความ "มิกิจังน่ารัก" จำนวน 10 ครั้ง สามารถเขียนสคริปต์ได้ดังนี้


บทความน่าสนใจ
ทำไม i = i + 1 | คำถามที่มือใหม่หลายคนสงสัย


Menu: นิยายที่มากกว่านิยาย

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


บล็อกย่อยของแต่ละตัวเลือกคือคำสั่งที่ทำงานเมื่อเลือกตัวเลือกนั้น มีวิธีจัดการคำสั่งของตัวเลือกหลายวิธี
  • วิธีที่ง่ายที่สุดคือใส่คำสั่งที่ต้องการลงในบล็อกย่อยโดยตรง แต่วิธีนี้ไม่เหมาะกับกรณีที่มีคำสั่งจำนวนมาก เพราะจะทำให้บล็อกย่อยยาวมากจนอ่านลำบาก
  • วิธีที่นิยมใช้คือใช้คำสั่ง jump เพื่อข้ามไปยัง label ที่อยู่นอกบล็อกย่อยแทน
  • อีกวิธีคือกำหนดค่าตัวแปรลงในบล็อกย่อย จากนั้นภายนอกบล็อกย่อยก็ตรวจสอบเงื่อนไขตัวแปรด้วยคำสั่ง if-else หรือ if-elif-else
ตัวอย่างการใช้คำสั่ง menu เพื่อแสดงตัวเลือกดังข้างล่างนี้ อย่าลืมใส่เครื่องหมาย : หลังคำสั่ง menu และตัวเลือกทุกตัว


เมื่อทดสอบเกมแล้วจะได้ดังรูปที่ 5.5 และรูปที่ 5.6
รูปที่ 5.5 ทดสอบตัวเลือกในเกม
รูปที่ 5.6 เมื่อเลือกตัวเลือก "ที่นี่ที่ไหนเนี่ย?"


สรุปท้ายบท

ในบทนี้ได้เรียนการควบคุมทิศทางการทำงานของเกมได้แก่ การใช้คำสั่ง label และ jump เพื่อข้ามการทำงานไปยังบรรทัดที่ต้องการ, การตรวจสอบเงื่อนไขแบบธรรมดาด้วยคำสั่ง if-else, และการตรวจสอบเงื่อนไขเพื่อวนซ้ำด้วยคำสั่ง while เราเรียนการควมคุมทิศทางการทำงานของเกม เพื่อใช้สร้างตัวเลือกของเกมในหัวข้อสุดท้ายของบท

ไม่มีความคิดเห็น:

แสดงความคิดเห็น