วิชาการโดย milo อ่าน 9 นาทีเรียบเรียงโดยมี AI ช่วย

คณิตศาสตร์เบื้องหลังเอนจินเกม: จาก 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 เป็นสิ่งสำคัญต่อความไว้วางใจของผู้อ่าน

พบข้อมูลที่ไม่ถูกต้องหรือคลาดเคลื่อน?เข้าสู่ระบบเพื่อทักท้วง
บทความนี้เป็นอย่างไร?

ยังไม่มีความคิดเห็น — มาเป็นคนแรกกันเถอะ!