Virtual Reality

สร้างเกม Shooting VR ด้วย Oculus Integration กับ Unity บน Oculus Quest

การสร้างเกม VR ระบบปืนด้วย Unity เล่นผ่าน Oculus Quest พร้อมระบบ AI เบื้องต้น

อ้างอิงจากบทเรียน การสร้างระบบปืนใน VR ด้วย Oculus Integration และ Unity รอบนี้เราจะสร้างเกม VR ระบบปืนด้วย Unity เล่นผ่าน Oculus Quest พร้อมระบบ AI เบื้องต้น

ซึ่งในบทความก่อนหน้าจะมีการเกริ่นว่าเราจำเป็นต้องมี Assets ของ Oculus Integration และ Gun ทำระบบยิงปืนให้เรียบร้อยก่อน และจะต้องมีความรู้ด้าน C# ของ Unity บ้าง ทำการ New Project ใหม่เสีย

บทเรียนที่ควรไปทบทวนก่อนจะไปต่อคือ:

ในบทเรียนนี้เราจะใช้ Assets เพิ่มเติมมาแก้ไขงานเก่าของเรานั่นคือ:
https://assetstore.unity.com/packages/tools/integration/oculus-integration-82022

ทำการอัพเด็ตเป็นเวอร์ชันล่าสุดให้เรียบร้อยก่อนนะครับ ไม่งั้นมีปัญหา

ขั้นตอนการอัพเด็ตจะมีการ Upgrade ตัว Spatializer Plugins ของ Oculus Integration ที่ต้อง Restart Unity หนึ่งครั้งเมื่อ Upgrade ใช้เวลารอนิดหน่อย

หากสมบูรณ์แล้วก็จบครับ ทำงานได้ ต่อมาสิ่งที่ผมอยากจะเพิ่มเติมคือ Assets สำหรับสร้าง AI ศัตรูของเราก็ตัวนี้ละกัน ไปโหลดกันเลย

https://assetstore.unity.com/packages/3d/characters/humanoids/bodyguards-31711

ทำการสร้างฉากขึ้นมาง่ายๆ เพื่อทดสอบระบบ วางตัว OVRPlayerController ลงไป สร้าง Plane ขนาด 5,5,5 เข้าไปใน Scene ตามตัวอย่าง:

สร้าง Cube ขึ้นมาเป็นกำแพงกันให้เกิดความซับซ้อนในฉากของเกมเรา

ต่อมาให้เราไปแก้ไข Script ปืนของเราที่เดิมจะมี Code ของ GunInput.cs ตามนี้:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using OVR;

public class GunInput : MonoBehaviour
{
    public float fireRate = 0.4f;
	  private float nextFire = 0.0f;

    public GameObject bullet,gun;

    void Update()
    {
        if(OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger) && Time.time > nextFire){
            nextFire = Time.time + fireRate;
            Fire();
        }
    }

    public void Fire(){
        Instantiate(bullet, transform.position, transform.rotation);
    }
}

เราจะเพิ่มกราฟิก Muzzle ของปืนเข้าไปซึ่งจำเป็นต้องเป็น PNG แบบ Transparent ไว้ทำประกายไฟของกระบอกปืนเวลาเหนี่ยวไกปืน โดยไฟล์ PNG ที่ดาวน์โหลดมาก็คือ

ไฟล์ Muzzle Gun
ไฟล์ Muzzle Gun

ไปแก้ไขไฟล์ GunInput.cs โดยประกาศ Global Variable ไว้เรียกใช้ภาพ Muzzle เป็น GameObject ชื่อ muzzleGun ดังนี้:

public GameObject muzzleGun;

ดังนั้นเราต้อง Implement ตัว Method ของ Start() ใหม่ให้ซ่อนค่า muzzleGun ในตอนเริ่มต้น

void Start(){
        muzzleGun.SetActive(false);
}

ไปที่ Method ของ Update() ให้แก้ไขเพิ่มส่วนของการเปิดประกายไฟ แล้วทำการ StartCoroutine ส่ง Parameter ให้มีความหน่วง 0.16f เป็นแบบ float ไป

//Update New Muzzle
muzzleGun.SetActive(true);
StartCoroutine(MuzzleOff(0.16f));

เวลาวางใน Update() ให้วางตามรูปแบบนี้:

void Update()
{
        if(OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger) && Time.time > nextFire){
            nextFire = Time.time + fireRate;
            Fire();
            //Update New Muzzle
            muzzleGun.SetActive(true);
            StartCoroutine(MuzzleOff(0.16f));
        }
}

ไป Implement ส่วนของ IEnumerator MuzzleOff() ดังนี้:

IEnumerator MuzzleOff(float secondMuzzle) {
   yield return new WaitForSeconds(secondMuzzle);
   muzzleGun.SetActive(false);
}

ดังนั้นไฟล์ GunInput.cs จะเป็นแบบนี้:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using OVR;

public class GunInput : MonoBehaviour
{
    public float fireRate = 0.4f;
	private float nextFire = 0.0f;

    public GameObject bullet,gun;
    public GameObject muzzleGun;

    void Start(){
        muzzleGun.SetActive(false);
    }

    void Update()
    {
        if(OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger) && Time.time > nextFire){
            nextFire = Time.time + fireRate;
            Fire();
            //Update New Muzzle
            muzzleGun.SetActive(true);
            StartCoroutine(MuzzleOff(0.3f));
        }
    }

    public void Fire(){
        Instantiate(bullet, transform.position, transform.rotation);
    }

    IEnumerator MuzzleOff(float secondMuzzle) {
		yield return new WaitForSeconds(secondMuzzle);
		muzzleGun.SetActive(false);
	}
}

ไปที่ Unity Editor ไปสร้าง MuzzleFlash บน Hierarchy ไว้ตำแหน่งปากกระบอกปืน เป็น GameObject แล้วทำการลากไปที่ muzzleGun ของ GunInput บน Inspector ให้เรียบร้อยตามตัวอย่าง

ส่วน Gun นั้นให้ลาก GameObject Gun ของปืนเราบน Hierarchy ไปปล่อย ตามด้วย Prefabs ของ Bullet ไปวางที่ Bullet ใน Inspector ของ GunInput.cs ก็เป็นอันเสร็จทดสอบกันหน่อย:

คราวนี้ก็มาทำ AI กันดีกว่าหลักการทำ AI นั้นจะง่ายหน่อยตรงที่เราสามารถทำตามบทเรียนนี้:

นำ Prefabs จาก Assets ของ BodyGuards มาวางใน Scene ตั้งค่าเป็น Rig->Humanoid ให้เรียบร้อย เพื่อที่เราจะทำ Animator Controller สำหรับท่าทางการวิ่ง และท่าทางการตาย

เอาอาวุธไปใส่ให้กับมันหน่อย หลังจากนั้นไปหา แอนิเมชันใน Mixamo.com มาใช้งาน

เวลาดาวน์โหลดให้เลือกเป็น FBX สำหรับ unity และ เลือก Skin เป็น WithOut Skin เพราะเรามี Model ของเราแล้ว ไม่ต้องเอาของ Mixamo.com มาเอามาแค่ Motion เท่านั้น

สร้าง Animator Controller ขึ้นมาชื่อ Enemy ทำการออกแบบ Trigger มี Parameter ชื่อว่า death แล้วนำแอนิเมชันมาออกแบบดังนี้ (ศึกษาได้ที่: เขียนเกม 3 มิติด้วย Unity การใช้ Animator Controller)

สร้าง Parameters เป็น Trigger ว่า “death”

นำ Animation ของ Run Forward ไปวางใน Animator Controller หลังจากนั้นลาก Falling Back Death หรือท่าตายไปวางเช่นกัน คลิกขวาจากท่าเดินเลือก Make Transition ใส่ Conditions เป็น death

ไปที่ Windows -> AI -> Navigation

คลิกที่พื้นของฉากเรา แล้วไปที่ Tab ข้างๆ Inspector มันจะให้เราเลือกเป็น Navigation static หลังจากนั้นถ้ามีเครื่องหมายถูกแล้วไปที่ Tab ชื่อ Bake กด Bake เพื่อให้ AI เรารู้จักพื้นของมัน ซึ่งจะเป็นสีฟ้า

ทำการคลิกที่ AI ของเราใน Hierarchy ใส่ Capsule Collider ตั้งค่า is Trigger เป็น จริงไว้ และเพิ่ม Navigation เลือก Add New Component เลือก Navmesh Agent ให้เรียบร้อยตั้งค่าให้ดี

