Game DevelopmentUnity 3D

สร้างเกม Unity 3D แนว Space Shooting ตอนที่ 1

การพัฒนาเกมแนวยานอวกาศ หรือ Space Shooting นั้นยังถือว่าเป็นเกมที่ได้รับความนิยมตลอดเวลา เพราะการควบคุมที่แสนง่าย และความเพลิดเพลินในการเล่นกับระบบที่เป็นรูปแบบ (Pattern) ที่ผู้เล่นสามารถจับทางได้แล้วก็จะเกิดความสนุก และเป็นการฝึกฝนไปในตัว ตัวอย่างที่ได้รับความนิยมมากในยุคแรก และ นับว่าเป็นเกมที่ได้ชื่อว่าเป็น เกมยานอวกาศระดับตำนาน ก็ได้แก่ Starfox เป็นต้น

Star Fox เป็นเกมยิงยานอวกาศที่สร้างขึ้นโดย Nintendo เกมดังกล่าวเป็นทีมการต่อสู้ของสัตว์มนุษย์ที่เรียกว่า Star Fox นำโดยหัวหน้าผู้ให้การสนับสนุน Fox McCloud การเล่นเกมเกี่ยวข้องกับการผจญภัยรอบ ๆ ระบบดาวเคราะห์ Lylat ใน เครื่องบินรบ “Awing” ระบบมีการเอื้อไปถึงการควบคุมยานพาหนะอื่น และมีโหมดเดินเท้าในฉากด้วยในภาคหลังๆ

สำหรับนักพัฒนาเกมแล้ว เกมแนว Space Shooting นับว่าเป็นจุดเริ่มต้นของการพัฒนาเกมสาย Programming ซึ่งเป็นตัวอย่างที่เหมาะที่สุดสำหรับการออกแบบ และสร้างเกมที่ประกอบไปด้วย การควบคุมตัวละครด้วยแป้นคีย์บอร์ด ปุ่มลูกศร การศึกษาระบบการตรวจจับการชนกันของวัตถุ หรือ Collision Detection ซึ่งเป็นหัวใจของการทำเกมก็ว่าได้ การศึกษาระบบการ เคลื่อนไหวของศัตรูแบบทิศทางเดียว การศึกษาระบบการ ยิงกระสุน โดยการ Spawn Prefabs การศึกษาระบบการจัดเก็บคะแนน ภายในเกม ทั้งหมดนี้จะถูกนะเสนอผ่าน Workshop การพัฒนาเกมยานอวกาศในตัวอย่างนี้

เริ่มต้นพัฒนาเกม

เปิด Unity Hub ขึ้นมาหลังจากนั้นทําการ New Project เป็น 3D Template เพื่อพร้อมใช้งาน

ถ้าหากว่าไม่มีอะไรผิดพลาดอยากให้ทําการออกแบบยานอวกาศของเราโดยการเข้าไปดาวน์โหลด Assets เบื้องต้นที่:

เมนู Windows -> Asset Store

หลังจาก New Project ขึ้นมาแล้วให้ไปที่ Hierarchy คลิกขวาเพื่อสร้าง Cubeขึ้นมาตัวหนึ่ง กําหนดค่า Inspector เป็น Rotation ที่ 0, 0, 0 และ Scale เป็น 1,1,1 เปลี่ยนชื่อเป็น Player

สังเกตตําแหน่งลูกศรใน Scene View ลูกศรสีนํ้าเงินคือแกน Z ถ้าทําความเข้าใจคือทิศทางที่ตัวละครเรา
กําลังจะพุ่งออกไป ให้เราเพิ่ม Add Component ใหม่เลือก Character Controller ในตัว Player เพิ่มขึ้นมา
สร้างการควบคุมให้กับยานอวกาศ สิ่งที่เราต้องเพิ่มเข้าไปคือคลิกที่ Player แล้วไปกดปุ่ม Add
Component ใน Inspector Window หาหมวดหมู่ Physics แล้วเลือก Character Controller

ทําการตั้งค่า Character Controller ปรับส่วน Radius และ Height ให้ครอบคลุมตัวยานอวกาศ ในตัวอย่างคือ
Radius เป็น 4 และ Height เป็น 3 จะได้เส้นสีเขียวครอบคลุมตัวยานนั่นคือการรองรับการควบคุมตัวละคร
แล้ว หลังจากนั้นเลือก Physics เพิ่ม RigidBody เพิ่มเข้าไปให้กับ Player เราต้องทําให้ GameObject ของ
Player เป็นฟิ สิกส์ให้ได้ก่อน ดังนั้นสิ่งที่ต้องเพิ่ม Add Component เข้าไปใน Player ของเราคือ

