ตัวอย่าง Code Unity 3D สำหรับการเคลื่อนที่ของตัวละคร (ผู้เล่น) โดยครอบคลุมการเดิน วิ่ง หัน และกระโดด พร้อมคำอธิบายในแต่ละส่วนและวิธีการตรวจจับพื้นด้วย OnCollisionEnter

ในการสร้างการเคลื่อนไหว 3 มิติใน Unity สำหรับตัวละคร (Player) ที่สามารถเดิน วิ่ง หัน และกระโดดได้ เราจะใช้ C# Script เป็นหลักครับ และจะอธิบายวิธีการ “check ground ด้วย collisionenter” รวมถึงการหันซ้ายขวาแบบละเอียด

นี่คือตัวอย่างโค้ดและคำอธิบายในแต่ละหัวข้อ:

ภาพรวมโครงสร้าง (Unity Scene Setup):

  • Player GameObject: สร้าง Capsule, Cube, หรือ Model ตัวละครของคุณ
    • เพิ่ม Character Controller Component (แนะนำสำหรับ Player Movement)
    • เพิ่ม Rigidbody Component (ตั้งค่า Is Kinematic เป็น true หากใช้ Character Controller เพื่อหลีกเลี่ยงการชนกันที่ไม่ได้ตั้งใจ แต่ถ้าต้องการแรงทางฟิสิกส์ให้ปล่อยเป็น false และจัดการ collision ดีๆ)
    • เพิ่ม Script ชื่อ PlayerMovement.cs (ที่เราจะเขียน)
  • Ground GameObject: สร้าง Plane หรือ Cube เพื่อเป็นพื้น
    • เพิ่ม Collider Component (เช่น Box Collider หรือ Mesh Collider)

PlayerMovement.cs (ตัวอย่างโค้ด)

