ตัวอย่าง 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.
- รับค่า Input จากแกน
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()
ได้ตามตัวอย่างในโค้ด.
- ถ้าต้องการให้ปุ่ม A/D ใช้สำหรับการหันเมื่อไม่ได้เดินหน้า/ถอยหลัง สามารถเพิ่มเงื่อนไข
- การหันแบบปกติ (ตามเมาส์ – แนะนำสำหรับเกม First/Third Person):
4. กระโดด (Jump)
- โค้ด:
HandleJump()
- หลักการ:
if (isGrounded && Input.GetButtonDown("Jump"))
: ตรวจสอบสองเงื่อนไข:isGrounded
: ตัวละครต้องอยู่บนพื้นก่อนถึงจะกระโดดได้.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 ที่เป็นพื้น เพื่อให้ตรวจสอบได้ง่ายขึ้น.
- Player 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 ของคุณนะครับ!