Advertisement
  1. Game Development
  2. Unity
Gamedevelopment

สร้างเกม Arkanoid โดย Unity: ผู้เล่นของบอล

Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Build Arkanoid With Unity.
Build Arkanoid With Unity: Project Setup
Build Arkanoid With Unity: Block Mechanics, Prefabs, and Level Design

Thai (ภาษาไทย) translation by Ittipon Teerapruettikulchai (you can also view the original English article)

Final product image
What You'll Be Creating

ใน Tutorial ชุดนี้, เราจะโชว์ให้ดูถึงวิธีเกมคลาสสิกอย่าง Arkanoid (หรือ Breakout) โดยใช้ Unity, โดยจะใช้เครื่องมือสำหรับภาพ 2 มิติของ Unity เลย. ในแต่ละโพสต์, เราจะโฟกัสไปในแต่ละส่วนของเกม; ในโพสต์นี้, เราจะทำแท่นให้ผู้ควบคุมเพื่อรับบอล และทำให้บอลเคลื่อนที่ได้.

ที่ๆ เราจากมา

ในตอนที่แล้ว, คุณได้เตรียม Project, Import Assets ต่างๆ, และ เตรียม Scene สำหรับด่านแรกแล้ว. ถ้าคุณยังไม่เสร็จ Tutorial ตอนก่อน เราแนะนำจริงๆ ว่าคุณควรจะทำมันก่อนเริ่มตอนนี้

ผลของงาน

ลอง Demo นี่ดูแล้วจะเห็นว่าเรากำลังจะทำอะไรกัน:

และนี่คืออะไรที่เราจะได้ตอนจบโพสต์นี้:

การเคลื่อนที่ของผู้เล่น

คุณมีแท่นของผู้เล่นใน Interface แล้ว; ตอนนี้คุณต้องทำให้มันสามารถควบคุมได้. คุณเคลื่อนที่มันในแนวนอน, ซ้ายและขวา. ในการสร้างการเคลื่อนไหวโดยกับรับคำสั่งจากแหล่งต่างๆ เช่น Keyboard, คุณจะต้องสร้าง Script.

Script ทั้งหลาย คือ ส่วนของการโค้ดที่จะทำสิ่งใดสิ่งนึง. Unity สามารถรองรับสามภาษา: Boo, C#, and JavaScript. Script ทั้งหมดที่จะถูกสร้างใน Tutorial นี้จะถูกเขียนโดยใช้ภาษา C# (แต่สามารถใช้ภาษาอื่นได้ตามใจ ถ้าคุณชอบ).

ในการสร้าง Script, ไปที่ Tab Project, เลือก Folder Scripts, แล้วคลิกขวา แล้วจะมีเมนูโผล่ขึ้นมา. เลือก Create > C# Script. ไฟล์ใหม่ที่มีชื่อว่า NewBehaviourScript จะปรากฏ; เปลี่ยนชื่อมันเป็น PlayerScript ใน Tab Inspector คุณจะเห็นเนื้อหาของ Script.

ดับเบิลคลิก ที่ Script เพื่อแก้ไขมัน โดยปกติ MonoDevelop IDE จะถูกเปิดขึ้นมา, แต่คุณสามารถตั้งค่าให้ใช้งาน Code Editor ตัวอีกที่คุณชอบได้.

Script ทั้งหมดจะมี 2 Method โดยปกติ:

  • Start(): ใช้สำหรับตั้งค่าเริ่มต้นให้กับตัวแปรต่างๆ ที่เราต้องใช้ในโค้ดของเรา.
  • Update(): ถูกเรียกทุกเฟรมของเกม, และใช้ในการเปลี่ยนแปลงค่าต่างๆ ของเกม.

ในการเคลื่อนตัวผู้เล่น, คุณต้องมีสองส่วนนี้:

  • ตำแหน่งของผู้เล่น
  • ความเร็วของผู้เล่น

ดังนั้น, สร้างตัวแปรสองตัว เพื่อเก็บค่าต่างๆ เหล่านั้น:

