3 กันยายน 2562

Ren'Py พื้นฐาน | บทที่ 9 แจกจ่ายเกมที่เสร็จแล้ว

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


แจกจ่ายเกม

1. เปิดโปรแกรม Ren'Py
2. เลือกโปรเจ็กต์ที่ต้องการแจกจ่ายตรงด้านซ้ายของโปรแกรม แล้วคลิก Build Distributions ดังรูปที่ 9.1
รูปที่ 9.1 การเลือกโปรเจ็กต์ที่ต้องการแจกจ่าย

27 สิงหาคม 2562

Ren'Py พื้นฐาน | บทที่ 8 Animation and Transformation Language (ATL)

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


คำสั่งแม่ของ ATL

ATL เป็นส่วนขยายของคำสั่งอื่น ต้องอยู่ภายในบล็อกของคำสั่งที่ไปขยาย คำสั่งที่ ATL สามารถขยายได้มีดังนี้

Show และ Scene

show และ scene คือคำสั่งพื้นฐานสำหรับการแสดงรูป สองคำสั่งนี้จึงรองรับลูกเล่นของรูปโดยตรง ลูกเล่นจะแสดงเมื่อใช้คำสั่งเหล่านี้ ผู้เขียนแนะนำให้ใส่ ATL ทุกอย่างในคำสั่ง show หรือ scene เนื่องจากเข้าใจและใช้งานง่าย

ตัวอย่างการใส่ ATL ในบล็อก show


Image

image คือคำสั่งสำหรับประกาศตัวแปรรูป เราสามารถใส่ ATL ไปพร้อมกับการประกาศตัวแปรรูปได้ แต่เนื่องจาก image เป็นคำสั่งประมวลผลล่วงหน้า (Preprocessor Directive) ซึ่งจะแซงคิวคำสั่งอื่น ทำให้ลูกเล่น ATL ในบล็อก image จึงแซงคิวคำสั่งอื่นตามไปด้วย

อย่าลืมว่าคำสั่ง image เป็นเพียงคำสั่งประกาศตัวแปรรูป ไม่ใช่คำสั่งแสดงรูป ถ้าต้องการแสดงรูปต้องใช้คำสั่ง show หรือ scene แล้วตามด้วยชื่อตัวแปรรูป

ตัวอย่างการใส่ ATL ในบล็อก image


Transform

transform คือคำสั่งรูปที่เกี่ยวกับตำแหน่งรูป เช่น กำหนดให้รูปอยู่ฝั่งซ้ายของหน้าจอ สามารถใส่ ATL ที่เกี่ยวกับตำแหน่งรูปได้ แต่ผู้เขียนแนะนำให้ใช้คำสั่ง show หรือ scene แทนดีกว่า เนื่องจากสามารถรองรับลูกเล่นตำแหน่งรูปได้เหมือนกัน อีกทั้งยังใช้ง่ายและหลากหลายกว่าคำสั่ง transform ด้วย

tranform เป็นคำสั่งประมวลผลล่วงหน้า (Preprocessor Directive) ซึ่งจะแซงคิวคำสั่งอื่น เหมาะสำหรับลูกเล่นที่ใช้ครั้งเดียว ถ้าไฟล์สคริปต์มีทั้งคำสั่ง image และ transform คำสั่ง transform จะทำงานก่อน เนื่องจากมีลำดับขั้นที่สูงกว่า

ตัวอย่างการใส่ ATL ในบล็อก transform


20 สิงหาคม 2562

Ren'Py พื้นฐาน | บทที่ 7 รูปภาพและวิดีโอ

โปรแกรม Ren'Py รองรับลูกเล่นกราฟฟิกมากมาย ในบทนี้จะเรียนการใส่รูปภาพและวิดีโอเบื้องต้นได้แก่แนวคิดพื้นฐาน การแสดงรูปและการเปิดวิดีโอ ส่วนลูกเล่นเพิ่มเติมต้องใช้ ATL (Animation and Transformation Language) ซึ่งจะเรียนกันในบทต่อไป


Layer: ชั้นของรูป

