บทเรียนการพัฒนาเกมแนว 2.5D แบบ Side Scrolling ร่วมกับโมเดล 3 มิติกับแนวเกมเดินต่อสู้ด้านข้าง หรือแนว Beat Em Up ด้วย Unity 3D เวอร์ชัน 5 กับการควบคุมตัวละคร
เกมแนว Beat Em Up เป็นเกมแนว Old School ที่มีการพัฒนามานานในระบบเกมรุ่นเก่าๆ ในยุคหลังๆ เนื่องจากจะประหยัดการใช้ Sprite Sheet 2มิติที่ต้องทำทีละเฟรม นักพัฒนาจึงนิยมปั้น โมเดล 3 มิติแล้วใช้การปรับแกนของมุมมองให้เป็น ระนาบแกน X,Y ออกไปแล้ให้ความสำคัญของระนาบแกน Z น้อยลง เลยกลายเป็นเกมแนว 2.5D หรือกึ่งๆ 3 มิติ
ตัวอย่างนี้จะเป็นการเริ่มต้นในการปรับมุมกล้องเพื่อทดสอบการทำ Workshop นี้โดยจะเริ่มที่การใช้เครื่องมือควบคุมตัวละครให้กดปุ่มเดินหน้า และถอยหลังๆ ได้อย่างปรกติอย่างที่ ตัวละครควรจะเป็นครับ
เริ่มต้นให้เปิด Project Unity ขึ้นมาได้เลยครับ
หลังจากนั้นให้สร้าง Plane ขึ้นมาปรับ Inspector ดังนี้ครับ
ตัวละครผมไปดาวน์โหลดมาจากชุดแจกฟรี Free Learning ของเว็บไซต์ Mixamo.com ก็ต้องนำมา Rig ตัวโมเดลผ่าน Unity ให้เป็น Humaniod กันสักเล็กน้อย (วิธี Rig อ่านได้ที่ https://www.daydev.com/2015/unity-3d-model-humanoid-import.html)
ทำการวางตัวละครลงไปใน Scene ครับแล้วหมุนกล้อง Main Camera ของเราแบบ Rotate ในด้านข้างเพื่อปรับระดับการฉายภาพของกล้อง พร้อมทั้งตั้งค่าระยะให้เหมาะสม
ตั้ง Inspector ตามนี้ได้ครับ
หากตั้งค่าระยะของกล้องได้เหมาะสมแล้วจะเห็น Preview ใน Game Scene ประมาณนี้
ทำการควบคุมตัวละครกันสักเล็กน้อยครับ โดยการใส่ Physics->RigidBody (ไม่ต้องใส่ Gravity), ส่วนของ Physics -> Character Controller และ Physics -> Capsule Collider พร้อมกับปรับขนาดของ Capsule และ Controller ให้พอดีตัวละครของเรา อย่าลืม Is Trigger ใน Capsule Collider ด้วยครับ
ไปหา Animation จาก Asset Store ที่เราคิดว่าจะนำมาใช้มาตั้งค่าของ Animator Controller ครับ (อ่านย้อนหลังได้ที่ https://www.daydev.com/2015/unity-animator-controller.html)
จะเห็นว่าตั้ง Bool ใน Parameters ของ Animator Controller ไว้ชื่อว่า “IsRunning” ไว้เช็คกับโปรแกรมภาษา C# ครับ (เอา Has Exit Times ออกด้วยนะครับตอนทำ Transition ของ State – อ่านย้อนหลังได้ที่ https://www.daydev.com/2015/unity-animator-controller.html)
ทดสอบว่า Animator ทำงานหรือเปล่า
เอาล่ะถ้าครบแล้วเรามาเขียน Code กันสร้าง C# ชื่อ Player.cs ขึ้นมาครับในตอนนี้จะเป็นการควบคุมตัวละครของเราให้เดินไปมาในฉาก หากใช้ Code
CharacterController controller = GetComponent<CharacterController>(); if (controller.isGrounded) { moveDirection = new Vector3(-(Input.GetAxis("Horizontal")), 0, Input.GetAxis("Vertical")); if (Input.GetButton("Jump")) moveDirection.y = jumpSpeed; moveDirection = transform.TransformDirection(-moveDirection); moveDirection *= speed; }
มันจะกลายเป็นว่าตัวละครของเราจะกด W เป็นเดินไปทางขวากด S เป็นเดินไปทางซ้ายซ้ำยังไม่หันหลังกลับด้านในทิศที่ต้องการไปอีกต่างหาก (เดินถอยหลัง ปุ่มบังคับผิด)
Code ไฟล์ Player.cs ต้องมีการเปลี่ยนส่วนของการควบคุมเป็นแบบนี้ครับ
if (controller.isGrounded) { moveDirection = new Vector3(-(Input.GetAxis("Vertical")), 0, Input.GetAxis("Horizontal")); }
เป็นการสลับปุ่มให้ A,D เป็น เดินไปซ้าย และ ขวา และ W,S เป็นเดินเลื่อนขึ้น และ เดินเลื่อนลงมาแทนครับ แต่ปัญหาที่พบคือจะเห็นว่าตัวละครเมื่อกด A จะเดินถอยหลังไม่สามารถหมุนตัวละครกลับไปด้านซ้ายได้ เราเลยต้องมีการเขียน Code เพิ่มเข้ามาคือการรับค่า Quaternion เพื่อ Rotate ตัวละครของเราแล้วนำไปคำนวณกับ Speed ของการเดินอ้าง Direction ที่เป็นค่า (-1,1) คือ Transform ตัว GameObject ไปทางซ้ายพร้อมหันหน้า 180 องศา และทางขวาในรูปแบบเดียวกันครับ อ้างด้วยเครื่องหมาย -1 เป็นการกลับด้านของ Game Object
การเขียนไฟล์ C# Player.cs จึงต้องเป็นไปตามขั้นตอนนี้ครับ
ประกาศตัวแปรดังต่อไปนี้ครับ
Animator anim; public float smooth = 1f; public float speed = 6.0F; public float jumpSpeed = 8.0F; public float gravity = 20.0F; private Quaternion lookLeft; private Quaternion lookRight; private Vector3 moveDirection = Vector3.zero;
สังเกตที่
private Quaternion lookLeft; private Quaternion lookRight;
เป็นการกำหนด สถานะของการหมุน Object ด้วยตัวแปร lookLeft และ lookRight เพื่อให้หมุนหรือหันไปทิศที่ต้องการก่อนจะเคลื่อนไหว
void Start(){ Cursor.visible = false; anim = GetComponent <Animator> (); Time.timeScale = 1; lookRight = transform.rotation; lookLeft = lookRight * Quaternion.Euler(0, 180, 0); }
ทำการเพิ่ม Method Start() โดยซ่อน Cursor Mouse ออกไปเมื่อเริ่มเกม ตามด้วยกำหนด Component Animator ที่เราสร้างไว้ใหตัวละครเก็บ State ต่างๆ ไว้ในตัวแปร anim
กำหนด lookRight เป็นค่า Rotation เริ่มต้นให้ตัวละครเริ่มจาก ซ้าย และหันหน้าไปทางขวาก่อน และตั้งค่า lookLeft เป็นการอ้าง lookRight เพียงแค่ปรับแกน y ของตัวละคร เป็น 180 เพื่อให้ Rotate หันหลัง
เพิ่ม Code ต่อไปนี้ใน Method Update()
void Update() { CharacterController controller = GetComponent<CharacterController>(); if (controller.isGrounded) { moveDirection = new Vector3(-(Input.GetAxis("Vertical")), 0, Input.GetAxis("Horizontal")); if (Input.GetButton("Jump")) moveDirection.y = jumpSpeed; if (Input.GetKey(KeyCode.A)){ transform.rotation = lookLeft; moveDirection = transform.TransformDirection(-moveDirection); moveDirection *= speed; anim.SetBool ("IsRunning", true); }else{ anim.SetBool ("IsRunning", false); } if (Input.GetKey(KeyCode.D)){ transform.rotation = lookRight; moveDirection = transform.TransformDirection(moveDirection); moveDirection *= speed; anim.SetBool ("IsRunning", true); }else{ anim.SetBool ("IsRunning", false); } } moveDirection.y -= gravity * Time.deltaTime; controller.Move(moveDirection * Time.deltaTime); }
พิจารณาส่วนของการเคลื่อนไหวใน Method Update()
if (Input.GetKey(KeyCode.A)){ transform.rotation = lookLeft; moveDirection = transform.TransformDirection(-moveDirection); moveDirection *= speed; anim.SetBool ("IsRunning", true); }else{ anim.SetBool ("IsRunning", false); }
เมื่อมีการกดปุ่มคีย์บอร์ด A ตัวละครจะทำการ transform rotation ไปที่ค่าของ lookLeft (ค่า lookRight ที่ปรับแกน y เป็น 180) ดังนั้นค่า movedirection หรือการเคลื่อนตัวละคร ต้องให้ TransfromDirection() เป็นค่า -moveDirection เพราะต้องวิ่งไปฝั่งตรงข้ามของการหันหน้า (วิ่งไปทางซ้าย นั่นเอง ให้เราทำการแสดง Animator state ที่เราตั้ง Bool ไว้ว่า IsRunning เป็น true และเมื่อปล่อยปุ่มก็ให้เป็น false
เช่นกันถ้ากดปุ่ม D จะคล้ายคลึงกันแค่ transform rotation ไปที่ค่าของ lookRight และตัว TransfromDirection() เป็นค่า moveDirection ที่ไม่ติดลบครับ
Code ไฟล์นี้จะออกมาหน้าตาแบบนี้
using UnityEngine; using System.Collections; public class Player : MonoBehaviour { Animator anim; public float smooth = 1f; public float speed = 6.0F; public float jumpSpeed = 8.0F; public float gravity = 20.0F; private Quaternion lookLeft; private Quaternion lookRight; private Vector3 moveDirection = Vector3.zero; void Start(){ Cursor.visible = false; anim = GetComponent <Animator> (); Time.timeScale = 1; lookRight = transform.rotation; lookLeft = lookRight * Quaternion.Euler(0, 180, 0); } void Update() { CharacterController controller = GetComponent<CharacterController>(); if (controller.isGrounded) { moveDirection = new Vector3(-(Input.GetAxis("Vertical")), 0, Input.GetAxis("Horizontal")); if (Input.GetButton("Jump")) moveDirection.y = jumpSpeed; if (Input.GetKey(KeyCode.A)){ transform.rotation = lookLeft; moveDirection = transform.TransformDirection(-moveDirection); moveDirection *= speed; anim.SetBool ("IsRunning", true); }else{ anim.SetBool ("IsRunning", false); } if (Input.GetKey(KeyCode.D)){ transform.rotation = lookRight; moveDirection = transform.TransformDirection(moveDirection); moveDirection *= speed; anim.SetBool ("IsRunning", true); }else{ anim.SetBool ("IsRunning", false); } } moveDirection.y -= gravity * Time.deltaTime; controller.Move(moveDirection * Time.deltaTime); } }
ทดสอบกดปุ่ม A และ D ครับ
เดินหน้าถอยหลังได้แล้ว
บทเรียนต่อไปจะเป็นการสร้าง Animation และการกำหนด Collider ของตัวละครเมื่อมีการต่อสู้ และ Trigger กันครับ
Tutorial Sample Project: ดาวน์โหลดได้ที่:
https://drive.google.com/file/d/0B1kwQ1abTIRrNUM3QW9JZlllUUU/view?usp=sharing