Physics -> Rigid Body เพื่อให้วัตถุมีค่าสอดคล้องกับแรงดึงดูดโลก (gravity) และชนกับวัตถุอื่นได้ และเพิ่ม
Physics -> Collider เข้าไปเพื่อให้ Player ของเรามีการกําหนดส่วนของการตรวจสอบการชนกัน

ทําการสร้าง Plane ขึ้นมาบน Hierarchy โดยการคลิกเมาส์ขวา เลือก 3D Object -> Plane เสร็จแล้วตั้งค่า Scale ของ Plane เป็น 10,10,10 เพื่อให้ใหญ่ครอบคลุมฉากของเรา

ขั้นตอนต่อไป ตัว Player ของเราต้องใส่ Box Collider เข้าไป แล้วต้องกําหนด ขอบเขตของการชนให้กับ Player ของเราว่าขอบเขตนั้นมีขนาดไหน โดยการคลิกที่ปุ่ ม Edit Collider หลังจากนั้นให้ปรับขนาดของ Collider ใน Scene View โดยการคลิกที่จุด เขียวขนาดเล็ก ค้างไว้แล้วเลื่อนไปมาเพื่อสร้างขอบเขตการชน เมื่อเรากําหนด ขอบเขตการตรวจจับการชนด้วย

Physics -> Box Collider แล้ว ให้เราสร้าง Trigger Collider ให้กับยานของเราโดยใช้การคัดลอดคุณสมบัติของ Box Collider ตัวเดิม โดยการคลิกขวาที่ ไอคอน จุดสามจุด มุมขวา แล้วเลือก Copy Component

การ Paste Component นั้นสามารถทําได้โดยคลิกที่ไอคอนรูปจุดสามจุด ตําแหน่งเดิมแล้วคลิกขวาเลือก
Paste Component As New เราจะมี Box Collider ปรากฏขึ้นบน Inspector Window 2 ตัว

ใน Box Collider ตัวที่ 2 ให้คลิกสร้างเครื่องหมายถูกที่ Is Trigger ก็เป็นอันเรียบร้อย นั่นหมายความว่าตัว ละครของเราสามารถชนกับศัตรูแล้วเกิดเงื่อนไขบางอย่างได้แล้ว

สร้าง Script ใหม่ขึ้นมาชื่อว่า Player หลังจากนั้นให้ประกาศตัวแปรตามนี้เป็น Global Variable:

CharacterController characterController;
public float speed = 6.0f;
public float jumpSpeed = 8.0f;
public float gravity = 20.0f;
private Vector3 moveDirection = Vector3.zero;

ประกาศตัวแปร speed คือความเร็ว jumpSpeed คือความเร่ง Gravity คือ แรงโน้มถ่วง ทั้งหมดถูกประกาศเป็น public แบบสาธารณะ และ Data Type เป็น Float หรือจุดทศนิยม

ตัวแปร characterController สร้างขึ้นมาเพื่อทําการรับค่า Component ของ CharacterController ที่เราสร้างขึ้นใน Inspector Window ของ Unity Editor ส่วนมากแล้วการตั้งชื่อตัวแปรเหล่านี้ มักจะตั้งชื่อเดียวกันแต่ตัวแปรมักจะขึ้นต้นด้วยตัวอักษรตัวเล็ก

CharacterController characterController;

ตัวแปร moveDirection คือการรับค่า Vector3 หรือทิศทางที่จะเปลี่ยนตําแหน่งไปมาทั้ง สามแกน คือ แกน x แนวระนาบ แกน y แนบดิ่ง และ แกน z แนวที่สามที่เพิ่มมาระดับเชิงลึกของมุมมอง เช่นไปหน้าหรือถอย หลัง ในตัวอย่างกําหนดค่าเริ่มต้นของ Vector3 เป็น 0 ทั้งหมด

เราจะทําการตั้งค่า Initiate ค่าเริ่มต้นในฟังก์ชัน Start() ให้ characterController ไปรับค่า Component ชื่อ เดียวกันในฟังก์ชันนี้ ดังนั้นคําสั่งที่ต้องเพิ่มเข้าไปคือ:

characterController = GetComponent<CharacterController>();

คําสั่งนี้ต้องนําไปประกาศที่ฟังก์ชัน Start() ตามรูปแบบนี้

void Start()
{
    characterController = GetComponent<CharacterController>();
}