เลเยอร์ (Layer) คือชั้นที่รวมรูปที่กำลังแสดงอยู่ โปรแกรม Ren'Py มีหลายเลเยอร์เพื่อรองรับการแสดงรูปหลายรูปพร้อมกัน ภายในหนึ่งเลเยอร์สามารถแสดงหลายรูปพร้อมกันได้ เลเยอร์หลักที่ใช้คือเลเยอร์ Master ซึ่งแสดงรูปพื้นหลัง, รูปตัวละคร, และรูปอื่น ๆ ที่นักสร้างเกมใส่มา นอกจากนี้ท่านสามารถสร้างเลเยอร์ใหม่เองได้ แต่จะไม่อธิบายการสร้างเลเยอร์ใหม่ในบทความนี้ เนื่องจากเลเยอร์ Master ก็เพียงพอสำหรับการใช้งานทั่วไปและลูกเล่นต่าง ๆ แล้ว
รูปที่ 7.1 การจัดเรียงเลเยอร์


Tag and Attribute: แท็กและคุณสมบัติ

รูปในโปรแกรม Ren'Py แตกต่างจากเสียงซึ่งสามารถตั้งชื่อไฟล์ได้ตามใจชอบ ชื่อของรูปประกอบด้วย 2 ส่วนได้แก่แท็ก (Tag) และคุณสมบัติ (Attribute) แท็กและคุณสมบัติแบ่งด้วยการเว้นวรรคภายในชื่อไฟล์รูป ส่วนซ้ายสุดคือแท็ก นอกจากนั้นเป็นคุณสมบัติที่ขยายแท็กนั้น (อยู่ทางขวาของแท็ก) จะมีคุณสมบัติเท่าไรก็ได้หรือไม่มีเลยก็ได้
รูปที่ 7.2 การแบ่งแท็กและคุณสมบัติจากชื่อไฟล์

16 สิงหาคม 2562

[Q&A] Parameter และ Argument ต่างกันอย่างไร?

เมื่อศึกษาการเขียนโปรแกรมไปเรื่อย ๆ จะพบกับคำศัพท์ว่าพารามิเตอร์ (Parameter) และอาร์กิวเมนต์ (Argument) หลายคนสงสัยและสับสนว่าสองคำนี้ต่างกันอย่างไร ผู้เขียนจะมาอธิบายในบทความนี้ แต่ก่อนหน้านั้นท่านต้องเข้าใจแนวคิดเรื่องโปรแกรมย่อย (Subprogram)


โปรแกรมย่อย

โปรแกรมย่อยคือชุดของคำสั่งที่แยกออกมาจากส่วนหลักของโปรแกรม (เช่น ส่วนหลักในภาษา C, Java คือฟังก์ชัน main) จุดประสงค์ของการแยกชุดของคำสั่งคือเพื่อเป็นอิสระจากส่วนหลัก ทำให้สามารถแก้ไขง่าย และเรียกใช้งานซ้ำได้หลายครั้ง โดยปกติโปรแกรมหลักจะถูกทำงานเป็นลำดับแรก ส่วนโปรแกรมย่อยจะไม่ถูกทำงานเลย ยกเว้นแต่จะถูกเรียกใช้งานจากโปรแกรมหลักหรือโปรแกรมย่อยอื่นที่กำลังทำงาน โปรแกรมเมอร์มักใช้โปรแกรมย่อยเพื่อสั่งให้ทำงานบางอย่างที่เจาะจง หลายครั้งมีการส่งข้อมูลไปยังโปรแกรมย่อย และรับข้อมูลที่ได้จากโปรแกรมย่อยกลับคืนสู่โปรแกรมที่เรียกใช้

โปรแกรมย่อยแบ่งออกเป็น 2 แบบได้แก่ โปรแกรมย่อยที่ส่งค่าคืน (Return) จากโปรแกรมย่อยนั้นกลับมายังโปรแกรมที่เรียกใช้ มักถูกเรียกว่าฟังก์ชัน (Function) และโปรแกรมย่อยที่ไม่ส่งค่าคืนกลับมา มีหลายชื่อแล้วแต่ภาษา เช่น Procedure, Sub (ในภาษา C, Java จะมองโปรแกรมย่อยที่ไม่ส่งค่ากลับเป็นฟังก์ชันแบบ void) แต่ค่าในอธิบายที่กล่าวมานี้ยังไม่ใช่พารามิเตอร์และอาร์กิวเมนต์ เนื่องจากค่าที่กล่าวมาเป็นค่าที่ส่งหลังจากโปรแกรมย่อยทำงานเสร็จแล้ว


พารามิเตอร์ V.S. อาร์กิวเมนต์

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


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