C#

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    // กำหนดค่าความเร็ว
    public float walkSpeed = 5f;
    public float runSpeed = 10f;
    public float jumpForce = 8f;
    public float rotationSpeed = 200f; // ความเร็วในการหัน

    // อ้างอิงถึง Character Controller
    private CharacterController controller;

    // สถานะการกระโดดและการเช็คพื้น
    private Vector3 moveDirection;
    private bool isGrounded; // สถานะว่าอยู่บนพื้นหรือไม่

    // Gravity
    public float gravity = 20f;

    void Start()
    {
        controller = GetComponent<CharacterController>();
        if (controller == null)
        {
            Debug.LogError("PlayerMovement: CharacterController not found!");
        }
    }

    void Update()
    {
        // 1. เดิน (Walk) และ 2. วิ่ง (Run)
        HandleMovement();

        // 3. หัน (Turn)
        HandleRotation();

        // 4. กระโดด (Jump)
        HandleJump();

        // ใช้ Gravity ตลอดเวลาเมื่อไม่ได้อยู่บนพื้น
        if (!isGrounded)
        {
            moveDirection.y -= gravity * Time.deltaTime;
        }

        // ใช้ Character Controller ในการเคลื่อนที่จริง
        controller.Move(moveDirection * Time.deltaTime);
    }

    private void HandleMovement()
    {
        // รับค่า Input จากแกน Horizontal (A/D หรือ Left/Right Arrow) และ Vertical (W/S หรือ Up/Down Arrow)
        float horizontalInput = Input.GetAxis("Horizontal");
        float verticalInput = Input.GetAxis("Vertical");

        // คำนวณทิศทางการเคลื่อนที่ตาม Input และทิศทางของ Player เอง (Local Space)
        Vector3 forwardMovement = transform.forward * verticalInput;
        Vector3 rightMovement = transform.right * horizontalInput;

        // รวมทิศทางการเคลื่อนที่และทำให้เป็น Normalized เพื่อความสม่ำเสมอ
        Vector3 desiredMove = forwardMovement + rightMovement;
        if (desiredMove.magnitude > 1f)
        {
            desiredMove.Normalize();
        }

        // กำหนดความเร็วตามสถานะเดินหรือวิ่ง
        float currentSpeed = Input.GetKey(KeyCode.LeftShift) ? runSpeed : walkSpeed; // กด Shift ค้างเพื่อวิ่ง

        // ถ้าอยู่บนพื้น ให้กำหนดทิศทาง XZ ใหม่ แต่รักษา Y (การกระโดด/แรงโน้มถ่วง)
        if (isGrounded)
        {
            moveDirection.x = desiredMove.x * currentSpeed;
            moveDirection.z = desiredMove.z * currentSpeed;
        }
        else
        {
            // ถ้าไม่อยู่บนพื้น ให้ยังคงใช้ทิศทาง XZ เดิม แต่ยังคงสามารถควบคุมทิศทางได้เล็กน้อย
            // (คุณอาจปรับแต่งส่วนนี้ได้ตามความต้องการ)
            moveDirection.x = Mathf.Lerp(moveDirection.x, desiredMove.x * currentSpeed, Time.deltaTime * 5f);
            moveDirection.z = Mathf.Lerp(moveDirection.z, desiredMove.z * currentSpeed, Time.deltaTime * 5f);
        }
    }

    private void HandleRotation()
    {
        // รับค่า Input สำหรับการหันซ้าย/ขวา
        // ใช้ Horizontal Input สำหรับการหมุนตัว Player
        float rotationInput = Input.GetAxis("Mouse X") * rotationSpeed * Time.deltaTime; // ใช้ Mouse X สำหรับการหันตามเมาส์

        // คุณสามารถใช้ Input.GetAxis("Horizontal") อีกครั้งหากต้องการหันด้วย A/D เมื่อไม่ได้เดินหน้า/ถอยหลัง
        // เช่น:
        // if (Input.GetAxis("Vertical") == 0) // ถ้าไม่ได้เดินหน้า/ถอยหลัง
        // {
        //     rotationInput = Input.GetAxis("Horizontal") * rotationSpeed * Time.deltaTime;
        // }


        // หมุน Player รอบแกน Y (ขึ้น/ลง)
        transform.Rotate(Vector3.up, rotationInput);
    }

    private void HandleJump()
    {
        if (isGrounded && Input.GetButtonDown("Jump")) // "Jump" คือ Spacebar โดย Default
        {
            moveDirection.y = jumpForce;
            isGrounded = false; // เมื่อกระโดดแล้ว ไม่ถือว่าอยู่บนพื้นทันที
        }
    }

    // การตรวจสอบพื้นด้วย OnControllerColliderHit (สำหรับ Character Controller)
    void OnControllerColliderHit(ControllerColliderHit hit)
    {
        // ตรวจสอบว่าชนกับวัตถุที่อยู่ด้านล่างและเป็นพื้นหรือไม่
        // โดยใช้ normal (ทิศทางของพื้นผิวที่ชน)
        if (Vector3.Angle(Vector3.up, hit.normal) < 45f) // มุมที่น้อยกว่า 45 องศา ถือว่าเป็นพื้น
        {
            isGrounded = true;
        }
        else
        {
            // ถ้าชนกับกำแพงหรือเพดาน อาจจะเซ็ต isGrounded เป็น false หรือจัดการอื่นๆ
        }
    }

    // สำหรับการตรวจสอบพื้นด้วย CollisionEnter (ถ้า Player ใช้ Rigidbody)
    // โปรดทราบ: หากใช้ Character Controller เป็นหลัก, OnControllerColliderHit จะเหมาะสมกว่า
    // แต่ถ้า Player ใช้ Rigidbody และต้องการใช้ OnCollisionEnter, ต้องมี Rigidbody บน Player ด้วย
    /*
    void OnCollisionEnter(Collision collision)
    {
        // ตรวจสอบว่าชนกับวัตถุที่มี Tag "Ground" หรือไม่
        if (collision.gameObject.CompareTag("Ground"))
        {
            isGrounded = true;
        }
    }

    void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.CompareTag("Ground"))
        {
            isGrounded = false;
        }
    }
    */
}

คำอธิบายแต่ละหัวข้อ:

