คณิตศาสตร์เบื้องหลังเอนจินเกม: จาก Vector สู่การตรวจจับการชน
เคยสงสัยไหมว่าทำไมตัวละครในเกมถึงเคลื่อนที่ได้ลื่นไหลเหมือนของจริง? บทความนี้จะเปลี่ยนคณิตศาสตร์ที่ดูยากให้เป็นเรื่องง่ายผ่านตัวอย่างในเกม
สารบัญ

ลองนึกภาพตอนที่คุณควบคุมตัวละครกระโดดข้ามกำแพงในเกมแอ็คชั่นโปรดของคุณ ตัวละครวิ่งเข้าหากำแพง กระโดดขึ้นไปในอากาศ และร่วงลงมาตามแรงโน้มถ่วงอย่างเป็นธรรมชาติ ทุกอย่างดูเหมือนเกิดขึ้นเองโดยไม่มีอะไรซับซ้อน แต่เบื้องหลังการเคลื่อนไหวนั้น คือการคำนวณทางคณิตศาสตร์ที่ทำงานอย่างต่อเนื่องหลายสิบครั้งต่อวินาที
ในบทความก่อนหน้า เราได้พูดถึงเส้นโค้งพาราเมตริกที่ทำให้เกิดเส้นทางการเคลื่อนที่ที่สวยงาม วันนี้เราจะเจาะลึกลงไปอีกขั้น มาดูว่าเอนจินเกมใช้คณิตศาสตร์ตัวไหนในการทำให้วัตถุเคลื่อนที่ มีความเร่ง และรู้ตัวว่าชนกับอะไร
พื้นฐาน Vector ที่ใช้ในการเคลื่อนที่
ถ้าพูดถึงการเคลื่อนที่ในเกม สิ่งแรกที่ขาดไม่ได้คือ Vector (เวกเตอร์) หลายคนอาจจำเวกเตอร์ได้จากวิชาคณิตศาสตร์ในโรงเรียน ซึ่งมักจะมาพร้อมกับลูกศรชี้ทิศทาง แต่ในโลกของการพัฒนาเกม เวกเตอร์คือหัวใจสำคัญที่กำหนดทั้งตำแหน่ง ทิศทาง และความเร็วของวัตถุ
เวกเตอร์ในเกม 2 มิติ (2D) จะมีค่า x และ y ส่วนในเกม 3 มิติ (3D) ก็จะเพิ่มแกน z เข้าไป ตัวอย่างเช่น ตัวละครของเรายืนอยู่ที่ตำแหน่ง (0, 0) และต้องการเดินไปทางขวา เราอาจะเพิ่มค่า x ไปทีละนิด แต่ถ้าต้องการเดินไปทางขวาบนเป็นแนวทแยมุม เราก็ต้องเพิ่มทั้ง x และ y พร้อมกัน
การบวกและการลบเวกเตอร์
การบวกเวกเตอร์ในเอนจินเกมใช้สำหรับการเคลื่อนที่ สมมติตัวละครอยู่ที่ตำแหน่ง Position = (2, 3) และผู้เล่นกดปุ่มเดินไปข้างหน้าด้วยความเร็ว Velocity = (1, 0) ในเฟรมถัดไป ตำแหน่งใหม่ของตัวละครก็จะเท่ากับ Position + Velocity ซึ่งก็คือ (3, 3) นั่นเอง
ส่วนการลบเวกเตอร์มักใช้เพื่อหาทิศทางจากจุดหนึ่งไปยังอีกจุดหนึ่ง ถ้าตัวละครของเราอยู่ที่ (2, 3) และศัตรูอยู่ที่ (5, 3) การลบตำแหน่งศัตรูด้วยตำแหน่งตัวละคร (5, 3) - (2, 3) จะได้เวกเตอร์ (3, 0) ซึ่งบอกทิศทางและระยะห่างว่าศัตรูอยู่ทางขวาของเรา 3 หน่วย
Normalization (การทำให้เป็นเวกเตอร์หน่วย)
บางครั้งเราไม่ได้สนใจระยะทาง แต่สนใจแค่ทิศทาง การทำ Normalization คือการย่อขนาดของเวกเตอร์ให้มีความยาวเท่ากับ 1 หน่วย โดยใช้ทฤษฎีบทพีทาโกรัสหาความยาวเวกเตอร์ก่อน แล้วนำค่า x และ y ไปหารด้วยความยาวนั้น
ยกตัวอย่างเวกเตอร์ (3, 4) ความยาวจริงๆ คือ √(3² + 4²) = 5 เมื่อนำไปหารจะได้เวกเตอร์หน่วยเป็น (0.6, 0.8) ซึ่งมีความยาวเท่ากับ 1 พอดี ในเกมเรามักจะนำเวกเตอร์หน่วยนี้ไปคูณด้วยความเร็วที่ต้องการ เพื่อให้ตัวละครเคลื่อนที่ในทิศทางนั้นด้วยความเร็วคงที่
การใช้ Calculus คำนวณความเร็วและความเร่ง
เมื่อพูดถึง Calculus (แคลคูลัส) หลายคนอาจนึกถึงสมการยากๆ แต่ในเอนจินเกม แคลคูลัสคือเรื่องของการเปลี่ยนแปลงเมื่อเวลาผ่านไป
อนุพันธ์ (Derivative) ในโลกเกม
ในทางคณิตศาสตร์ อนุพันธ์ของตำแหน่งเทียบกับเวลาคือความเร็ว และอนุพันธ์ของความเร็วคือความเร่ง ในเอนจินเกม เราไม่ได้คำนวณอนุพันธ์แบบสมการต่อเนื่อง แต่ใช้วิธีการประมาณค่าในช่วงเวลาสั้นๆ (Delta Time) ซึ่งเรียกว่า Numerical Integration
สมมติตัวละครมีตำแหน่ง P ความเร็ว V และความเร่ง A ในแต่ละเฟรมที่เอนจินอัปเดต เราจะอัปเดตค่าเหล่านี้ด้วยเวลาที่ผ่านไป dt (เดลต้าไทม์) ดังนี้
# อัปเดตความเร็วด้วยความเร่ง
V = V + (A * dt)
# อัปเดตตำแหน่งด้วยความเร็วใหม่
P = P + (V * dt)
วิธีการนี้เรียกว่า Euler Integration เป็นวิธีที่ง่ายที่สุดและใช้ทรัพยากรน้อยที่สุด แม้จะไม่ได้แม่นยำระดับวิทยาศาสตร์นาซา แต่ก็เพียงพอสำหรับเกมทั่วไป
ระบบกระโดดและแรงโน้มถ่วง
ลองนึกถึงตอนที่ตัวละครกระโดด เมื่อผู้เล่นกดปุ่มกระโดด เราจะตั้งค่าความเร็วในแกน Y ให้เป็นค่าบวก (เช่น 10) จากนั้นในทุกๆ เฟรม เราจะเพิ่มค่าความเร่งในแกน Y ให้เป็นค่าลบ (เช่น -9.8 เพื่อจำลองแรงโน้มถ่วง) ผลลัพธ์คือตัวละครจะลอยขึ้นไปก่อน แล้วค่อยๆ ช้าลง จากนั้นตกลงมาเร็วขึ้นเรื่อยๆ จนถึงพื้น ทั้งหมดนี้เกิดจากการคำนวณแคลคูลัสเบื้องต้นที่เราทำในเอนจิน
สมการการตรวจจับการชน (Collision Detection)
การเคลื่อนที่อย่างเดียวยังไม่พอ วัตถุในเกมต้องสามารถชนกันได้ การตรวจจับการชน (Collision Detection) คือกระบวนการตรวจสอบว่าวัตถุสองชิ้นซ้อนทับกันหรือไม่ ซึ่งมีหลายวิธีขึ้นอยู่กับรูปทรงของวัตถุ
AABB (Axis-Aligned Bounding Box)
วิธีที่นิยมและประหยัดทรัพยากรที่สุดคือ AABB ซึ่งหมายถึงการหุ้มวัตถุด้วยกล่องสี่เหลี่ยมที่ไม่หมุน การตรวจสอบการชนของกล่องสองใบทำได้โดยดูว่าค่าในแกน X และ Y มีการซ้อนทับกันหรือไม่
สมมติกล่อง A มีจุดมุมซ้ายล่าง (Ax1, Ay1) และมุมขวาบน (Ax2, Ay2) ส่วนกล่อง B มี (Bx1, By1) และ (Bx2, By2) กล่องทั้งสองจะชนกันเมื่อ
- แกน X ซ้อนทับกัน:
Ax1 < Bx2และAx2 > Bx1 - แกน Y ซ้อนทับกัน:
Ay1 < By2และAy2 > By1
ถ้าเงื่อนไขทั้งสองข้อเป็นจริงพร้อมกัน แปลว่ากล่องชนกัน
Circle Collision (การชนของวงกลม)
สำหรับวัตถุที่กลม เช่น ลูกบอลหรือตัวละครที่มองจากมุมบน การใช้วงกลมจะแม่นยำกว่ากล่อง การตรวจจับการชนของวงกลมสองวงทำได้โดยเปรียบเทียบระยะห่างระหว่างจุดศูนย์กลางทั้งสองกับผลรวมของรัศมี
ถ้าระยะห่างระหว่างจุดศูนย์กลางน้อยกว่าหรือเท่ากับผลรวมรัศมี แปลว่าวงกลมทั้งสองซ้อนทับกัน การหาระยะห่างใช้สูตรระยะทางระหว่างสองจุด ซึ่งก็คือรากที่สองของผลรวมกำลังสองของผลต่างในแกน X และ Y นั่นเอง
ตัวอย่างโค้ด Python และ C# ในการประยุกต์ใช้
เพื่อให้เห็นภาพชัดเจนขึ้น มาดูโค้ดตัวอย่างที่นำคณิตศาสตร์เหล่านี้ไปประยุกต์ใช้จริงในเอนจินเกมกัน
ตัวอย่าง Python: การเคลื่อนที่และความเร่ง
โค้ดด้านล่างเป็นการจำลองตัวละครที่เคลื่อนที่ไปข้างหน้าด้วยความเร่งคงที่ โดยใช้หลักการแคลคูลัสเบื้องต้น
class Player:
def __init__(self):
self.position = [0.0, 0.0] # ตำแหน่งเริ่มต้น
self.velocity = [0.0, 0.0] # ความเร็วเริ่มต้น
self.acceleration = [1.0, 0.0] # ความเร่งไปทางขวา
def update(self, dt):
# อัปเดตความเร็วด้วยความเร่ง
self.velocity[0] += self.acceleration[0] * dt
self.velocity[1] += self.acceleration[1] * dt
# อัปเดตตำแหน่งด้วยความเร็ว
self.position[0] += self.velocity[0] * dt
self.position[1] += self.velocity[1] * dt
# จำลองการทำงาน 60 เฟรมต่อวินาที (dt = 1/60)
player = Player()
for frame in range(60):
player.update(1/60)
print(f"ตำแหน่งสุดท้าย: {player.position}")
print(f"ความเร็วสุดท้าย: {player.velocity}")
จะเห็นว่าหลังจากผ่านไป 1 วินาที (60 เฟรม) ตัวละครจะมีความเร็วเพิ่มขึ้นเรื่อยๆ เนื่องจากมีความเร่งคงที่ และตำแหน่งก็จะขยับไปไกลขึ้นตามลำดับ
ตัวอย่าง C#: การตรวจจับการชนแบบ AABB
สำหรับนักพัฒนาที่ใช้ Unity หรือเอนจินที่รองรับ C# โค้ดนี้เป็นตัวอย่างการตรวจจับการชนแบบ AABB แบบง่ายๆ
using System;
public struct Box
{
public float X1, Y1; // มุมซ้ายล่าง
public float X2, Y2; // มุมขวาบน
public Box(float x1, float y1, float x2, float y2)
{
X1 = x1; Y1 = y1;
X2 = x2; Y2 = y2;
}
}
public class CollisionDetector
{
public static bool IsColliding(Box a, Box b)
{
// ตรวจสอบการซ้อนทับในแกน X
bool overlapX = (a.X1 < b.X2) && (a.X2 > b.X1);
// ตรวจสอบการซ้อนทับในแกน Y
bool overlapY = (a.Y1 < b.Y2) && (a.Y2 > b.Y1);
return overlapX && overlapY;
}
}
// ตัวอย่างการใช้งาน
class Program
{
static void Main()
{
Box boxA = new Box(0, 0, 10, 10);
Box boxB = new Box(5, 5, 15, 15);
if (CollisionDetector.IsColliding(boxA, boxB))
{
Console.WriteLine("กล่องชนกัน!");
}
else
{
Console.WriteLine("กล่องไม่ชนกัน");
}
}
}
โค้ดนี้แสดงให้เห็นว่าการตรวจจับการชนไม่จำเป็นต้องซับซ้อนเสมอไป ด้วยการเปรียบเทียบค่าพื้นฐานทางคณิตศาสตร์ เราก็สามารถสร้างระบบฟิสิกส์ในเกมได้
สรุป
คณิตศาสตร์ในเอนจินเกมไม่ได้น่ากลัวอย่างที่คิด เมื่อเราเข้าใจหลักการพื้นฐาน เวกเตอร์ช่วยให้เราอธิบายตำแหน่งและทิศทางได้ แคลคูลัสช่วยให้เราคำนวณการเปลี่ยนแปลงเมื่อเวลาผ่านไป และสมการง่ายๆ ช่วยให้เราตรวจจับการชนได้ ทั้งหมดนี้คือเครื่องมือที่นักพัฒนาเกมใช้สร้างโลกเสมือนจริงที่น่าตื่นเต้น
ลองนำโค้ดตัวอย่างไปปรับใช้ในโปรเจกต์เกมของคุณดู แล้วคุณจะพบว่าคณิตศาสตร์ไม่ใช่แค่วิชาในห้องเรียน แต่มันคือภาษาที่ใช้สร้างสรรค์โลกในจินตนาการ
คุณคิดว่าในอนาคตเอนจินเกมจะพัฒนาระบบฟิสิกส์ไปในทิศทางไหน? มาแชร์ความคิดเห็นและประสบการณ์ของคุณในการใช้คณิตศาสตร์ในเกมได้เลยในคอมเมนต์ด้านล่าง!
เนื้อหาที่จัดทำโดยมี AI ช่วยจะมีป้ายกำกับ "เรียบเรียงโดยมี AI ช่วย" เพื่อให้คุณทราบอย่างชัดเจน เราถือว่าความโปร่งใสเรื่องการใช้ AI เป็นสิ่งสำคัญต่อความไว้วางใจของผู้อ่าน
ความคิดเห็น (0)
ยังไม่มีความคิดเห็น — มาเป็นคนแรกกันเถอะ!