สําหรับการทํางานเราต้องรับค่าแป้นพิมพ์ ทั้ง ซ้าย ขวา บน ล่าง เพื่อ ควบคุมยานอวกาศของเรา ดังนั้นเรา
ต้องกําหนดค่าดังนี้ในฟังก์ชัน Update()

void Update()
{
     moveDirection = new
     Vector3(Input.GetAxis("Horizontal"),Input.GetAxis("Vertical"), 0.0f);
     moveDirection *= speed;
     if (Input.GetButton("Jump"))
     {
       moveDirection.y = jumpSpeed;
     }
     moveDirection.y -= gravity * Time.deltaTime;
     characterController.Move(moveDirection * Time.deltaTime);
}

หากทําการทดสอบให้เราบันทึกไฟล์แล้ว กด play ที่ Editor เราจะเห็นว่าเราได้ควบคุมยานอวกาศของเรา ได้ผ่านแป้นลูกศรบนคีย์บอร์ดของเราได้แล้ว และเมื่อเราไม่กดอะไร ยานจะลอยตัวลงไปยังตําแหน่งพื้นอัตโนมัติ

ขั้นตอนต่อไปให้สร้าง Material ใหม่ขึ้นมาโดยการคลิกขวาที่ Project Windows

ทําการเปลี่ยนสี Material ชื่อ Player ใน Inspector ใหม่เป็นสีอื่นๆ ตามที่เราต้องการ

ลากตัว Material จาก Project Windows ไปวางทับกับ Player บน Hierarchy จะเห็นว่า Player ของเรามี
การเคลื่อนที่ได้แล้ว

ทดสอบเกมของเราโดยการควบคุมการบังคับด้วยแป้นพิมพ์

ไปที่ Component ของ RigidBody บน Inspector ให้ทําการปรับตั้งค่าตามตัวอย่าง นั่นคือการ Freeze การหมุนไม่ให้เป็นไปตามหลักฟิ สิกส์ เนื่องจากตัวอย่างนี้ต้องการการหมุน และเคลื่อนที่แบบ คงที่ Euclidian และ Linear

ทําการ Freeze Rotation แกน X,Y,Z เพื่อทําให้วัตถุที่ควบคุม คงตัวอย่างเสมอภาคกัน การเคลื่อนที่ของ Player ที่คงที่ และไม่มีการหมุนหรือพลิก

การสร้างระบบกระสุน

เราจะเพิ่มระบบการยิงกระสุน และการทํา Material ของพื้นให้มีการเคลื่อนที่เพื่อสร้างประสบการณ์ของผู้ เล่นให้เหมือนยานกําลังเคลื่อนที่ไป ให้ทําการสร้าง Cube ขึ้นมาด้านหน้าของ Player ตั้งชื่อว่า Gun ซึ่งการ สร้างขึ้นมานั้นต้องมีทิศทางของลูกศรสีนํ้าเงินทิศทางเดียวกันกับ Player ของเรา เมื่อสร้างแล้วจึงค่อยย้ายเจ้า GameObject ชื่อ Gun ไปเป็น Child ของ Player

เปลี่ยนชื่อ Cube เป็น Gun แล้วลากไปเป็น Child ของ Player บน Hierarchy สร้าง Script ขึ้นมาใหม่ใน
GameObject ชื่อ Gun เพื่อเรียกคําสั่งในการรับค่าการคลิกเมาส์ซ้าย แล้วปล่อยกระสุนออกไป ตั้งค่า Is
Trigger ใน Box Collider ให้เป็น True โดยการเลือกเครื่องหมายถูก

สร้าง Script ขึ้นมาใหม่ใน GameObject ชื่อ Gun เพื่อเรียกคําสั่งในการรับค่าการคลิกเมาส์ซ้าย แล้ว ปล่อยกระสุนออกไป

ดังนั้นคลิกที่ Gun แล้วกดปุ่ ม Add Component เลือก New Script ตั้งชื่อ Gun เราจะได้ไฟล์ Gun.cs
เขียนคําสั่งต่อไปนี้ ประกาศตัวแปร Global Variable ขึ้นมา

public float fireRate = 0.4f;
private float nextFire = 0.0f;
public GameObject bullet;

Workflow หลักการทํางาน คือ เราต้องการให้คลิกซ้าย แล้วเราจะ Clone กระสุนออกมาจากปืน ซึ่งเราต้อง
เตรียม GameObject สําหรับโคลนกระสุนขึ้นมาชื่อว่า bullet ส่วนการยิงนั้นจําเป็นต้องมีการกําหนด fireRate ประมาณ 0.4 วินาที เพื่อที่จะเป็นการกําหนดความถี่ในการปล่อยกระสุน หาด fireRate เป็น 0 จะกดเมาส์ค้างปล่อยกระสุนได้ตลอดเกมจะไม่ท้าทาย ตัวแปร fireRate จะใช้ทํางานร่วมกับ nextFire ในการกําหนดการปล่อยกระสุนครั้งต่อไป ดังนั้นเราไปรับค่ากรคลิกเมาส์ซ้ายที่ฟังก์ชัน Update() ดังนี้:

void Update()
{
     if (Input.GetMouseButton(0) && Time.time > nextFire)
     {
       nextFire = Time.time + fireRate;
       Fire();
     }
}

หลักการทํางานคือเมื่อคลิกแล้วจะไม่เกิดคําสั่งถ้าเวลา Clock ในเกม Time.time มากกว่า nextFire แต่ถ้าเข้าเงื่อนไขถูกหลัง nextFire = Time.time + fireRate แล้ว ค่อยไปเรียกฟังก์ชันที่เราสร้างเองขึ้นมาในตัวอย่างตั้งชื่อฟังก์ชันนี้ว่า Fire()

ดังนั้นเราต้องไป Implement หรือสร้าง ฟังก์ชันใหม่ชื่อ Fire() หลังจบฟังก์ชัน Update() ภายใน Class ของ Gun ซึ่งการประกาศ ฟังก์ชันใหม่เราจะเขียนดังนี้:

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

คําสั่งของ Class Gun ของเราจะเป็นดังนี้:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gun : MonoBehaviour
{
     public float fireRate = 0.4f;
     private float nextFire = 0.0f;
     public GameObject bullet;
     void Update()
     {
      if (Input.GetMouseButton(0) && Time.time > nextFire)
      {
       nextFire = Time.time + fireRate;
       Fire();
      }
     }
     public void Fire()
     {
      Instantiate(bullet, transform.position, transform.rotation);
     }
}

โดยคําสั่งของฟังก์ชัน Fire() นั้นก็คือเมื่อเมารับค่าการคลิกเมาส์ซ้าย ฟังก์ชันนี้จะทํางานคําสั่งการ Spawn การทําซํ้าเรียก GameObject ที่ชื่อ Bullet มาสร้างใหม่ในตําแหน่งของ Gun โดยอ้างอิงตําแหน่ง transform.position นั่นคือไม่ว่าจะอยู่ตําแหน่งไหนบนหน้าจอ กระสุนจะถูกปล่อยจากที่นั่น และ หมุนไป ทิศทางตาม transform.rotation

ทีนี้เราต้องมาสร้าง กระสุนของยานอวกาศของเราก่อน ซึ่งถ้าวิเคราะห์ตาม Workflow เราจะต้องรู้ดีกว่ากระสุนต้องพุ่งไปทิศทางข้างหน้า แต่ถ้าเรา Optimized หรือปรับประสิทธิภาพเกมไม่ดีนัก กระสุนจํานวนมากจะทําให้เกมทํางานช้าลงเพราะไม่มีการล้างค่าหรือทําลายทิ้ง ดังนั้นเราต้องสร้างฟังก์ชันในการนับเวลาถอยหลัง ภายหลังจากกระสุนถูกปล่อยออกไป ให้ทําลายตัวเองด้วย

สร้างกระสุนโดยการคลิกขวาที่ Hierarchy เลือก 3D Object เลือก Sphere หลังจากนั้นให้เพิ่ม Physics ->RigidBody โดยให้เอาเครื่องหมายถูกบน Gravity ออกไป และเพิ่มเครื่องหมายถูกที่ Is Trigger ใน Sphere Collider บน Inspector Window

ทําการเปลี่ยนชื่อ Sphere บน Hierarchy แก้ไขเป็นชื่อ bullet เพื่อที่เราจะนํามาใช้เป็นกระสุนในการบรรจุ แล้วปล่อยออกจาก Gun

เมื่อเสร็จแล้วให้เราสร้าง Script ใหม่ใน bullet ตั้งชื่อ Script ว่า Bullet เราจะได้ไฟล์ชื่อว่า Bullet.cs ขึ้นมา
เขียนคําสั่งเพิ่มเติมดังนี้เริ่มต้นคือการประกาศ Global Variable คือ

public float Speed = 0.7f;
public float SecondsUntilDestroy = 1.2f;
float startTime;