ตั้งค่าของ Nav Mesh Agent ใหม่ให้ Speed เป็น 3.5 หลังจากนั้นระยะการหยุดของมันต้องการเท่าไรก็ใส่เข้าไปในตัวอย่างผมใส่ 0 ใน Stopping Distance

ส่วนของลังประกอบฉากเป็นไปได้ให้คลิกเลือกทั้งหมด แล้วตั้งค่าเป็น Nav Mesh Obtacles เพื่อสร้างเป็นสิ่งกีดขวางให้ AI ของเราต้องคำนวณการเดินอ้อม

ต่อมาคือการสร้าง C# ของ Enemy.cs ละให้เราใส่ Code นี้ลงไป

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Enemy : MonoBehaviour {
    [Tooltip("ลากสิ่งที่ต้องการให้ AI เดินไปหามาไว้ที่นี่")]
    Transform goalObject;
    [Tooltip("พิมพ์ชื่อ Tag ที่เรากำหนดเข้าไป เช่น ลูกกระสุน")]
    public string tagObject;
    Animator animator;
    UnityEngine.AI.NavMeshAgent navAgent;
 
    void Start()
    {
        //บังคับให้ AI ประมวลผลเดินไปยังจุดที่เรากำหนด
        animator = GetComponent<Animator>();
        navAgent = GetComponent<UnityEngine.AI.NavMeshAgent>();
        if (goalObject == null)
            goalObject = GameObject.FindGameObjectWithTag("Player").transform;
        
    }
 
    void Update(){
        navAgent.destination = goalObject.position;
    }
 
 
    void OnTriggerEnter(Collider collision)
    {
        if (collision.gameObject.tag == tagObject)
        {
            //แสดงท่าทางตอนล้ม
            animator.SetTrigger("death");
            Destroy(collision.gameObject);
            navAgent = GetComponent<UnityEngine.AI.NavMeshAgent>();
            navAgent.isStopped = true;
            StartCoroutine(clearObject());
        }
    }
 
    IEnumerator clearObject() {
        //หนวง 2 วินาที แล้วค่อยทำให้หายไป
        yield return new WaitForSeconds(2f);
        Destroy(this.gameObject);
    }
 
}

ให้ navAgent ไปเรียก Component ของ UnityEngine.AI.NavMeshAgent

GetComponent<UnityEngine.AI.NavMeshAgent>();

ไปที่ Prefabs ไปเพิ่ม Tag ใหม่ให้กับ Bullet นั่นคือ Tag ที่ชื่อ bullet ตัวเล็กหมด แล้วค่อยไปพิมพ์คำว่า bullet ใน tagObject ของ Enemy ใน Inspector ของตัว AI ที่เราสร้างเพื่อให้มันรู้ว่าถ้าโดน GameObject ที่มี tag ว่า bullet มันต้องแสดงท่าการตาย และ หยุดการเดินด้วยคำสั่ง:

navAgent.isStopped = true;

สร้าง tag ให้กระสุนก่อนว่า bullet

คลิก Add Tag เพิ่มเข้าไปเป็น bullet

สำหรับ Player เช่นกันเราต้องใส่ tag ให้มันว่า “Player” ด้วย

เพราะ AI มันจะค้นหา Tranform ที่มี tag ว่า Player เมื่อมันเจอมันจะวิ่งใส่ทันที:

if (goalObject == null) 
goalObject = GameObject.FindGameObjectWithTag("Player").transform;

ตั้งค่า is Trigger ให้กับ bullet ของเราผ่าน Prefabs แล้วทดสอบระบบว่า AI เดินมาให้เรายิงได้หรือยัง และเวลายิงประกายไฟทำงานได้จริงไหม

เป็นไงครับระบบการสร้างเกม Shooting บน VR แบบม้วนเดียวจบเช่นเคยของ Daydev ต่อไปเราจะเห็นคนไทยทำเกม VR เยอะขึ้นครับ เพราะ Headset เดี๋ยวนี้มันราคาไม่แพงมากแล้วล่ะ

ที่เหลือก็คือ ไอเดีย ล่ะมั้งที่เราต้องคิดราคาแพงหน่อยว่ามันจะสนุกยังไง

Asst. Prof. Banyapon Poolsawas

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

Related Articles

Back to top button

Adblock Detected

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