ลองใช้ NavMesh ทำ Area ให้ตัวละครเดินโดยไม่ใช้ Collider กันดีกว่า

ถ้าเป็นปกติเวลาเราทำพื้นให้ตัวละครของเราลงไปเดินเล่นได้ Component ที่น่าจะต้องใช้กันทุกคนแน่ๆก็น่าจะเป็น Physic Collider สักตัวที่เหมาะกับพื้นของเรา ส่วนใหญ่ก็น่าจะเป็นพวก Box Collider หรือไม่ก็ Mesh Collider ถ้าแมพเป็น Terrain ไปเลยก็อาจจะใช้เป็น Terrain Collider อะไรทำนองนี้
ซึ่งหลักการก็คือเราจะยัด Collider ลงไปทั้งในพื้นและในตัวละครของเรา เพื่อให้ทั้งสอง Object เช็คชนกันและกัน อาจจะมียัด RigidBody เข้าไปในตัวละครด้วยเพื่อเพิ่มความสามารถด้าน Physic (แรงโน้มถ่วงที่กดให้เราติดกับพื้นอะไรประมาณนี้) เมื่อสอง Object เช็คชนกันและกันก็จะตู้ม! เกิดเป็นโกโก้ครันช์… ไม่ใช่ล่ะเห้ย!!!
เอาง่ายๆก็มันทำให้ตัวละครเราใต่ไปตามพื้นผิวของแมพได้
แต่ว่าตัว Collider เองมันก็มีข้อจำกัดของมันอยู่ อย่างกรณีที่ผมเคยเจอ ไม่รู้ว่า Unity แก้ไขไปรึยัง คือถ้าวัตถุพุ่งมาด้วยความเร็วสูงๆหน่อยแล้วมาชนกับ Collider มันมีโอกาสที่วัตถุนั้นจะทะลุ Collider ไปได้เฉย อ้าว =_=
และตัว Collider เองก็ใช้ทรัพยากรในการประมวลผลค่อนข้างมาก (เราเลยไม่ค่อยเห็นใครใช้ Collider มาเช็คชนกับพื้นผิวที่มีความละเอียดมากๆอย่างตัวละครไง) ยิ่งมีพื้นผิวเยอะๆ ละเอียดๆ Collider ก็ต้องประมวลผลละเอียดตามไปด้วย แล้วถ้า Object ในเกมเราทุกชิ้นมันมี Collider ติดอยู่กันทุกชิ้นเลยล่ะ หึหึ
ก็เลยเกิดเป็น How to อันนี้
NavMesh มันคืออะไร ?
NavMesh มาจากคำสองคำคือ Nav มาจากคำว่า Navigation และ Mesh ซึ่งก็คือองค์ประกอบของ จุด (Vertices) เส้น (Edges) และผิวหน้า (Faces) ที่ประกอบรวมกันเป็นรูปทรงอะไรซักอย่างในพิกัดสามมิติของคอมพิวเตอร์ <- ไม่รู้อธิบายแล้วยากขึ้นรึเปล่า ฮ่าๆ เอาเป็นว่ามันคือพื้นผิวละกัน
สรุปคือ NavMesh มันก็คือพื้นผิวที่เรากำหนดขึ้นมา เพื่อใช้เป็นข้อมูลบอกกับระบบ AI ว่าพื้นที่ตรงนี้เดินไปได้นะ พื้นที่ตรงนี้ห้ามเดินนะ
อ้าว แล้วมันเกี่ยวกับ How to ของเรายังไง ?
เราจะใช้สมบัติข้อหนึ่งของ NavMesh ที่ว่า Agent ทุกตัวจะต้องอยู่บนพื้นที่ที่สามารถเดินได้ จะไม่สามารถทะลุออกไปนอกพื้นที่นี้ได้ พอจะมองเห็นไอเดียไหม?

มาเริ่มจากสร้างตัวละครกันก่อน
สร้าง Object อะไรมาก็ได้ แล้วสร้างไฟล์ C# Script ชื่อว่า PlayerController แล้วติดมันเข้าไปที่ Object นั้น
เปิดไฟล์สคริปต์ขึ้นมา เราจะเขียนการทำงานให้ตัวละครสามารถเดินไปเดินมาได้ด้วยการกดปุ่ม wasd บนคีย์บอร์ด โดยเขียนโค๊ดดังนี้
void Start ()
{
playerRigid = GetComponent<Rigidbody>();
}
void Update ()
{
PlayerMovement();
}
private Rigidbody playerRigid;
private void PlayerMovement()
{
if(Input.GetAxisRaw("Vertical") > 0)
{
playerRigid.velocity = new Vector3(playerRigid.velocity.x,
playerRigid.velocity.y, 5.0f);
}
if(Input.GetAxisRaw("Vertical") < 0)
{
playerRigid.velocity = new Vector3(playerRigid.velocity.x,
playerRigid.velocity.y, -5.0f);
}
if(Input.GetAxisRaw("Horizontal") < 0)
{
playerRigid.velocity = new Vector3(-5.0f,
playerRigid.velocity.y, playerRigid.velocity.z);
}
if(Input.GetAxisRaw("Horizontal") > 0)
{
playerRigid.velocity = new Vector3(5.0f,
playerRigid.velocity.y, playerRigid.velocity.z);
}
if(Input.GetAxisRaw("Vertical") == 0)
{
playerRigid.velocity = new Vector3(playerRigid.velocity.x,
playerRigid.velocity.y, 0);
}
if(Input.GetAxisRaw("Horizontal") == 0)
{
playerRigid.velocity = new Vector3(0, playerRigid.velocity.y,
playerRigid.velocity.z);
}}
อย่าลืม Call ฟังชันก์นี้ใน Update ด้วยนะ
กลับมาที่ Scene ที่สร้างไว้ แปะ RigidBody เข้าไปในตัวละครของเราด้วย แล้วติ๊กถูกหน้า Use gravity ออกไปก่อน
เท่านี้ตัวละครของเราก็น่าจะเดินไปเดินมาได้แล้ว