ตัวแปร Speed คือความเร็วของกระสุน เป็น Data Type ประเภทจุดทศนิยม เช่นกัน SecondUntilDestroy คือค่าวินาทีที่เราจะให้กระสุนปรากฏในเกม เมื่อครบเวลาแล้วให้ทําลายทิ้ง และตั้งค่าการนับเวลากระสุน ปรากฏผ่านตัวแปร startTime ดังนั้นเราไปเริ่มนับเวลากันในฟังก์ชัน Start() ดังนี้:

void Start()
{
     startTime = Time.time;
}

ดังนั้นขั้นตอนต่อไปคือการเพิ่มความเร็วพุ่งไปข้างหน้าของกระสุน และนับเวลาการปรากฏในเกมของ
กระสุนถ้าเกินเวลาให้ทําลายทิ้งให้เราไป Implement ส่วนของฟังก์ชัน Update() ดังนี้:

void Update()
{
     this.gameObject.transform.position += Speed * this.gameObject.transform.forward;
     if (Time.time - startTime >= SecondsUntilDestroy)
      {
        Destroy(this.gameObject);
      }
}

คําสั่งในการพุ่งไปข้างหน้าคือ transform.postition ให้เราเพิ่มตามเวลาและ Speed ที่เรากําหนด และเขียนคําสั่ง เช็คว่าถ้าเราเริ่มนับเวลาในเกม แล้วเกินเวลาที่กําหนดในตัวแปร SecondUntilDestroy ให้เราทําลายกระสุนทิ้งจากเกมไปเลย

เพิ่ม Workflow ของเกมอีกสักหน่อย กระสุนของเราถ้ามันชนศัตรูเมื่อไรให้มันทําลายทิ้งเช่นกัน เรามาดําสั่งสําหรับตรวจสอบกรชนกันของวัตถุกัน นั่นคือฟังก์ชัน OnTriggerEnter()

การทํางานเบื้องต้นคือ เราจะกําหนดว่า GameObject ที่เป็นยานของศัตรูนั้นเราจะใส่ tag ให้กับมันคือ “Enemy” ซึ่งเราสามารถกําหนดได้ ดังนั้นเรามาดูการเพิ่มฟังก์ชันนี้ว่ามันทํางานยังไง เพิ่มคําสั่งนี้ใน Class
ของ Bullet

void OnTriggerEnter(Collider collision)
{
    if (collision.gameObject.tag == "Enemy")
    {
     Destroy(this.gameObject);
    }
}

ตัวแปร collision นั้นคือวัตถุอื่นที่พุ่งเข้ามาชน หรือ วัตถุของเราพุ่งเข้าไปหาแล้วเกิดการชน ให้นํามาเข้าเงื่อนไขว่าถ้าวัตถุที่กระสุนชนนั้นมี tag ชื่อว่า “Enemy” ให้ทําลายตัวเองทิ้ง ดังนั้นภาพรวม Class ของ Bullet จะเป็นดังนี้:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
   public float Speed = 0.7f;
   public float SecondsUntilDestroy = 1.2f;
   float startTime;
   void Start()
   {
     startTime = Time.time;
   }
   void Update()
   {
    this.gameObject.transform.position += Speed *this.gameObject.transform.forward;
    if (Time.time - startTime >= SecondsUntilDestroy)
    {
     Destroy(this.gameObject);
    }
   }
   void OnTriggerEnter(Collider collision)
   {
    if (collision.gameObject.tag == "Enemy")
    {
      Destroy(this.gameObject);
    }
   }
}

ให้ทําการบันทึก Script Bullet แล้วกลับมาที่ Unity Editor ให้เราไปที่ Project Window ให้สร้าง โฟลเดอร์ ใหม่ขึ้นมาชื่อว่า “Prefabs” ทําหน้าที่เก็บ Prefabricated หรือแปลตามตัวว่างานทํามือ หรือสร้างขึ้นมาเอง หลักการสร้าง Prefabs คือคลิกวัตถุทีต้องการสร้างเป็น Prefab บน Hierarchy ลากไปวางในโฟลเดอร์ “Prefabs” บน Project Window ก็เป็นอันเสร็จ

ลาก GameObject ที่เราต้องการสร้างเป็น Prefab จาก Hierarchy ไปปล่อยที่ โฟลเดอร์ “Prefabs” ระบบจะสร้างแบบจําลองให้เราอัตโนมัติ เมื่อเราสร้าง Prefab แล้วเราสามารถลบวัตถุต้นแบบบน Hierarchy ได้ ทีนี้เรามาตั้งค่าปืนกระสุนกัน ทํา การลบ Bullet บน Hierarchy ออกได้ทันทีคลิกที่ Gun บน Hierarchy แล้วสังเกตที่ Inspector Window จะเห็นการเรียกหา Game Object อยู่ตรง Bullet ให้เราลากกระสุน bullet ที่เราสร้างเป็น Prefab จาก โฟลเดอร์ “Prefabs” ไปวางที่นั่น