แล้วอย่างที่คุณอาจจะสังเกตุได้, playerVelocity เป็นตัวแปรแบบ Public ในขณะที่ playerPosition นั้นเป็นแบบ Private. ทำไมเราทำยังงั้นล่ะ? เอาล่ะ, Unity อนุญาติให้คุณสามารถเปลี่ยนค่าตัวแปรแบบ Public ได้ทาง Editor โดยไม่ต้องแก้อะไรในส่วนของโค้ดเลย; นี่เป็นสิ่งที่มีประโยชน์มากตอนที่คุณมีตัวแปรหลายๆ ตัว ที่ต้องการเปลี่ยนแปลงค่า หลายๆ ครั้ง. ความเร็ว (Velocity) คือหนึ่งในกรณีนั้น, ดังนั้นเราตั้งให้มันเป็นแบบ Public.

Save ไฟล์ Script (ใน MonoDevelop) แล้วกลับไปที่ Unity Editor อีกครั้ง

ตอนนี้คุณมี Script; คุณแค่ต้องกำหนดมันให้กับ Object แท่น (Paddle) ของผู้เล่นของคุณ. เลือกที่แท่น (Paddle) ผู้เล่นจาก Tab Hierarchy, แล้วใน Tab Inspector, คลิก Add Component. แล้วพิมพ์ชื่อ Script ที่คุณเพิ่ง Save ไป เพื่อเพิ่มมันเข้าสู่ Game object.

สำหรับข้อมูลเพิ่มเติมของ Concept ของ Components และ วิธีการทำงานของมันใน Unity, ดู Unity: Now You're Thinking With Components.

ทางเลือกอื่นคือเพิ่ม Script โดยการลากจาก Folder แล้ววางตรงส่วนของ Add Component. คุณควรจะเห็นบางอย่างแบบนี้ใน Inspector:

อย่างที่คุณเห็น, เมื่อเราตั้งให้ตัวแปร playerVelocity เป็นแบบ Public, คุณจะสามารถตั้งค่าของมันได้ใน Editor. ตอนนี้, ตั้งค่าของมันเป็น 0.3 และคืนค่าให้ Code.

คุณกำลังจะตั้งค่าเริ่มต้นให้ตัวแปร playerPosition. ในการทำสิ่งนั้น, คุณต้องเข้าถึงค่าตำแหน่งของ Game object ใน Method Start:

ตอนนี้เราได้ทำการกำหนดค่าตำแหน่าง เริ่มต้น และ ความเร็วในกับแท่น (Paddle) ของผู้เล่นแล้ว, แต่เรายังต้องทำให้มันควบคุมได้. เพื่อการนั้น, เราแก่ Method Update.

เมื่อเราต้องการให้มันเคลื่อนที่ได้ในแนวนอนเท่านั้น, เราสามารถใช้ Method GetAxis ของ Class Input ในการหาทิศทางที่ผู้เล่นควบคุมตามแกนแนวนอน (-1 ไปทางซ้าย, +1 ไปทางขวา), คูณด้วยค่าความเร็ว (Velocity), เพิ่มค่านี้ไปให้กับตำแหน่งปัจจุบันของตัวผู้เล่น, และปรับค่านี้ให้กับตัวแปร playerPosition ให้ตรงกัน.

ในระหว่างที่เราทำอะไรเกี่ยวกับ Input, เรายังสามารถตรวจสอบการออกจากเกมได้ เมื่อผู้เล่นกดปุ่ม Esc.

โค้ดส่วนหนึ่งที่เสร็จแล้ว:

Save ไฟล์ Script แล้วกลับไปที่ Unity editor. ตอนนี้กด Play แล้วลองเคลื่อนที่แท่น (Paddle) ไปทางซ้ายและขวาโดยใช้ปุ่มลูกศรดู.

กำหนดพื้นที่ของเกม

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

ในการสร้างกรอบ, สร้างตัวแปรแบบ Public ใหม่ - ตั้งชื่อว่า boundary