ได้เวลาสร้างพื้น
สร้าง Cube ขึ้นมาตัวนึง ตั้งชื่อให้มันว่า Ground แล้วปรับให้มันแบนเหมือนกับมันเป็นพื้น กะขนาดให้มีความใหญ่พอประมาณ หรือจะใช้วิธีทำเป็นแผ่นเล็กๆมาต่อๆกันเหมือนกระเบื้องก็ได้นะ
สิ่งสำคัญคือ ให้ติ๊กถูกหน้าคำว่า Static ที่อยู่เหนือ Component Transform ด้านหลังชื่อ Object ด้วยนะ ขั้นตอนนี้สำคัญมาเพราะเป็นตัวกำหนดว่า NavMesh จะถูกสร้างบน Object ชิ้นใหนบ้าง

ผมจะใช้วิธีสร้างพื้นขึ้นมาหลายๆชิ้นแล้วเอามาต่อกันให้เป็น Area ใหญ่ๆ ที่สำคัญก็คือดูให้แน่ใจว่าทุกชิ้นเป็น Static หมดแล้ว
จากนั้นไปที่ Window -> Navigation เพื่อเปิดหน้า Navigation ขึ้นมา
จะพบกับแท็บสี่แท็บ ให้เลือกไปที่ Object ก่อน จากนั้นเลือก Object พื้นของเรามาหนึ่งชิ้น จะได้พารามิเตอร์ขึ้นมาใหม่สามตัว ให้ติ๊กถูกหน้า Navigation Static และ Generate OffMeshLinks ทั้งสองตัว ส่วน Navigation Area ให้เลือกเป็น Walkable
จากนั้นเลือกแท็บ Bake ใช้ค่าดั้งเดิมทั้งหมดที่ระบบให้มา จากนั้นกด Bake โล้ด!

ลองกด Play ทดสอบเล่นดูจะพบว่า อ่าว ก็ยังเดินออกไปนอกพื้นได้เหมือนเดิมนี่หว่า ไอคนเขียนมันหลอกให้อ่านหรอวะเนี่ย
เปล่าๆ สิ่งสุดท้ายที่ต้องทำคือเลือกไปที่ตัวละครของเราแล้วเพิ่ม Component Nav Mesh Agent เข้าไปก่อน
ปรับค่าความสูงกับรัศมีของ Agent ให้เหมาะสมกับขนาดตัวละคร จะปรับ Base Offset ด้วยก็ได้ถ้าต้องการ ส่วนค่าความเร็วทั้งหลายไม่ต้องไปสนใจ เพราะว่าตัวละครนี้ผู้เล่นเป็นคนคุม ไม่ใช่ระบบ AI
ทีนี้ลองทดสอบดูอีกครั้ง
จะพบว่าตัวละครจะไม่เดินออกไปนอกพื้นอีกแล้ว ฮิ้วววววว~~~
สรุป
จริงๆแล้ว NavMesh มันเอาไว้สำหรับสร้าง AI ศัตรูให้วิ่งตามผู้เล่นอะไรแบบนี้ มันเป็นการให้ข้อมูลกับตัว Agent ว่าพื้นที่ตรงนี้เดินได้นะ ตรงนี้เดินไม่ได้นะ ถ้าหากมีอะไรขวางให้เดินหลบหรือไปหาทางอื่น
แต่เราสามารถใช้ Component Agent มาติดไว้กับตัวละครเฉยๆเพื่อให้มันยึดติดอยู่กับพื้นที่ที่เรากำหนดให้เดินได้เท่านั้น วิธีนี้ไม่ได้ใช้ Collider เลยแม้แต่อันเดียว ทำให้ประหยัดทรัพยากรที่ต้องใช้ในการประมวลผลไปได้มากโข
อันที่จริงวิธีนี้ผมลองผิดลองถูกด้วยตัวเอง อาจจะไม่ใช่ Best Practic ที่ดีที่สุด หากว่าใครมีวิธีที่ดีกว่าก็เอามาแชร์กันได้ครับ