กด Play แล้วทําการทดสอบ การยิงของยานอวกาศของเรา โดยการคลิกเมาส์ซ้าย แล้วดูการปล่อยกระสุนกระสุนถูกยิงออกไป เมื่อคลิกเมาส์ซ้าย

ขั้นตอนต่อไปเราจะไปหา ภาพจาก Google Image ค้นหาคําว่า “Water Texture Seamless” แล้วเลือก
ภาพของพื้นนํ้ามาสักรูป บันทึกและนําเข้าไปยัง Project Window

การนําเข้าไฟล์รูปภาพคือการลากวางไปยัง Project Window ขั้นตอนต่อมาเราจะสร้าง Material ให้กับพื้นดินที่เราวางลงไป ให้เราคลิกขวาที่ Project Window เลือก Create -> Material ให้เราตั้งชื่อ Material นี้ว่า Water แล้วลาก Material ชื่อ Water นี้จาก Project Window ไปวางใน Plane บน Scene View

ลาก Material ชื่อ Water ไปปล่อยใน Plane บน Scene View ขั้นตอนต่อไปคือการนํารูปภาพไปใส่ใน Material ทําการลากรูปภาพ Water.png ไปปล่อยใน ช่อง Albedo ใน Material “Water” เราจะเห็นการเปลี่ยนแปลงของฉากใน Scene View

คลิกที่ Plane บน Hierarchy ให้เราเพิ่ม Script ขึ้นมาตั้งชื่อว่า WaterGround เขียนคําสั่งต่อไปนี้ประกาศตัวแปร Global Variable ตั้งชื่อว่า speed

public float speed = 0.5f;

เราจะทํางานผ่านการควบคุม Material ให้มีการหมุนเคลื่อนที่ในตัวเอง โดยเราต้องไปเขียนควบคุมการ
เคลื่อนที่ตาม speed ที่กําหนดในฟังก์ชัน Update() ดังนี้:

void Update()
{
   float offset = Time.time * speed;
   GetComponent<Renderer>().material.mainTextureOffset = new Vector2(0, -offset);
}

ดังนั้น Classของ WaterGround จะเป็นดังนี้:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WaterGround : MonoBehaviour
{
   public float speed = 0.5f;
   void Update()
   {
    float offset = Time.time * speed;
    GetComponent<Renderer>().material.mainTextureOffset = new Vector2(0, -offset);
   }
}

บันทึก และทดสอบการทํางานโดยกดปุ่ ม Play เราจะพบว่า ยานอวกาศของเราพุ่งไปข้างหน้าแล้ว
เหมือนกับตัวละคร Player ของเราสามารถลอยพุ่งไปข้างหน้าของฉากในเกม

ฉากพื้นนํ้ามีการเคลื่อนที่ ทําให้ดูเหมือนยานอวกาศของเรากําลังเดินหน้าไป

การสร้างศัตรู และระบบสุ่มตําแหน่ง
จากตัวอย่างบทเรียนที่แล้ว เราจะมียานอวกาศที่พร้อมโจมตีและฉากของการเคลื่อนที่ดูสมจริง พร้อมกระสุนที่บรรจุใหม่ และปล่อยออกไปต้องมีการตรวจสอบการชนเป็นที่เรียบร้อย ในบทเรียนนี้เราจะมาเริ่มต้นที่การสร้างศัตรูในฉากของเราพร้อมกับระบบสุ่มตําแหน่งของศัตรูเพื่อที่เกมจะได้มีความท้าทาย
เพิ่มขึ้น

ให้เราสร้าง ศัตรูของเราขึ้นมาโดยการสร้าง Create Empty ขึ้นมา หลังจากนั้นไปกําหนดค่า Rotation ใน
Inspector ส่วนของ Y เป็น 180 เปลี่ยนชื่อเป็น Spawn

เมื่อสร้างเรียบร้อยแล้วให้ทําการลากตําแหน่งของเจ้า Spawn ไปให้ไกล สุดฉากอีกด้านของตัว Player เพื่อ
เป็นจุดปล่อย Spawn บางสิ่งเข้าหา Player

ตั้งค่า Rotation แกน Y เป็น 180 แล้วเลื่อนไปอีกด้านของ Player ให้ไกลประมาณหนึ่ง