1. เดิน (Walk)

  • โค้ด: HandleMovement()
  • หลักการ:
    • รับค่า Input จากแกน Vertical (W/S หรือ Up/Down Arrow) เพื่อกำหนดทิศทางเดินหน้า/ถอยหลัง และ Horizontal (A/D หรือ Left/Right Arrow) สำหรับเดินซ้าย/ขวา (Strafe).
    • ใช้ transform.forward และ transform.right เพื่อให้การเคลื่อนที่เป็นไปตามทิศทางที่ตัวละครหันอยู่ (Local Space) ไม่ใช่ทิศทางของโลก (World Space).
    • controller.Move(moveDirection * Time.deltaTime): ใช้เมธอด Move ของ CharacterController ในการเคลื่อนที่จริง. Time.deltaTime ทำให้การเคลื่อนที่เป็นอิสระจาก Frame Rate.
    • walkSpeed: ตัวแปรที่ใช้ควบคุมความเร็วในการเดิน คุณสามารถปรับได้ใน Inspector ของ Unity.

2. วิ่ง (Run)

  • โค้ด: ส่วนหนึ่งของ HandleMovement()
  • หลักการ:
    • เป็นการเพิ่มความเร็วในการเคลื่อนที่จาก walkSpeed เป็น runSpeed.
    • ในโค้ดตัวอย่าง เราใช้ Input.GetKey(KeyCode.LeftShift) เพื่อตรวจสอบว่าผู้เล่นกำลังกดปุ่ม Left Shift ค้างไว้หรือไม่.
    • ถ้ากด Shift, currentSpeed จะเป็น runSpeed, ถ้าไม่กด, currentSpeed จะเป็น walkSpeed.

3. หัน (Turn)

  • โค้ด: HandleRotation()
  • หลักการ:
    • การหันแบบปกติ (ตามเมาส์ – แนะนำสำหรับเกม First/Third Person):
      • float rotationInput = Input.GetAxis("Mouse X") * rotationSpeed * Time.deltaTime;
      • เราใช้ Input.GetAxis("Mouse X") เพื่อรับค่าการเคลื่อนที่ของเมาส์ในแนวนอน. ค่านี้จะบวก/ลบเมื่อเมาส์เคลื่อนที่ซ้าย/ขวา.
      • transform.Rotate(Vector3.up, rotationInput);
      • Vector3.up คือแกน Y (แกนตั้ง) ของโลก. การหมุนรอบแกน Y จะทำให้ตัวละครหันซ้ายหรือขวา.
      • rotationSpeed: ตัวแปรควบคุมความเร็วในการหัน.
      • Time.deltaTime: ทำให้การหมุนเป็นไปอย่างราบรื่นและไม่ขึ้นกับ Frame Rate.
    • การหันแบบกดปุ่ม A/D (สำหรับบางเกมที่ไม่ได้ใช้เมาส์หันเป็นหลัก):
      • ถ้าต้องการให้ปุ่ม A/D ใช้สำหรับการหันเมื่อไม่ได้เดินหน้า/ถอยหลัง สามารถเพิ่มเงื่อนไข if (Input.GetAxis("Vertical") == 0) เข้าไปใน HandleRotation() ได้ตามตัวอย่างในโค้ด.

4. กระโดด (Jump)

  • โค้ด: HandleJump()
  • หลักการ:
    • if (isGrounded && Input.GetButtonDown("Jump")): ตรวจสอบสองเงื่อนไข:
      1. isGrounded: ตัวละครต้องอยู่บนพื้นก่อนถึงจะกระโดดได้.
      2. Input.GetButtonDown("Jump"): ตรวจสอบว่าผู้เล่นกดปุ่ม “Jump” (โดยปกติคือ Spacebar) ในเฟรมปัจจุบัน.
    • moveDirection.y = jumpForce;: เมื่อเงื่อนไขเป็นจริง, กำหนดค่า Y ของ moveDirection ให้เป็น jumpForce (แรงกระโดด). ค่า Y นี้จะถูกลดลงเรื่อยๆ ด้วยแรงโน้มถ่วง (gravity) ใน Update().
    • isGrounded = false;: ตั้งค่า isGrounded เป็น false ทันทีที่กระโดด เพื่อป้องกันการกระโดดกลางอากาศหลายครั้ง.

