FeaturedGame DevelopmentUnity 3D

เขียนเกม 3 มิติด้วย Unity การใช้ Animator Controller

บทเรียนตัวอย่างต่อเนื่องจากการ นำโมเดล 3 มิติของเราที่ Rigged แล้วมาใช้ในเกมโดยบทเรียนนี้จะเป็นการเขียนเกม 3 มิติด้วย Unity 3D การใช้ Animator Controller 

ก่อนอื่นหากไม่เคยรู้จัก Unity มาก่อนให้ไปศึกษาบทเรียนย้อนหลังที่นี่ครับ

https://www.daydev.com/tag/unity

บทเรียนนี้จะเป็นการต่อยอดจากบทเรียนก่อน นั่นคือ: “เขียนเกม Unity การทำ Humanoid ให้กับ โมเดลตัวละคร 3 มิติ” มาใช้ในการเขียนโปรแกรมควบคุมตัวละครครับ

จากบทเรียนก่อนหน้าเราจะได้ตัวละครของเราที่ใช้งาน Humanoid และ Animator ได้แล้ว

rigged-model-18

ให้เราไปหา Animation พื้นฐานของ Unity มาทดสอบการเคลื่อนไหวดูครับซึ่งเบื้องต้นผมไปดาวน์โหลด Template ตัว Complete Project มาก่อน

มีตัวฟรีใน Asset Store ครับ https://www.assetstore.unity3d.com/en/#!/content/5328

Screen Shot 2558-04-30 at 10.47.13 PM

ทำการ Login เข้า Asset Store แล้ว Download พร้อม Import มาใช้ในเกมได้เลยครับ

เบื้องต้นกลับไปที่ Scene View ก่อน แล้วทำการเพิ่ม Character Controller และ Capsule Collider ขึ้นมาพร้อมทำการ Trigger

Screen Shot 2558-04-30 at 10.50.14 PM

อย่าลืมใส่ Ridgid Body นะครับ

Screen Shot 2558-04-30 at 10.50.19 PM

ต่อจากนั้นให้เราสร้าง Animator Controller ขึ้นมา คลิกขวา Create จาก Project หรือจะเอาบทเรียนก่อนหน้ามาปรับใช้ก็ได้

Screen Shot 2558-04-30 at 10.19.27 PM

ไปที่ แท็บชื่อ “Parameters” ทำการเพิ่ม ตัวแปร Bool ซึ่งจะมีผลแค่ true และ false ตั้งชื่อสถานะ หรือ State parameters ว่า “IsWalking”

Screen Shot 2558-04-30 at 10.19.38 PM

ลาก Animation จาก Project ของเราไปวาง โดยเลือก idle และ run มาลองใช้

Screen Shot 2558-04-30 at 10.54.30 PM

ลากไปวางที่ Animator Controller ของเราครับ

Screen Shot 2558-04-30 at 10.20.03 PM

 

คลิกขวาเลือก “Make Transition” แล้วลากไปวางที่ Run ไปเชื่อมต่อกัน

Screen Shot 2558-04-30 at 10.20.14 PM

 

คลิกที่เส้นลูกศรให้เป็นสีน้ำเงินแล้ว เพิ่ม Conditions เลือก IsWalking เป็น true เพื่อเป็นการบอกว่า การเปลี่ยน state สถานะจากยืน idle ไปเป็นวิ่ง หรือ  Run นั้นจะเกิดก็ต่อเมื่อ IsWalking เป็น true

Screen Shot 2558-04-30 at 10.20.28 PMลากเส้น Make Transition จาก Run มา idle เหมือนกันเพิ่ม Conditions จาก IsWalking = true ให้เป็น false นั่นคือเมื่อไม่มีการวิ่งก็ให้กลับมาเป็นยืนนิ่งๆ แบบ Idle

Screen Shot 2558-04-30 at 10.29.05 PM

เพิ่ม  Parameter ใหม่เข้าไปคือ IsJumping เป็น Bool ครับ ไปหา Animation ตอนกระโดด มาวางแล้วทำ Transition แบบเดียวกับ idle -> run แต่เปลี่ยนเป็นจาก Run -> Jump แทน

Screen Shot 2558-04-30 at 10.58.36 PM

บันทึก Animator ตัวนี้ แล้วลากไปใส่ที่ตัว Player ของเรา

rigged-model-16

เขียนคำสั่ง 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 กระโดดดู

Running State

Jumping State

ต่อมาเรามาลองใช้ Parameter ประเภท Trigger กัน ไปที่ Animator ของใหม่อีกครั้งครับ สร้าง Parameter ชื่อ “Death” เป็นแบบ Trigger

Screen Shot 2558-04-30 at 11.06.30 PM

Screen Shot 2558-04-30 at 11.06.42 PM

 

สร้าง GameObject ขึ้นมาเป็น Cube ก็ได้วางไว้ในฉาก กำหนด Box Colider เป็น Trigger ไว้ครับ

Screen Shot 2558-04-30 at 11.11.48 PM

หา Animation ประเภท Die หรือ ตายมาใส่ลงไปแล้วสร้าง Transition จาก run ไป die ครับ ตั้ง condition ให้เป็น Trigger = Death

Screen Shot 2558-04-30 at 11.08.12 PM

 

Screen Shot 2558-04-30 at 11.08.43 PM

 

เขียนคำสั่งนี้เพิ่มลงไปก่อนปิด Class Players ในไฟล์ players.cs

void OnTriggerEnter(Collider other)
{
   if (other.gameObject.name == "Cube") {
	anim.SetTrigger("Death");
   }
}

เป็นคำสั่งว่าถ้าตัวละครของเรามี Collider ไปชนกับ Cube แล้วจะมีการเซ็ต Trigger ของ Animator ให้เป็น “Death” หรือตายครับ

ทดสอบวิ่งไปชนดู

Screen Shot 2558-04-30 at 11.18.19 PM

ไม่รอด….

จะเห็นว่าบทเรียนนี้ไม่ยากอีกแล้ว และยังสามารถอธิบายอะไรได้เคลียร์ๆ มากเลยว่าการใช้ 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 ไม่ต้องมีหรอกมั้งไม่ได้ยากอะไร…

Asst. Prof. Banyapon Poolsawas

อาจารย์ประจำสาขาวิชาการออกแบบเชิงโต้ตอบ และการพัฒนาเกม วิทยาลัยครีเอทีฟดีไซน์ & เอ็นเตอร์เทนเมนต์เทคโนโลยี มหาวิทยาลัยธุรกิจบัณฑิตย์ ผู้ก่อตั้ง บริษัท Daydev Co., Ltd, (เดย์เดฟ จำกัด)

Related Articles

Back to top button

Adblock Detected

เราตรวจพบว่าคุณใช้ Adblock บนบราวเซอร์ของคุณ,กรุณาปิดระบบ Adblock ก่อนเข้าอ่าน Content ของเรานะครับ, ถือว่าช่วยเหลือกัน