สร้าง Material ขึ้นมาอีกลูกหนึ่งโดยกําหนดสีให้แตกต่างจาก Player แล้วทําการเปลี่ยนชื่อว่า Enemy เพื่อ
เป็นการกําหนดสีของ Enemy ที่จะพุ่งเข้ามาหา Player

ให้เราสร้าง ศัตรูของเราขึ้นมาโดยการสร้าง 3D Object -> Cube ขึ้นมา หลังจากนั้นไปกําหนดค่า Rotation
ใน Inspector ส่วนของ Y เป็น 180 เหมือน GameObject ตัวก่อนหน้า ทําการเปลี่ยนชื่อเป็น Enemy แล้ว
ลากตําแหน่งของเจ้า Enemy ไปให้ไกล สุดฉากอีกด้านของตัว Player

สร้าง Cubeใหม่ชื่อว่า Enemy วางในตําแหน่งห่างจาก Player หัก Rotation Y เป็น 180

หลังจากสร้าง Cube เปลี่ยนชื่อ Enemy แล้วให้ทําการเพิ่ม Tag เป็น Enemy หากไม่มีให้กด Add Tag เข้า
ไปได้ด้วยตนเอง

คลิกที่ เครื่องหมาย + แล้วตั้งชื่อ New Tag Name เป็น Enemy แล้วกด Save หลังจากนั้นออกไปคลิกที่ Enemy ใน Hierarchy

ใน Tag จะมี Drop Down เพิ่มมาคือ Enemy ที่เราเพิ่มเข้าไปให้คลิกเลือก

ทําการสร้าง Box Collider และ RigidBody ให้กับยานศัตรูตามตัวอย่างรูปภาพของ Component ด้านล่าง

ข้อที่ควรพิจารณาคือการกําหนด Collider ผ่าน Edit Collider ในส่วนของ is Trigger มีความสําคัญต่อการ ที่ลูกกระสุนจะพุ่งไปโดนยานอวกาศมาก และ มีความสําคัญเวลาที่ยานอวกาศของ Player จะพุ่งไปโดย ยานของศัตรูเช่นกัน ดังนั้นการกําหนด Collider จึงขึ้นอยู่ในกับ รูปทรงแบบจําลอง 3 มิติที่เรานํามาใช้ใน Unity Editor

ขั้นตอนต่อมาให้เราสร้าง Script ขึ้นมาชื่อว่า Enemy ประกาศ Global Variable ดังนี้:

public float objectSpeed = 0.5f;

หลังจากนั้นให้เราไป Implement ส่วนของฟังก์ชัน Update() ดังนี้:

void Update(){
   transform.Translate(0, 0, objectSpeed);
}

เพิ่มคําสั่งการตรวจจับการชน ผ่าน TriggerEnter เข้าไปสําหรับตรวจว่า กระสุนถูกพุ่งมาชน ในขั้นตอนนี้จะ แสดงตัวอย่างการตรวจสอบโดยอ้าง Name ของ GameObject แทนการใช้ Tag

void OnTriggerEnter(Collider collision)
{
   if (collision.gameObject.name == "bullet(Clone)")
   {
     Destroy(this.gameObject);
   }
}

วัตถุที่เป็น Prefab อย่างกระสุนที่เราใช้ในเกม หากมีการสร้างใหม่ขึ้นมาจะมีชื่ออ้างอิงต้นแบบของ Prefab แล้วตามด้วย (Clone) ในตัวอย่างชื่อกระสุน bullet ก็จะถูกสร้างใหม่ชื่อว่า bullet(Clone) ภาพรวมของ Class ชื่อ Enemy จะเป็นดังนี้:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
   public float objectSpeed = 0.5f;
   void Update()
   {
    transform.Translate(0, 0, objectSpeed);
   }
   void OnTriggerEnter(Collider collision)
   {
    if (collision.gameObject.name == "bullet(Clone)")
    {
     Destroy(this.gameObject);
    }
   }
}

ทดสอบระบบของ Enemy เราจะเห็นว่ามันได้ทําการพุ่งเข้ามาหา Player ของเราแล้ว ขั้นตอนต่อไปคือการ สร้างระบบสุ่มตําแหน่งของการ เรียก Enemy มาทําซํ้าในตําแหน่งที่แตกต่างกันหรือที่เรียกว่า Spawn เกิด ใหม่ขึ้นมา ให้เราสร้าง Create Empty ขึ้นมาใหม่ตั้งชื่อว่า SpawnPoint ใส่Tag ให้กับมันเป็น Respawn ให้เรียบร้อย

หลักการทํางานของ ReSpawn