ตัวแปรนี้จะเก็บค่าสูงสุดของแกน X ที่ผู้เล่นสามารถเคลื่อนที่ไปได้ ตอนนี้เรากำลังจะสร้างด่านที่มีจุดศูนย์กลางอยู่ที่ตำแหน่ง (0, 0, 0), นั่นหมายความว่า ค่าของขนาดกรอบนั้นจะเหมือนกันทั้งค่าบวกและลบ X.

เพื่อหลีกเลี่ยงไม่ให้ตัวละครทับกับกรอบได้, เราจะเพิ่มเงื่อนไข if เข้าไป. โดยทั่วไปแล้ว, เราจะกำหนดเงื่อนไขว่า ถ้าค่า X ของตำแหน่ง มากกว่าค่าของขนาดกรอบ, แล้วค่า X จะถูกกำหนดให้เท่ากับค่าของขนาดกรอบ. ทีนี้, เราก็สามารถมั่นใจได้ว่าแท่น (Paddle) จะไม่หลุดออกจากกรอบพื้นที่ของเกมไป. Code ที่เกี่ยวข้องมีดังนี้:

ตอนนี้, กลับไปที่ Editor แล้วกำหนดค่าที่เหมาะที่สุดให้กับ boundary. โดยลากแท่น (Paddle) ไปตำแหน่งในแกน X, คุณจะเห็นว่าค่าที่ดีที่สุดคือ 5.46 (ตามใน Project ของเรา).

ใน Inspector, เปลี่ยนค่าแกน X ของแท่น (Paddle) กลับมาเป็น 0, และใส่ค่า 5.46 ให้กับตัวแปรขนาดของกรอบ (boundary) ใน Component Player Script

กด Play ใน Editor. ตอนนี้คุณจะสามารถเคลื่อนแท่น (Paddle) ได้, แต่ไม่หลุดออกนอกพื้นที่ของเกมแล้ว.

สร้างตัวแปรเกี่ยวกับ Physic

กับเกมแบบนี้, เราต้องมีตัวแปรเกี่ยวกับ Physic ให้กับ: ตัวของผู้เล่น, บอล และ กำแพงทั้งหลาย. ตอนนี้เรากำลังทำเกม 2 มิติอยู่, เราจะใช้งาน Collider แบบ 2 มิติ (Collider คือ องค์ประกอบที่ทำให้ Game object ใดๆ สามารถตอบสนองกับ Game object ที่มี Collider อันอื่นได้)

เริ่มจากเพิ่ม Collider ให้กับแท่น (Paddle) ของเรา. ใน Tab Hierarchy, เลือก แท่น (Paddle) ของเรา. แล้วไปที่ Tab Inspector, คลิก Add Component แล้วพิมพ์ว่า collider อย่างที่คุณจะเห็นแบบใน Screenshot ด้านล่าง, Collider ประเภทต่างๆ จะปรากฏออกมาให้คุณได้เลือกใช้. แต่ละแบบจะมีตัวแปรแต่งต่างกันตามรูปแบบของวัตถุ.

เราได้ทำให้แท่น (Paddle) ของผู้เล่นเป็นสี่เหลี่ยม, เราจะเลือกใช้ Box Collider 2D.  เลือกมัน, แล้ว Component จะถูกเพิ่มไปให้กับแท่น (Paddle) โดยอัตโนมัติ ค่าของขนาด, และตำแหน่งจุดศูนย์กลางของ Collider จะถูกกำหนดไว้แล้ว; โดยจะเป็นค่าปกติที่ใช้งานได้เลย, ดังนั้นคุณไม่จำเป็นต้องเปลี่ยนค่าของมัน.

ตอนนี้, ทำการเพิ่ม Collider ให้กับ Bar ทั้งหลาย และ Block ด้วย โดยใช้ขั้นตอนเดิม. (Hierarchy > Inspector > Add Component > Box Collider 2D).

ตอนนี้ Game object ทุกอันก็มี Collider แล้ว, ยกเว้นบอล.  บอลมันรูปร่างต่างกัน, ดังนั้นเราจะต้องใช้ Collider อีกแบบนึง. เลือกมันแล้ว, ใน Tab Inspector, เพิ่ม Component ชื่อ Circle Collider 2D