การตรวจสอบพื้น (Check Ground) ด้วย OnControllerColliderHit และ OnCollisionEnter

OnControllerColliderHit (แนะนำสำหรับ Character Controller)

  • หลักการ: เมธอดนี้จะถูกเรียกโดย Unity เมื่อ CharacterController ชนกับ Collider อื่นๆ.
  • โค้ดในตัวอย่าง:C#void OnControllerColliderHit(ControllerColliderHit hit) { if (Vector3.Angle(Vector3.up, hit.normal) < 45f) { isGrounded = true; } }
  • อธิบาย:
    • hit.normal: คือ Vector Normal ของพื้นผิวที่ CharacterController ชน. Normal Vector จะตั้งฉากกับพื้นผิว.
    • Vector3.Angle(Vector3.up, hit.normal): คำนวณมุมระหว่างแกน Y ของโลก (Vector3.up) กับ Normal Vector ของพื้นผิวที่ชน.
    • ความหมาย: ถ้ามุมนี้น้อยกว่า 45 องศา (หรือค่าที่คุณกำหนด), แสดงว่าพื้นผิวที่ชนค่อนข้างราบเรียบและอยู่ด้านล่างของตัวละคร ซึ่งหมายความว่าตัวละครอยู่บนพื้น. ค่า 45 องศาเป็นค่าทั่วไปที่ใช้เพื่อกำหนดความชันสูงสุดที่ตัวละครสามารถยืนอยู่ได้.
    • ประโยชน์: วิธีนี้มีความแม่นยำสูงและออกแบบมาเพื่อทำงานร่วมกับ CharacterController ได้เป็นอย่างดี.

OnCollisionEnter (สำหรับ Rigidbody)

  • หลักการ: เมธอดนี้จะถูกเรียกเมื่อ Collider ของ GameObject ที่มี Rigidbody ชนกับ Collider อื่นๆ.
  • ข้อควรระวัง: ถ้าคุณใช้ CharacterController เป็นหลัก คุณไม่จำเป็นต้องมี Rigidbody ที่ไม่ได้เป็น Kinematic บน Player. ถ้ามี Rigidbody ที่ไม่ใช่ Kinematic มันอาจจะชนและเคลื่อนที่ด้วยฟิสิกส์เอง ซึ่งจะขัดแย้งกับการควบคุมของ CharacterController.
  • ถ้าจะใช้:
    • Player GameObject ต้องมี Rigidbody Component และ ไม่ ได้ตั้งค่า Is Kinematic เป็น true.
    • พื้น (Ground) GameObject ต้องมี Collider.
    • คุณอาจต้องเพิ่ม Tag “Ground” ให้กับ GameObject ที่เป็นพื้น เพื่อให้ตรวจสอบได้ง่ายขึ้น.
  • โค้ดตัวอย่าง (อยู่ใน Comment ใน Script):C#/* void OnCollisionEnter(Collision collision) { if (collision.gameObject.CompareTag("Ground")) { isGrounded = true; } } void OnCollisionExit(Collision collision) { if (collision.gameObject.CompareTag("Ground")) { isGrounded = false; } } */
  • อธิบาย:
    • OnCollisionEnter(Collision collision): ถูกเรียกเมื่อเริ่มการชน.
    • collision.gameObject.CompareTag("Ground"): ตรวจสอบว่า GameObject ที่ชนมี Tag เป็น “Ground” หรือไม่.
    • OnCollisionExit(Collision collision): ถูกเรียกเมื่อหยุดการชน. ใช้เพื่อตั้งค่า isGrounded เป็น false เมื่อตัวละครออกจากพื้น.

วิธีการ หัน ซ้าย ขวา แบบ // สำหรับเปลี่ยนทิศทาง Player (หันซ้าย/ขวา)

ในโค้ดตัวอย่างใน HandleRotation() มีการอธิบายถึงวิธีการหันซ้ายขวาแล้ว แต่จะเน้นย้ำอีกครั้งในส่วนนี้:

1. การหันตามเมาส์ (Mouse X Input – แนะนำสำหรับมุมมองบุคคลที่หนึ่ง/สาม):

  • float rotationInput = Input.GetAxis("Mouse X") * rotationSpeed * Time.deltaTime;
    • Input.GetAxis("Mouse X") จะให้ค่าบวกเมื่อเมาส์เลื่อนไปทางขวา และค่าลบเมื่อเมาส์เลื่อนไปทางซ้าย. ค่านี้จะต่อเนื่องและลื่นไหล.
    • เราคูณด้วย rotationSpeed เพื่อควบคุมความเร็วในการหัน และ Time.deltaTime เพื่อให้การหมุนไม่ขึ้นกับ Frame Rate.
  • transform.Rotate(Vector3.up, rotationInput);
    • เมธอด transform.Rotate() ใช้ในการหมุน GameObject.
    • Vector3.up คือแกน Y ของโลก. การหมุนรอบแกน Y จะทำให้ GameObject หันซ้าย/ขวา เหมือนการหมุนตัวอยู่กับที่.
    • rotationInput คือมุมที่ต้องการหมุนในแต่ละเฟรม.

ข้อดี: เป็นวิธีที่นิยมและให้ความรู้สึกเป็นธรรมชาติในการควบคุมตัวละครในเกม 3 มิติส่วนใหญ่.

2. การหันด้วยปุ่ม A/D (Horizontal Input – สำหรับบางกรณี):

  • หากคุณต้องการให้ปุ่ม A/D (หรือ Left/Right Arrow) ใช้ในการหมุนตัวละครแทนการเดิน Strafe (หรือใช้เมื่อไม่ได้เดินหน้า/ถอยหลัง), คุณสามารถปรับใน HandleRotation() ได้ดังนี้:C#private void HandleRotation() { // รับค่า Input สำหรับการหันซ้าย/ขวา float rotationInput = 0f; // ถ้าต้องการหันด้วยเมาส์ rotationInput += Input.GetAxis("Mouse X") * rotationSpeed * Time.deltaTime; // หรือถ้าต้องการหันด้วย A/D เมื่อไม่ได้เดินหน้า/ถอยหลัง // (คุณอาจจะต้องปรับ Logic ใน HandleMovement ไม่ให้ A/D ใช้เดิน Strafe ด้วย หากใช้ A/D หันอย่างเดียว) // if (Input.GetAxis("Vertical") == 0) // ถ้าไม่ได้เดินหน้า/ถอยหลัง // { // rotationInput += Input.GetAxis("Horizontal") * rotationSpeed * Time.deltaTime; // } transform.Rotate(Vector3.up, rotationInput); }
  • หลักการ: คล้ายกับการหันด้วยเมาส์ แต่ใช้ Input.GetAxis("Horizontal") แทน.

การตั้งค่าใน Unity:

  • ตรวจสอบให้แน่ใจว่าได้เพิ่ม PlayerMovement.cs ลงใน Player GameObject ของคุณ.
  • ลาก Character Controller Component เข้าไปในช่อง Controller ใน Inspector ของ Script.
  • ปรับค่า Walk Speed, Run Speed, Jump Force, และ Rotation Speed ใน Inspector ให้เหมาะสมกับเกมของคุณ.
  • ตรวจสอบว่าพื้นของคุณมี Collider.

หวังว่าคำอธิบายนี้จะเป็นประโยชน์ในการสร้างการเคลื่อนไหว 3 มิติใน Unity ของคุณนะครับ!

เราใช้คุกกี้เพื่อพัฒนาประสิทธิภาพ และประสบการณ์ที่ดีในการใช้เว็บไซต์ของคุณ คุณสามารถศึกษารายละเอียดได้ที่ นโยบายความเป็นส่วนตัว และสามารถจัดการความเป็นส่วนตัวเองได้ของคุณได้เองโดยคลิกที่ ตั้งค่า

ตั้งค่าความเป็นส่วนตัว

คุณสามารถเลือกการตั้งค่าคุกกี้โดยเปิด/ปิด คุกกี้ในแต่ละประเภทได้ตามความต้องการ ยกเว้น คุกกี้ที่จำเป็น

ยอมรับทั้งหมด
จัดการความเป็นส่วนตัว
  • เปิดใช้งานตลอด

บันทึกการตั้งค่า