เราจะสร้างตัวแปร GameObject เปล่าๆ ขึ้นมาตั้งชื่อ ว่า temp โดย temp จะมีหน้าที่ Clone ตัว Prefab จากตัวแปร enemy อีกทีโดยการหนดจุดปล่อยผ่านการสุ่มแนวราบของฉากตําแหน่งแกน x ที่ -30 ไป จนถึง 30 นั่นคือความกว้างหมดฉากของฉากที่เป็นผืนนํ้า แล้ว ตําแหน่งแกน y แนวดิ่ง ยานของศัตรูจะมีทั้ง ลอยเหนือน่านนํ้าและ ลอยสูงกว่าตัวยานของ Player ให้เราต้องบังคับบินขึ้นไปยิงใส่มัน

สร้าง Script ใหม่ขึ้นมาตั้งชื่อ Class ว่า Respawn หลังจากนั้นให้เรากําหนดตัวแปร Global Variable ดังนี้:

public GameObject enemy;
float timeElapsed = 0;
float ItemCycle = 0.5f;

กําหนดให้ GameObject ที่เราจะเรียกใช้งานซํ้าๆในรูปแบบ Prefab นั้นเก็บในตัวแปร enemy หลังจากนั้นให้เรากําหนด Cycle ของยานศัตรูให้ออกมาทุก 0.5 วินาที ผ่านตัวแปร ItemCycle

โดยมีการจับเวลาผ่านตัวแปร timeElapsed ดังนั้นให้ไป Implement ส่วนของการสร้าง Spawn จาก Prefab ในฟังก์ชัน Update() ดังนี้:

void Update()
{
   timeElapsed += Time.deltaTime;
   if (timeElapsed > ItemCycle)
   {
    GameObject temp;
    temp = (GameObject)Instantiate(enemy);
    Vector3 pos = temp.transform.position;
    temp.transform.position = new Vector3(Random.Range(-30, 30),Random.Range(0, 10), pos.z);
    timeElapsed -= ItemCycle;
   }
}

เราจะสร้างตัวแปร GameObject เปล่าๆ ขึ้นมาตั้งชื่อ ว่า temp โดย temp จะมีหน้าที่ Clone ตัว Prefab จากตัวแปร enemy อีกที โดยการหนดจุดปล่อยผ่านการสุ่มแนวราบของฉากตําแหน่งแกน x ที่ -30 ไปจนถึง 30 นั่นคือความกว้างหมดฉากของฉากที่เป็นผืนนํ้าแล้ว

ตําแหน่งแกน y แนวดิ่ง ยานของศัตรูจะมีทั้งลอยเหนือน่านนํ้า และ ลอยสูงกว่าตัวยานของ Player ให้เรา ต้องบังคับบินขึ้นไปยิงใส่มัน

ภาพรวม Class ของ Respawnจะเป็นดังนี้:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Respawn : MonoBehaviour
{
   public GameObject enemy;
   float timeElapsed = 0;
   float ItemCycle = 0.5f;
   void Update()
   {
    timeElapsed += Time.deltaTime;
    if (timeElapsed > ItemCycle)
    {
     GameObject temp;
     temp = (GameObject)Instantiate(enemy);
     Vector3 pos = temp.transform.position;
     temp.transform.position = new Vector3(Random.Range(-30, 30),Random.Range(0, 10), pos.z);
     timeElapsed -= ItemCycle;
    }
   }
}

ทําการลาก Enemy บน Hierarchy ไปสร้างเป็น Prefabs

สร้าง Enemy เป็น Prefab โดยการลากวางไปยังโฟลเดอร์ “Prefabs” ใน Project Window

คลิกที่ Spawn บน Hierarchy สังเกตที่ Inspector Window เราจะเห็นช่องที่เรียกหา enemy อยู่ให้เราลาก Prefab ของ Enemy จากโฟลเดอร์“Prefabs” ใน Project Window ไปวางใน Class ของ Spawn

ทําการทดสอบเกมโดยการกด Play เพื่อทดสอบการบังคับการสุ่มตัวศัตรู และการยิงกระสุนใส่ศัตรู เรา สามารถยิงศัตรูได้แล้วในตอนนี้

ดังนั้นในขั้นตอนต่อไปที่จะเป็นขั้นตอนสุดท้ายของเกมยานอวกาศนั่นคือการสร้างเงื่อนไขให้ Player ชนศัตรูแล้วเกิดสถานะที่เรียกว่า “Game Over”

อ่านต่อ ตอนที่ 2: สร้างเกม Unity 3D แนว Space Shooting ตอนที่ 2

Asst. Prof. Banyapon Poolsawas

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

Related Articles

Back to top button

Adblock Detected

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