ค่าต่างๆ ของ Circle Collider 2D ก็จะคล้ายๆ กับ Box Collider, แต่จะไม่มีค่า ขนาด (Size)  ที่ใช้กำหนดเป็นค่ากว้างและสูงของกล่อง, มันจะมีค่า รัศมี (Radius) ที่ใช้กำหนดรัศมีของวงกลมแทน.

ทำ Material ที่เด้งได้

ในการที่จะทำให้บอลเด้งได้, เราต้องสร้าง Physic Material ที่เด้งได้ และ แนบไปที่บอล. Unity ได้เตรียมระบบ Physic Material ไว้อยู่แล้ว, ดังนั้นสิ่งที่เราจะต้องทำคือการเพิ่มมัน.

ใน Tab Project, สร้างโฟลเดอร์ใหม่ข้างในโฟลเดอร์ Asset แล้วตั้งชื่อว่า Physics. เลือกที่โฟลเดอร์, คลิกขวา -> Create, แล้วเลือก Physics2D Material. ตั้งชื่อ Physics material อันใหม่ของคุณว่า BallPhysicsMaterial.

Physic Material นั้นจะมี 2 Parameters ได้แก่ Friction และ Bounciness. ถ้าคุณอยากให้มันเด้งได้โดยไม่มีแรงเสียดทานเลย, ก็เปลี่ยนค่าตามนี้: Friction เป็น 0Bounciness เป็น 1.

ตอนคุณก็มี Physic Material ที่พร้อมใช้งาน, ต่อไปก็เอามันไปใส่ที่บอล. เลือก Game Object ของบอลใน Tab Hierarchy แล้วดูที่ Tab Inspector. ถ้าคุณลองดูใกล้ๆ Circle Collider 2D ของคุณ, คุณจะสังเกตุเห็นได้ว่า Component มี Parameter ชื่อ Material; ตรงนี้, คุณสามารถแนบ Physic Material ของคุณเข้าไปได้

ในการแนบ BallPhysicsMaterial, แค่ลากมันเข้าไปใน Parameter Material ของ Collider.

เพิ่ม Rigid Body

ในการทำให้เคลื่อนที่ภายใต้การควบคุมของ Physics, เราต้องเพิ่มอีกสิ่งหนึ่งคือ: Rigidbody. เลือกที่บอลและเพิ่ม Component ชื่อว่า RigidBody 2D.  Component นี้มี Parameters ต่างๆ ที่สามารถปรับแต่งได้.  เมื่อบอลจะเคลื่อนที่โดยใช้การเด้งกระดอนเท่านั้น, คุณควรเปลี่ยนค่า Gravity Scale จาก 1 เป็น 0 - ทำแบบนี้เพื่อให้ชัวร์ว่าแรงโน้มถ่วงจะไม่ส่งผลต่อบอล ค่าที่เหลือสามารถปล่อยไว้ให้เป็นค่าปกติของมันได้:

Script ควบคุมบอล

บอลจะต้องเคลื่อนที่, ดังนั้นเราต้องเขียน Script เพื่อการกระทำนั้น.