อย่าเรียกพารามิเตอร์และอาร์กิวเมนต์สลับกัน เพราะสองคำนี้ถูกเรียกจากมุมมองที่ต่างกัน โปรแกรมย่อยเป็นอิสระจากโปรแกรมที่เรียกใช้ โปรแกรมย่อยจะเป็นผู้กำหนดว่าค่าใดตัวแปรชนิดใดควรนำเข้ามา โปรแกรมที่เรียกใช้ต้องส่งอาร์กิวเมนต์ให้ถูกต้องตามที่โปรแกรมย่อยกำหนดเท่านั้น นอกจากนี้ยังมีคุณสมบัติหลายอย่าง เช่น การตั้งชื่อโปรแกรมย่อยซ้ำกันแต่มีพารามิเตอร์ต่างกัน (Overloading) หรือการตั้งค่าเริ่มต้น (Default) สำหรับพารามิเตอร์ที่ไม่ได้รับอาร์กิวเมนต์, รวมทั้งค่าของพารามิเตอร์และค่าของอาร์กิวเมนต์ถูกเก็บแยกกันเป็นตัวแปรคนละตัว เพียงแค่เป็นตัวแปรคนละตัวที่มีค่าเหมือนกัน (ยกเว้นว่าเป็นพารามิเตอร์แบบ Reference จากอาร์กิวเมนต์)
จำง่าย ๆ ว่า “ส่งออกอาร์กิวเมนต์ นำเข้าพารามิเตอร์”

13 สิงหาคม 2562

Ren'Py พื้นฐาน | บทที่ 6 เสียงประกอบเกม

5 บทก่อนหน้าเราได้เรียนการสร้างเกมแนว Visual Novel ด้วยโปรแกรม Ren'Py ได้เรียนพื้นฐานมาครบถ้วนแล้ว? ใช่ เกมที่สร้างในบทก่อนหน้าก็ดูดีแล้ว แต่รู้สึกว่าขาดอะไรไปบางอย่างหรือเปล่า? เรายังไม่ได้ใส่เสียงในเกมเลย บทนี้จะมาเรียนกันเรื่องการใส่เสียงกัน

ประเภทเสียง

ไฟล์เสียงต้องอยู่ในโฟลเดอร์โปรเจ็กต์เกม (ชื่อโปรเจ็กต์\game) ไฟล์เสียงที่โปรแกรม Ren'Py รองรับได้แก่
  • Opus (.opus)
  • Ogg Vorbis (.ogg)
  • MP3 (.mp3)
  • WAV(.wav)

เสียงในโปรแกรม Ren'Py แบ่งเป็น 3 ประเภทได้แก่ Music, Sound, และ Voice เสียงทั้ง 3 ประเภทแบ่งตามการวนซ้ำและการเริ่มต้นดังตารางข้างล่าง ไม่จำเป็นต้องเป็นเสียงตามประเภทจริง ๆ ก็ได้ เช่น ถ้าต้องการเปิดเพลงครั้งเดียวจบ ไม่วนซ้ำ สามารถเปิดเพลงนั้นด้วยคำสั่งเปิดเสียงเอฟเฟกต์ได้ โปรแกรม Ren'Py สามารถเปิดหลายเสียงพร้อมกันได้ แต่ต้องไม่ใช่เสียงประเภทเดียวกัน (เปิดได้ประเภทละ 1 เสียง รวมเป็นเปิดได้พร้อมกัน 3 เสียง)

ความแตกต่างของประเภทเสียง
ประเภทเสียงวนซ้ำเริ่มต้นระยะเวลาเปิดเสียง
Music (เสียงเพลง)เริ่มทันทีไม่สิ้นสุด
จนกว่าจะมีคำสั่งหยุดหรือเปลี่ยนเสียง
Sound (เสียงประกอบ)เริ่มทันทีเปิดจนจบครั้งเดียว
Voice (เสียงพูด)เริ่มพร้อมกล่องข้อความต่อไปเปิดจนจบครั้งเดียว
หรือเปิดจนกว่าเปลี่ยนกล่องข้อความ (ถ้ายังไม่จบ)

นอกจากนี้โปรแกรม Ren'Py ยังมีเสียงประเภทพิเศษคือ Audio จุดเด่นของเสียงประเภทนี้คือสามารถเปิดหลายเสียงพร้อมกันได้ แม้ว่ากำลังเปิดเสียง Audio อื่นอยู่ก็ตาม แต่ Audio ค่อนข้างมีข้อจำกัดมากกว่าเสียง 3 ประเภทข้างต้น เช่น ไม่สามารถต่อคิวเสียงได้ ไม่สามารถหยุดเสียงได้ ถ้าไม่จำเป็นจริง ๆ ผู้เขียนไม่แนะนำให้ใช้เสียง Audio

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