ก่อนหน้านี้คุณเขียน C# สำหรับสคริปต์ MonoBehaviour ของ Unity และเขียน C++ สำหรับโค้ดระดับเอนจินมาแล้ว บทนี้จะเอาเอนจินเชิงพาณิชย์จริงสองตัวมาเทียบกัน คือ Unity กับ Unreal Engine (มักเรียกสั้น ๆ ว่า "Unreal" หรือ "UE") ทั้งคู่ถูกใช้สร้างเกมจริงที่วางขายจริง คำถามไม่ใช่ "ตัวไหนดีกว่ากัน" แต่เป็น "ตัวไหนเหมาะกับงานที่คุณอยากทำ และการสลับไปมาระหว่างสองตัวนี้ต้องแลกด้วยอะไรบ้าง"
บทนี้เป็นบทเปรียบเทียบ ไม่ใช่การสอนเอนจินตัวใดตัวหนึ่งใหม่ทั้งหมด ถ้าเจอศัพท์ที่ไม่คุ้น จะอธิบายทันทีตอนที่มันโผล่มาครั้งแรก จบบทนี้แล้วคุณควรอ่านประกาศรับสมัครงานที่เขียนว่า "Unity/C#" หรือ "UE5/C++" แล้วรู้ทันทีว่างานประจำวันจะเป็นแบบไหน
game engine (เอนจินเกม) คือซอฟต์แวร์ที่แก้ปัญหายาก ๆ ที่ต้องทำซ้ำ ๆ ไว้ให้แล้ว — render พิกเซล, เล่นเสียง, จัดการ input, รัน physics, โหลด asset — เพื่อให้คุณโฟกัสที่กติกาของเกมตัวเองได้ Unity กับ Unreal ทำหน้าที่นี้ทั้งคู่ ไม่มีตัวไหนเป็น "เคล็ดลับ" ที่ทำให้เกมดี แต่ละตัวคือโรงงานที่คุณใช้สร้างเกม
เอนจินสองตัวนี้ trade-off กันแทบทุกจุด: ภาษาที่คุณเขียน, หน้าตาโปรเจกต์ใหม่ก่อนที่คุณจะแตะอะไรเลย, แพลตฟอร์มที่มันถูก tune มาให้ และใครมักจ้างงานเอนจินไหน trade-off พวกนี้ไม่เกี่ยวกับความสามารถดิบ ๆ เลย เพราะทั้งสองเอนจินสร้างเกม gacha บนมือถือหรือเกมยิงคอนโซล AAA ได้ทั้งคู่ในทางเทคนิค ความต่างอยู่ที่ว่าเส้นทางไหนถูกปูทางไว้ดีกว่ากัน
ใน Unity โค้ด gameplay เกือบทั้งหมดคือ C# คุณเขียนสคริปต์ แนบมันเข้ากับ GameObject (object ที่วางอยู่ใน scene) ในฐานะ MonoBehaviour (base class ที่สคริปต์ Unity สืบทอดมา) แล้ว Unity จะเรียก method บางตัวในเวลาที่กำหนด — Start() ครั้งเดียวตอนที่มันเข้ามาใน scene ครั้งแรก, Update() ทุกเฟรม
using UnityEngine;
public class Health : MonoBehaviour
{
public int maxHP = 100;
private int hp;
void Start()
{
hp = maxHP;
Debug.Log("Health ready: " + hp + " HP");
}
public void TakeDamage(int amount)
{
hp -= amount;
if (hp <= 0)
{
Debug.Log("Character died");
}
else
{
Debug.Log("HP left: " + hp);
}
}
}
เรียก TakeDamage(30) แล้วตามด้วย TakeDamage(90) จากสคริปต์อื่น จะพิมพ์:
Health ready: 100 HP
HP left: 70
Character died
ใน Unreal แนวคิดเดียวกันนี้มีอยู่ แต่เครื่องมือแบ่งออกเป็นสองชั้น C++ คือภาษาสำหรับตัวเอนจินเองและสำหรับโค้ด gameplay ที่ต้อง performance สูงหรือเป็นโครงสร้างพื้นฐาน ส่วน Blueprint คือ visual scripting layer (ชั้นการเขียนสคริปต์แบบมองเห็นภาพ) — คุณต่อ logic ด้วยการลาก node มาเชื่อมกันแทนการพิมพ์ตัวหนังสือ และมัน compile ออกมาเป็น bytecode จริง ไม่ใช่ของเล่น รูปแบบที่สตูดิโอมักใช้คือ: engineer เขียน "ชิ้นส่วนพื้นฐาน" เป็น C++ แล้วเปิดให้ใช้งานได้ จากนั้น designer เอาชิ้นส่วนพวกนั้นมาต่อกันใน Blueprint เพื่อทดลองปรับ feel ของ gameplay ได้เร็ว ๆ
นี่คือไอเดีย Health เดียวกันเขียนเป็น Unreal C++ (โปรเจกต์จริงจะแยกไฟล์นี้เป็น .h กับ .cpp แต่เอามารวมกันตรงนี้เพื่อประหยัดพื้นที่):
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "HealthActor.generated.h"
UCLASS()
class AHealthActor : public AActor
{
GENERATED_BODY()
public:
int32 MaxHP = 100;
void TakeDamage(int32 Amount);
protected:
virtual void BeginPlay() override;
private:
int32 HP;
};
void AHealthActor::BeginPlay()
{
Super::BeginPlay();
HP = MaxHP;
UE_LOG(LogTemp, Log, TEXT("Health ready: %d HP"), HP);
}
void AHealthActor::TakeDamage(int32 Amount)
{
HP -= Amount;
if (HP <= 0)
{
UE_LOG(LogTemp, Log, TEXT("Character died"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("HP left: %d"), HP);
}
}
เรียก TakeDamage(30) แล้วตามด้วย TakeDamage(90) จะพิมพ์เรื่องเดียวกัน แค่ไปที่ Output Log ของ Unreal แทน Console ของ Unity:
LogTemp: Health ready: 100 HP
LogTemp: HP left: 70
LogTemp: Character died
logic เดียวกัน ผลลัพธ์เดียวกัน แค่ syntax ต่างกันและมีระบบ macro ต่างออกไป (UCLASS(), GENERATED_BODY(), UE_LOG) ห่อรอบมันอยู่ designer ที่ไม่เคยเปิดไฟล์ C++ นั้นเลยก็สร้างพฤติกรรม BeginPlay แบบเดียวกันเป๊ะได้ด้วยภาพ:
ในชีวิตประจำวัน สิ่งนี้เปลี่ยนวิธีทำงานของคุณ ใน Unity คุณแทบจะเขียน C# ตลอดเวลา ใน Unreal คุณต้องสลับหมวกตลอด: ใช้ C++ เมื่อต้องการ performance ดิบ ๆ หรือสร้างระบบที่ใช้ซ้ำได้ ใช้ Blueprint เมื่อกำลังทดลองปรับ feel ของ gameplay อย่างรวดเร็ว
สร้างโปรเจกต์ใหม่เปล่า ๆ ในแต่ละเอนจินแล้วดูแสงเริ่มต้น ความต่างเห็นได้ทันที
renderer เริ่มต้นของ Unreal มี Lumen (ระบบคำนวณแสงสะท้อนแบบสมจริงแบบเรียลไทม์ โดยไม่ต้อง bake อะไรเองด้วยมือ) และ Nanite (ระบบที่ให้คุณใช้ mesh คุณภาพระดับภาพยนตร์ที่มีรายละเอียดเยอะมาก โดยไม่ต้องสร้างเวอร์ชันย่อสำหรับระยะไกลเอง — เวอร์ชันย่อพวกนั้นเรียกว่า LOD) รวมกันแล้วทำให้ scene ใหม่ของ Unreal ดูใกล้เคียง photoreal (ย่อจาก photorealistic คือใกล้เคียงภาพถ่ายจริง) แทบจะทันที นี่คือเหตุผลหลักที่ Unreal โผล่บ่อยในงาน cinematic และงาน virtual production ของหนัง/ทีวี
Unity ไม่ได้มี renderer ระดับสูงตัวเดียวตายตัว แต่คุณต้องเลือก Scriptable Render Pipeline (SRP ระบบ render ที่สลับได้): URP (Universal Render Pipeline — เบา เร็ว ปรับให้รันได้ตั้งแต่ PC ระดับท็อปไปจนถึงมือถือระดับกลาง) หรือ HDRP (High Definition Render Pipeline — หนักกว่า เล็งไปที่ภาพระดับสูงบน PC/console ใกล้เคียงกับที่ Unreal ให้มาเป็นค่าเริ่มต้น) scene ใหม่ของ Unity เริ่มต้นแบบเรียบ ๆ แล้วคุณค่อยสร้างลุคขึ้นมาเอง
ไม่มีแนวทางไหน "ดีกว่า" อีกฝ่ายจริง ๆ หรอก ทั้งคู่ optimize เพื่อเป้าหมายต่างกัน Unreal optimize ให้ดูดีโดยที่คุณต้อง tune เองน้อยลง ส่วน Unity optimize ให้คุณคุม performance ได้เอง ซึ่งสำคัญมากเมื่อเป้าหมายของคุณคือมือถืออายุสามปี ไม่ใช่ gaming PC
ทั้งสองเอนจินในทางเทคนิค export ไปได้แทบทุกแพลตฟอร์ม — มือถือ, PC, console, web แต่คำว่า "ทำได้" กับ "ถูก tune มาให้เป็นค่าเริ่มต้น โดยไม่ต้องฝืนเอนจินเยอะ" เป็นคนละคำถามกัน
ขนาดที่เบากว่าเป็นค่าเริ่มต้นของ Unity และประวัติศาสตร์ยาวนานบนฮาร์ดแวร์มือถือ ทำให้มันเป็นตัวเลือกที่ใช้งานได้จริงสำหรับเกมที่ต้องรันดีบนมือถืออายุห้าปีแบตน้อย ๆ — ซึ่งตรงกับตลาด live-service บนมือถือส่วนใหญ่ (เกมที่ยังคงปล่อยเนื้อหาใหม่ตามตารางเวลาต่อเนื่อง ไม่ใช่ปล่อยครั้งเดียวแล้วจบ) พลังภาพเริ่มต้นและเครื่องมือสำหรับ console ของ Unreal ทำให้มันเป็นตัวเลือกที่ใช้งานได้จริงสำหรับเกมที่จุดขายทั้งหมดคือ "ดูภาพนี้สิ"
คุณเห็นแพทเทิร์นของแพลตฟอร์มนี้ได้จากเกมจริงที่วางขายแล้ว:
นี่คือเหตุผลที่คำตอบของ "ควรเรียนเอนจินไหน" เปลี่ยนไปตามเป้าหมาย เกมทั้งหมดที่ HoYoverse วางขายแล้ว รันบน Unity หมด สตูดิโอเกมยิง console งบสูงมีโอกาสสูงกว่ามากที่จะใช้ Unreal สตูดิโอ indie แบ่งกันคร่าว ๆ ตาม genre กับความทะเยอทะยาน — เกมเล็ก ๆ แบบ 2D หรือ 3D สไตล์การ์ตูนมักเอียงไปทาง Unity ส่วนเกมเล็ก ๆ ที่ไล่ตามลุคแบบภาพยนตร์มักเอียงไปทาง Unreal
สำหรับคนที่เรียนเอนจินเป็นครั้งแรก Unity มักเป็นทางลาดที่นุ่มนวลกว่า C# เป็น managed language (runtime จัดการ memory ให้คุณเอง ไม่ต้องคอยจด allocation/free เองแบบ C++ ดิบ ๆ) สคริปต์หนึ่งไฟล์คือหนึ่งไฟล์ และ Unity compile ให้ใหม่อัตโนมัติในไม่กี่วินาทีทุกครั้งที่คุณ save
ฝั่ง C++ ของ Unreal หนักกว่า: ตั้งค่าโปรเจกต์ใหญ่กว่า, compile time นานกว่าเมื่อแก้อะไรใหญ่ ๆ และมี codebase ของเอนจินขนาดมหึมาซ่อนอยู่ใต้โค้ดของคุณเอง นั่นคือต้นทุนจริงตอนที่คุณยังเรียนอยู่ แต่ Unreal ผ่อนหนักเป็นเบาด้วย Blueprint — การทดลองช่วงแรก ๆ ของผู้เรียนใหม่ส่วนใหญ่เกิดขึ้นใน visual graph ล้วน ๆ โดยไม่ต้องผ่านขั้นตอน compile C++ เลย
ตรงนี้แหละที่บทก่อน ๆ ที่คุณเรียนมาจะคุ้มค่า ถ้าคุณเคยฝ่าฟันเรื่อง pointer, stack vs heap และ undefined behavior ในบท C มาแล้ว C++ ของ Unreal จะน่ากลัวน้อยกว่ามากเมื่อเทียบกับคนที่เจอ C++ เป็นครั้งแรกในอ้อมกอดของ codebase เอนจินยักษ์
นี่คือข้อเท็จจริงที่มีประโยชน์ที่สุดในบทนี้: ใต้ชื่อที่ต่างกัน Unity กับ Unreal ใช้ โครงสร้างแกนกลางเดียวกัน มีบางอย่างอยู่ในโลกเกมในฐานะ object; object นั้นถือ component ที่ให้ data กับ behavior กับมัน; component เหล่านั้นรันโค้ดของตัวเองตามจังหวะ lifecycle ที่กำหนดไว้แน่นอน
ย้อนไปดูตัวอย่าง Health ในหัวข้อ 2 Start() กับ BeginPlay() คือไอเดียเดียวกัน แค่ชื่อต่างกัน: "รันสิ่งนี้ครั้งเดียว ตอนที่ฉันเพิ่งโผล่มา" MonoBehaviour กับ AActor ทั้งคู่คือ "base type ที่สิ่งของในโลกเกมสืบทอดมาจาก" Unity Prefab (template ที่บันทึกไว้ ใช้ซ้ำได้ — สร้างศัตรูตัวเดียวแล้ว stamp ออกมาสิบตัว) กับ Unreal Blueprint Class (class ที่คุณสร้างด้วยภาพ แล้ววาง instance ได้หลายตัว) แก้ปัญหาเดียวกันเป๊ะ: กำหนดครั้งเดียว ใช้ซ้ำได้ทุกที่
นั่นแปลว่าการเรียนเอนจินตัวหนึ่งให้ลึกไม่ใช่การเสียเวลาเปล่า ถ้าวันหนึ่งคุณต้องใช้อีกตัว คุณไม่ได้เริ่มจากศูนย์ คุณแค่แปะป้ายชื่อใหม่ให้กับรูปทรงที่คุณเข้าใจอยู่แล้ว ส่วนที่ใหม่จริง ๆ ตอนสลับเอนจินคือเครื่องมือกับ syntax (ขั้นตอน compile C++, editor แบบ node-graph, ชื่อเมนูที่ต่างกัน) ไม่ใช่ไอเดียเบื้องหลัง
เอาหกหัวข้อที่ผ่านมารวมเป็นตารางเดียว:
ไม่มีอะไรในตารางนี้เป็นกฎตายตัว Unity ก็มีเกม HDRP ระดับสูงวางขายอยู่ Unreal ก็มีเกมมือถือเบา ๆ วางขายอยู่ อ่านมันในฐานะ "เส้นทางที่ปูทางไว้ดีมันพาไปทางไหน" ไม่ใช่ "อะไรทำได้บ้างในทางกายภาพ"
จากทั้งหมดข้างบน นี่คือการแบ่งแบบใช้งานได้จริง:
ถ้าเป้าหมายของคุณคือ HoYoverse โดยเฉพาะ (หรือสตูดิโอ live-service gacha แบบ mobile-first ที่คล้ายกัน) — เจาะลึก Unity กับ C# ไปเลย เกมทั้งหมดที่พวกเขาวางขายรันบน Unity หมด นี่ไม่ใช่การเดา มันคือ stack จริงของบริษัทเลย ให้ priority กับ: พื้นฐาน C# ที่แน่น (ซึ่งคุณมีอยู่แล้วจากบทก่อน ๆ), URP, performance กับการ profile บนมือถือ, ระบบ UI และแพทเทิร์นแบบ "เนื้อหาที่ปล่อยตามตาราง" ที่เกม live-service ต้องพึ่งพา เวลาที่ใช้ไปกับ Unreal แทนไม่ได้ผิดอะไร แต่มันไม่ใช่การใช้เวลาที่มีจำกัดอย่างมีประสิทธิภาพที่สุดสำหรับเป้าหมายนี้โดยเฉพาะ
ถ้าเป้าหมายของคุณคือสาย AAA กว้าง ๆ หรือคุณยังไม่รู้จริง ๆ ว่าอยากไปสตูดิโอไหน — เรียนทั้งคู่ แต่ไม่พร้อมกันและไม่ลึกเท่ากันตั้งแต่วันแรก เริ่มจาก Unity ก่อน มันเป็นทางลาดที่นุ่มนวลกว่า และเพราะหัวข้อ 7 ทุกอย่างที่คุณเรียนรู้เกี่ยวกับรูปทรง GameObject/Component/lifecycle ถ่ายทอดตรงไปได้เลย พอรูปทรงนั้นกลายเป็นเรื่องธรรมชาติแล้ว ค่อยย้ายไปเรียน C++ กับ Blueprint ของ Unreal คุณจะใช้เวลาไปกับการเรียนชื่อใหม่และเครื่องมือใหม่ ไม่ใช่ concept ใหม่ ดังนั้นเอนจินตัวที่สองควรไปได้เร็วกว่าตัวแรกอย่างเห็นได้ชัด
public class Mover : MonoBehaviour
{
public int distance = 0;
public int speed = 4;
void Update()
{
distance += speed;
if (distance > 10)
{
Debug.Log("Reached checkpoint at distance " + distance);
}
}
}
(a) ใช้ตารางจากหัวข้อ 7 บอกชื่อสิ่งที่เทียบเท่ากับ MonoBehaviour ใน Unreal และสิ่งที่เทียบเท่ากับ Update() ใน Unreal
(b) Update() รันติดกันสามครั้ง (สามเฟรม) ให้เขียนว่าแต่ละเฟรมพิมพ์อะไรออกมาบ้าง ถ้ามี
(a) สิ่งที่เทียบเท่ากับ MonoBehaviour ใน Unreal คือ AActor (base class ที่ "สิ่งของ" ที่วางได้สืบทอดมา) สิ่งที่เทียบเท่ากับ Update() คือ Tick() (รันทุกเฟรม)
(b) เฟรม 1: distance กลายเป็น 4 4 > 10 เป็นเท็จ ไม่มีอะไรพิมพ์ เฟรม 2: distance กลายเป็น 8 8 > 10 เป็นเท็จ ไม่มีอะไรพิมพ์ เฟรม 3: distance กลายเป็น 12 12 > 10 เป็นจริง เลยพิมพ์ Reached checkpoint at distance 12
น้ำ ควรทุ่มไปที่ Unity เกือบทั้งหมด เกมที่ HoYoverse วางขายรันบน Unity ทั้งหมด นี่ไม่ใช่การเดิมพัน มันคือการจับคู่กับ stack จริงของบริษัทเลย เพราะน้ำรู้ C# ดีอยู่แล้ว ปีนี้ควรใช้ไปกับทักษะเฉพาะของ Unity: URP, performance กับการ profile บนมือถือ, ระบบ UI, และแพทเทิร์นเนื้อหาแบบ live-service การใช้เวลาส่วนใหญ่ไปกับ Unreal แทนไม่ได้ผิดในแง่ทั่วไป แต่มันไม่ได้พาน้ำเข้าใกล้เป้าหมายนี้มากขึ้น เลยไม่ใช่ทางเลือกที่มีประสิทธิภาพที่สุด
พลอย ควรเรียนทั้งคู่ ตามลำดับ ไม่ใช่พร้อมกัน เริ่มจาก Unity ในช่วงสองสามเดือนแรก — มันมี learning curve ที่นุ่มนวลกว่า และตามหัวข้อ 7 มันสอนรูปทรง GameObject/Component/lifecycle แบบเดียวกันเป๊ะกับที่ Unreal ใช้ภายใต้ชื่อต่างกัน พอรูปทรงนั้นกลายเป็นเรื่องอัตโนมัติแล้ว ค่อยใช้เดือนที่เหลือไปกับ C++ กับ Blueprint ของ Unreal เพราะงานสาย AAA บน console/PC เอียงไปทาง Unreal บ่อยกว่า Unity เพราะ concept พื้นฐานถ่ายทอดมาแล้ว ครึ่งหลังนี้ควรไปได้เร็วกว่าครึ่งแรก — พลอยส่วนใหญ่กำลังเรียนชื่อใหม่กับเครื่องมือใหม่ (ขั้นตอน compile C++, editor แบบ Blueprint graph) ไม่ใช่ไอเดียใหม่ สัดส่วนคร่าว ๆ อาจเป็น 40% ของปีไปกับ Unity ก่อน แล้ว 60% ไปกับ Unreal หลังจากพื้นฐานเป็นเรื่องอัตโนมัติแล้ว
สรุปแบบตรงไปตรงมา: Unity กับ Unreal เป็นชุดเครื่องมือคนละชุดที่สร้างอยู่บนไอเดียเดียวกัน เลือกตัวที่ตรงกับที่ที่คุณอยากทำงานจริง ๆ เจาะลึกตัวนั้นก่อน แล้วมองอีกเอนจินเป็นแค่ปัญหาที่ต้องไปเปิดดูทีหลัง — โมเดล object, component, และ lifecycle ที่คุณรู้อยู่แล้วจะยังอยู่ตรงนั้น แค่ใส่ชื่อคนละชื่อเท่านั้นเอง