สร้าง Script ใหม่ (เราจะใช้ C# อีกนั่นแหละ) แล้วตั้งชื่อมันว่า BallScript. ใส่ Script ใหม่นี้ไปที่บอล (Hierarchy > Inspector > Add Component).

ตอนนี้, ลองวิเคราะห์กฏและคุณสมบัติที่บอลต้องมี, ก่อนเริ่มการเขียน Script:

  • บอลจะต้องมีสองสถานะคือ: ไม่ทำงาน (Inactive) (บอลจะเคลื่อนที่ตามแท่น (Paddle) ก่อนเริ่มเกม) และ กำลังทำงาน (Active) (เด้งออกจาก แท่น, กำแพง และ Block ต่างๆ).
  • บอลจะเริ่มทำงาน (Active) ก็ต่อเมื่อผู้เล่นทำงานกดปุ่มที่กำหนดไว้.
  • ตอนที่บอลเริ่มทำงาน (Active), เราจะกำหนดค่าพลังงานให้กับมันเพื่อให้มันเริ่มเคลื่อนไหว.
  • ถ้าบอลตกออกนอกหน้าจอ, เราจะรีเซ็ตให้มันกลับมาที่แท่น.

จากข้อมูลดังกล่าว, เราจะกำหนดตัวแปร ballIsActiveballPosition, และ ballInitialForce.

ตอนนี้คุณมีตัวแปรต่างๆ แล้ว, คุณควรกำหนดค่าเริ่มต้นให้มัน. ใน Start, คุณควร:

  • สร้างพลังงานเพื่อดันบอลให้เคลื่อนที่.
  • ตั้งค่าให้บอลไม่ทำงาน (Inactive).
  • เก็บค่าตำแหน่งของบอล.

นี่คือสิ่งที่มันเป็น:

ตอนนี้, เราได้กำหนดพลังงานในแกน Y เป็น 300 เพื่อให้บอลเคลื่อนที่ขึ้น, และกำหนดพลังในแกน X เป็น 100 เพื่อให้บอลเคลื่อนที่แบบเฉียง ไม่ใช่แค่เคลื่อนที่แบบตรงขึ้นเท่านั้น. ทางนี้, คุณบังคับผู้เล่นให้เคลื่อนตำแหน่งของแท่น (Paddle).

ใน Update, เราจะทำการกำหนดให้เคลื่อนไหวตามแต่ละกรณี

อย่างแรก, เราต้องควบคุม Input จาก ผู้เล่น; เราจะใช้ค่าปกติของปุ่ม กระโดด (Jump) ของ Unity เป็นปุ่ม Action สำหรับทำสิ่งต่างๆ. ปุ่มที่ใช้ กระโดด (Jump) สามารถเปลี่ยนได้. แต่ค่าปกติของมันจะเป็น ปุ่ม Space bar.

สิ่งต่อไปที่จะต้องทำคือการตรวจสอบสถานะของบอล, ปุ่ม Action มันควรจะใช้งานได้ก็ต่อเมื่อบอลอยู่ในสถานะยังไม่ทำงาน (Inactive):

สมมติว่าตอนนี้กำลังเริ่มเกม, แล้วเราต้องกำหนดพลังงานให้กับบอลและกำหนดให้มันอยู่ในสถานะทำงาน (Active). ฟังก์ชัน Update ที่แก้ใหม่ควรจะเป็นแบบนี้:

ตอนนี้, กดปุ่ม Play เพื่อลองเล่น และทดสอบปุ่ม กระโดด (Jump); คุณจะสังเกตุว่าบอลจะถูกผลักออกไปและเริ่มเด้งกระดอนอย่างที่มันควรจะเป็น. อย่างไรก็ตาม, คุณก็ยังสังเกตุได้อีกว่าบอลไม่ได้เคลื่อนไหวตามแท่น (Paddle) เมื่อมันอยู่ในสถานะไม่ทันงาน (Inactive). หยุดเกมแล้วมาแก้ไขมันกัน.

ในฟังก์ชัน Update, เราต้องตรวจสอบสถานะของบอล และ, ถ้าบอลยังไม่ทำงาน (Inactive), เราต้องตรวจสอบให้แน่นอนก่อนว่าค่าตำแหน่งในแกน X ของบอลตรงกับของแท่น (Paddle) รึเปล่า.

อ๊ะ, แต่เราจะเอาค่าตำแหน่งของ Game object อันอื่นมาได้ยังไงกัน?  ง่ายๆ เลย: เราแค่สร้างตัวแปรสำหรับเก็บค่า Game Object ของแท่น (Paddle) เข้าไป. ดังนั้น, สร้างตัวแปรประเภท GameObject สำหรับใช้อ้างอิงถึงแท่น (Paddle):

กลับไปที่ฟังก์ชัน Update.  เราจะตรวจสอบสถานะของบอล และ ค่าที่อ้างอิงถึงแท่น (Paddle).  ถ้าสถานะเป็นไม่ทำงาน (Inactive) และ ค่าที่อ้างอิงถึงแท่น (Paddle) ไม่ว่างเปล่า (null) (นั่นแสดงว่าเราได้อ้างอิงถึงมันแล้ว), บอลควรเคลื่อนที่ตามตำแหน่งของแท่น (Paddle). ฟังก์ชัน Update ที่เสร็จแล้วตอนนี้: 

Save แล้วกลับมาที่ Editor. อย่างที่คุณอาจสังเกตุเห็นได้, ค่าอ้างอิงของแท่น (Paddle) เป็นแบบ public, หมายความว่าเราสามารถกำหนดค่ามันได้ผ่านทาง Editor. ใน Tab Hierarchy, เลือกที่บอล. ใน Inspector, คุณจะสังเกตุได้ว่า Parameter Player Object ในตอนนี้เป็น None.

ในการกำหนดค่าอ้างอิงถึงแท่น (Paddle), สามารถทำได้ง่ายๆ โดยการลากและวาง Game object ของแท่น (Paddle) จาก Hierarchy เข้าไปใน Parameter Player Object.

กดปุ่ม Play, แล้วทดสอบเกมของคุณ. ตอนนี้คุณจะเห็นบอลตามแท่น (Paddle) ก่อนกดปุ่มกระโดด (Jump).

การเริ่มเกมใหม่

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

เราจะตรวจสอบว่าถ้าบอลทำงานอยู่ (Active) และ ตำแหน่งในแกน Y น้อยกว่า -6. ที่ใช้, เราจะทำการรีเซ็ตบอลให้อยู่ในสถานะไม่ทำงาน (Inactive) และ รีเซ็ตตำแหน่งบอลให้อยู่บนแท่น (Paddle). Script สำหรับส่วนดังเล่าวจะเป็นแบบนี้:

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

เอาล่ะ, จำได้มั้ยว่าเราเพิ่มพลังงานให้บอลทุกครั้งตอนปล่อยมัน - ดังนั้น, ทุกๆ ครั้งที่เริ่มเกมใหม่, คุณจะเพิ่มพลังงานให้ Rigid Body, ทำให้เกมเล่นยากขึ้น. ดังนั้น, คำถามคือ, เราจะแก้ปัญหานี้ยังไง ?

ในการกำหนดพลังงานให้เป็นแบบเดิมทุกครั้ง, เราต้องลบล้างพลังงานเก่าที่เคยกำหนดไว้ออกไปก่อน. ในการทำแบบนั้น, สามารถทำได้ง่ายๆ โดยการเปิดใช้งานค่า Parameter Is Kinematic ทุกครั้งที่บอลหยุดเคลื่อนที่, และปิดการใช้งานเมื่อเกมเริ่ม. Parameter นี้ใช้กำหนดให้ Physic มีผลต่อบอลหรือไม่, และถ้าไม่ได้เปิดใช้งาน มันจะตรวจสอบและกำหนดพลังงานทั้งหมด ก่อนที่จะหายไป.

เพิ่มอีกสองบรรทัดในฟังก์ชัน Update เพื่อที่มัน:

  • rigidbody2D.isKinematic = false ก่อนเพิ่มพลังงาน, และ
  • rigidbody2D.isKinematic = true เมื่อเราอยากให้บอลเริ่มเคลื่อนที่อีกครั้ง.

ท้ายที่สุด, ฟังก์ชัน Update จะหน้าตาประมาณนี้:

ตอนนี้, คุณสามารถกดปุ่ม Play ลองเล่นและตรวจสอบคุณสมบัติต่างๆ ดู.

ตอนต่อไป

นี่คือส่วนสรุปส่วนที่สองของซีรีย์นี้. ตอนนี้คุณได้ลองทำการเขียน Scripts, ใช้งาน Physics Colliders, และ ควบคุมการรับ Input. ตอนต่อไป, เราจะมาก่อ Block ต่างๆ กัน.

ถ้าคุณมีคำถามหรือข้อเสนอแนะใดๆ สามารถคอมเมนท์ข้างใต้นี้ได้.


Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.