บทเรียนตัวอย่างต่อเนื่องจากการ นำโมเดล 3 มิติของเราที่ Rigged แล้วมาใช้ในเกมโดยบทเรียนนี้จะเป็นการเขียนเกม 3 มิติด้วย Unity 3D การใช้ Animator Controller
ก่อนอื่นหากไม่เคยรู้จัก Unity มาก่อนให้ไปศึกษาบทเรียนย้อนหลังที่นี่ครับ
https://www.daydev.com/tag/unity
บทเรียนนี้จะเป็นการต่อยอดจากบทเรียนก่อน นั่นคือ: “เขียนเกม Unity การทำ Humanoid ให้กับ โมเดลตัวละคร 3 มิติ” มาใช้ในการเขียนโปรแกรมควบคุมตัวละครครับ
จากบทเรียนก่อนหน้าเราจะได้ตัวละครของเราที่ใช้งาน Humanoid และ Animator ได้แล้ว
ให้เราไปหา Animation พื้นฐานของ Unity มาทดสอบการเคลื่อนไหวดูครับซึ่งเบื้องต้นผมไปดาวน์โหลด Template ตัว Complete Project มาก่อน
มีตัวฟรีใน Asset Store ครับ https://www.assetstore.unity3d.com/en/#!/content/5328
ทำการ Login เข้า Asset Store แล้ว Download พร้อม Import มาใช้ในเกมได้เลยครับ
เบื้องต้นกลับไปที่ Scene View ก่อน แล้วทำการเพิ่ม Character Controller และ Capsule Collider ขึ้นมาพร้อมทำการ Trigger
อย่าลืมใส่ Ridgid Body นะครับ
ต่อจากนั้นให้เราสร้าง Animator Controller ขึ้นมา คลิกขวา Create จาก Project หรือจะเอาบทเรียนก่อนหน้ามาปรับใช้ก็ได้
ไปที่ แท็บชื่อ “Parameters” ทำการเพิ่ม ตัวแปร Bool ซึ่งจะมีผลแค่ true และ false ตั้งชื่อสถานะ หรือ State parameters ว่า “IsWalking”
ลาก Animation จาก Project ของเราไปวาง โดยเลือก idle และ run มาลองใช้
ลากไปวางที่ Animator Controller ของเราครับ
คลิกขวาเลือก “Make Transition” แล้วลากไปวางที่ Run ไปเชื่อมต่อกัน
คลิกที่เส้นลูกศรให้เป็นสีน้ำเงินแล้ว เพิ่ม Conditions เลือก IsWalking เป็น true เพื่อเป็นการบอกว่า การเปลี่ยน state สถานะจากยืน idle ไปเป็นวิ่ง หรือ Run นั้นจะเกิดก็ต่อเมื่อ IsWalking เป็น true
ลากเส้น Make Transition จาก Run มา idle เหมือนกันเพิ่ม Conditions จาก IsWalking = true ให้เป็น false นั่นคือเมื่อไม่มีการวิ่งก็ให้กลับมาเป็นยืนนิ่งๆ แบบ Idle
เพิ่ม Parameter ใหม่เข้าไปคือ IsJumping เป็น Bool ครับ ไปหา Animation ตอนกระโดด มาวางแล้วทำ Transition แบบเดียวกับ idle -> run แต่เปลี่ยนเป็นจาก Run -> Jump แทน
บันทึก Animator ตัวนี้ แล้วลากไปใส่ที่ตัว Player ของเรา
เขียนคำสั่ง C# ขึ้นมาใหม่ชือว่า Players.cs ครับ แล้วใส่ code ตามนี้
using UnityEngine; using System.Collections; public class Players : MonoBehaviour { Animator anim; public float speed = 6.0F; public float jumpSpeed = 10.0F; public float gravity = 10.0F; private Vector3 moveDirection = Vector3.zero; public bool Running = false; public bool Jumping = false; public float rotationSpeed = 100.0F; void Start(){ anim = GetComponent <Animator> (); } void Update() { CharacterController controller = GetComponent<CharacterController>(); if (controller.isGrounded) { moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); moveDirection = transform.TransformDirection(moveDirection); moveDirection *= speed; if (Input.GetButton("Jump")){ moveDirection.y = jumpSpeed; Jumping = true; Debug.Log ("Jump Status:"+Jumping); }else{ Jumping = false; } if (Input.GetKey((KeyCode.D)) || Input.GetKey("right") || Input.GetKey((KeyCode.A)) || Input.GetKey("left") || Input.GetKey((KeyCode.D)) || Input.GetKey("up") || Input.GetKey((KeyCode.W)) || Input.GetKey("down") || Input.GetKey((KeyCode.S)) ){ Running = true; }else{ Running = false; } if (Input.GetKey(KeyCode.S)){ } Debug.Log ("state:"+Running); if(Running == true){ //anim.SetTrigger("Running"); anim.SetBool ("IsWalking", true); }else{ anim.SetBool ("IsWalking", false); } if(Jumping == true){ //anim.SetTrigger("Running"); anim.SetBool ("IsJumping", true); }else{ anim.SetBool ("IsJumping", false); } } //Mouse movement float translation = Input.GetAxis("Vertical") * speed; float rotation = Input.GetAxis("Horizontal") * rotationSpeed; translation *= Time.deltaTime; rotation *= Time.deltaTime; transform.Translate(0, 0, translation); transform.Rotate(0, rotation, 0); moveDirection.y -= gravity * Time.deltaTime; controller.Move(moveDirection * Time.deltaTime); } }
โดยสังเกตจุดนี้ครับ
if (Input.GetKey((KeyCode.D)) || Input.GetKey("right") || Input.GetKey((KeyCode.A)) || Input.GetKey("left") || Input.GetKey((KeyCode.D)) || Input.GetKey("up") || Input.GetKey((KeyCode.W)) || Input.GetKey("down") || Input.GetKey((KeyCode.S)) ){ Running = true; }else{ Running = false; }
เมื่อมีการกดปุ่ม A,S,W,D ก็จะเปลี่ยนสถานะของ Running ที่เราประกาศเป็น bool อยู่แล้วให้เป็น true ถ้าไม่มีการกดก็เป็น false ตัวค่าตัวแปร Running นี่แหละครับเราจะไปเทียบกับ คำสั่งนี้ครับ
anim = GetComponent <Animator> ();
if(Running == true){ //anim.SetTrigger("Running"); anim.SetBool ("IsWalking", true); }else{ anim.SetBool ("IsWalking", false); }
เป็นการบอกให้ animator ของเรา ไปตั้งค่า bool หรือ boolean ที่ชื่อ IsWalking ให้เป็น true และ false เช่นกัน ISJumping ก็คงไม่ยาก
ให้เราทดสอบโดยการ กดปุ่มบังคับทิศทางที่กำหนดไว้ หรือ Space Bar กระโดดดู
ต่อมาเรามาลองใช้ Parameter ประเภท Trigger กัน ไปที่ Animator ของใหม่อีกครั้งครับ สร้าง Parameter ชื่อ “Death” เป็นแบบ Trigger
สร้าง GameObject ขึ้นมาเป็น Cube ก็ได้วางไว้ในฉาก กำหนด Box Colider เป็น Trigger ไว้ครับ
หา Animation ประเภท Die หรือ ตายมาใส่ลงไปแล้วสร้าง Transition จาก run ไป die ครับ ตั้ง condition ให้เป็น Trigger = Death
เขียนคำสั่งนี้เพิ่มลงไปก่อนปิด Class Players ในไฟล์ players.cs
void OnTriggerEnter(Collider other) { if (other.gameObject.name == "Cube") { anim.SetTrigger("Death"); } }
เป็นคำสั่งว่าถ้าตัวละครของเรามี Collider ไปชนกับ Cube แล้วจะมีการเซ็ต Trigger ของ Animator ให้เป็น “Death” หรือตายครับ
ทดสอบวิ่งไปชนดู
ไม่รอด….
จะเห็นว่าบทเรียนนี้ไม่ยากอีกแล้ว และยังสามารถอธิบายอะไรได้เคลียร์ๆ มากเลยว่าการใช้ Animator แบบ Humanoid นั้นไม่ได้ซับซ้อนมากกว่า Legacy แม้แต่น้อย
สาย Javascript ก็นี่เลยครับ
#pragma strict private var anim: Animator; public var speed:float = 6.0F; public var jumpSpeed:float = 10.0F; public var gravity:float = 10.0F; private var moveDirection:Vector3 = Vector3.zero; public var Running:boolean = false; public var Jumping:boolean = false; public var rotationSpeed:float = 100.0F; function Start () { anim = GetComponent("Animator"); } function Update () { var controller:CharacterController = GetComponent("CharacterController"); if (controller.isGrounded) { moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); moveDirection = transform.TransformDirection(moveDirection); moveDirection *= speed; if (Input.GetButton("Jump")){ moveDirection.y = jumpSpeed; Jumping = true; Debug.Log ("Jump Status:"+Jumping); }else{ Jumping = false; } if (Input.GetKey((KeyCode.D)) || Input.GetKey("right") || Input.GetKey((KeyCode.A)) || Input.GetKey("left") || Input.GetKey((KeyCode.D)) || Input.GetKey("up") || Input.GetKey((KeyCode.W)) || Input.GetKey("down") || Input.GetKey((KeyCode.S)) ){ Running = true; }else{ Running = false; } if (Input.GetKey(KeyCode.S)){ } Debug.Log ("state:"+Running); if(Running == true){ //anim.SetTrigger("Running"); anim.SetBool ("IsWalking", true); }else{ anim.SetBool ("IsWalking", false); } if(Jumping == true){ //anim.SetTrigger("Running"); anim.SetBool ("IsJumping", true); }else{ anim.SetBool ("IsJumping", false); } } //Mouse movement var translation :float = Input.GetAxis("Vertical") * speed; var rotation :float = Input.GetAxis("Horizontal") * rotationSpeed; translation *= Time.deltaTime; rotation *= Time.deltaTime; transform.Translate(0, 0, translation); transform.Rotate(0, rotation, 0); moveDirection.y -= gravity * Time.deltaTime; controller.Move(moveDirection * Time.deltaTime); }
Source code ไม่ต้องมีหรอกมั้งไม่ได้ยากอะไร…
One Comment