วิธีการสร้างและเขียน Script การให้คะแนน แบบ 2 มิติ
โดยการแยกโค้ดออกเป็นหลาย Class เพื่อให้การจัดการโปรเจกต์ให้เป็นระเบียบและง่ายต่อการบำรุงรักษา (Modular Design)

โครงสร้าง Class
แยกโค้ดออกเป็น 3 Class หลักๆ ดังนี้:
ScoreManager: ทำหน้าที่จัดการและแสดงผลคะแนนบน UI.ScoreUpObject: ทำหน้าที่เพิ่มคะแนนเมื่อผู้เล่นชน.ScoreDownObject: ทำหน้าที่ลดคะแนนเมื่อผู้เล่นชน.
การเตรียมการใน Unity (ปรับปรุง)
การเตรียม GameObjects จะคล้ายเดิม แต่มีบางจุดที่ต้องปรับเปลี่ยนเล็กน้อย:
- วัตถุผู้เล่น (Player GameObject):
- เหมือนเดิมคือมี
Rigidbody2D(Dynamic),Collider2D(Is Trigger). - สิ่งสำคัญ: ผู้เล่นจะ ไม่จำเป็นต้องมี Script ใดๆ ที่เกี่ยวกับการชนคะแนนโดยตรง อีกต่อไป แต่ผู้เล่นจะต้องมี
Collider2Dที่เป็นIs Triggerเพื่อให้วัตถุอื่นสามารถตรวจจับการชนได้.
- เหมือนเดิมคือมี
- วัตถุที่ทำให้คะแนนเพิ่ม (ScoreUp GameObject):
- มี
Collider2D(Is Trigger),Rigidbody2D(Kinematic). - ไม่ต้องตั้ง Tag เป็น
ScoreUpอีกแล้ว. - ลาก C# Script ชื่อ
ScoreUpObjectไปใส่ที่ GameObject นี้.
- มี
- วัตถุที่ทำให้คะแนนลด (ScoreDown GameObject):
- มี
Collider2D(Is Trigger),Rigidbody2D(Kinematic). - ไม่ต้องตั้ง Tag เป็น
ScoreDownอีกแล้ว. - ลาก C# Script ชื่อ
ScoreDownObjectไปใส่ที่ GameObject นี้.
- มี
- UI สำหรับแสดงคะแนน (Score Text UI):
- สร้าง
Text - TextMeshProเหมือนเดิม ตั้งชื่อเป็นScoreText.
- สร้าง
- GameObject สำหรับจัดการคะแนน (ScoreManager GameObject):
- สร้าง GameObject เปล่าๆ หนึ่งอัน (คลิกขวาที่ Hierarchy -> Create Empty) ตั้งชื่อว่า
ScoreManager. - ลาก C# Script ชื่อ
ScoreManagerไปใส่ที่ GameObject นี้.
- สร้าง GameObject เปล่าๆ หนึ่งอัน (คลิกขวาที่ Hierarchy -> Create Empty) ตั้งชื่อว่า
โค้ด C# (แยก Class)
1. ScoreManager.cs (Class สำหรับจัดการและแสดงผลคะแนน)
สร้าง C# Script ชื่อ ScoreManager แล้วคัดลอกโค้ดนี้ลงไป:
C#
using UnityEngine;
using TMPro; // จำเป็นต้องใช้สำหรับ TextMeshProUGUI
public class ScoreManager : MonoBehaviour
{
// Instance (singleton pattern) เพื่อให้ Class อื่นเรียกใช้ได้ง่าย
public static ScoreManager Instance { get; private set; }
// ตัวแปรสำหรับเก็บคะแนนปัจจุบัน
private int score = 0;
// อ้างอิงถึง TextMeshProUGUI UI ที่จะแสดงคะแนน
[SerializeField] private TextMeshProUGUI scoreText; // [SerializeField] ทำให้เห็นใน Inspector แม้จะเป็น private
// Property สำหรับเข้าถึงคะแนนจากภายนอก (อ่านได้อย่างเดียว)
public int CurrentScore
{
get { return score; }
}
private void Awake()
{
// ตรวจสอบว่ามี Instance อื่นอยู่แล้วหรือไม่
if (Instance != null && Instance != this)
{
Destroy(gameObject); // ทำลายตัวเองถ้ามี Instance อื่นอยู่แล้ว
}
else
{
Instance = this; // กำหนด Instance เป็นตัวเอง
}
}
void Start()
{
// ตรวจสอบว่าได้กำหนด TextMeshProUGUI ใน Inspector แล้วหรือไม่
if (scoreText == null)
{
Debug.LogError("Score Text UI is not assigned in ScoreManager! Please assign it in the Inspector.");
}
// อัปเดตคะแนนเริ่มต้นบนหน้าจอ
UpdateScoreText();
}
/// <summary>
/// เพิ่มคะแนน
/// </summary>
/// <param name="amount">จำนวนคะแนนที่จะเพิ่ม</param>
public void AddScore(int amount)
{
score += amount;
UpdateScoreText();
Debug.Log("Score Increased! Current Score: " + score);
}
/// <summary>
/// ลดคะแนน
/// </summary>
/// <param name="amount">จำนวนคะแนนที่จะลด</param>
public void DecreaseScore(int amount)
{
score -= amount;
// ตรวจสอบไม่ให้คะแนนติดลบ (ถ้าต้องการ)
if (score < 0)
{
score = 0;
}
UpdateScoreText();
Debug.Log("Score Decreased! Current Score: " + score);
}
/// <summary>
/// ฟังก์ชันสำหรับอัปเดตข้อความคะแนนบน UI
/// </summary>
private void UpdateScoreText()
{
if (scoreText != null)
{
scoreText.text = "Score: " + score.ToString();
}
}
}
คำอธิบาย ScoreManager.cs:
public static ScoreManager Instance { get; private set; }: นี่คือการใช้ Singleton Pattern ซึ่งทำให้เราสามารถเข้าถึงScoreManagerได้จากที่ไหนก็ได้ในโค้ด โดยไม่ต้องอ้างอิง GameObject โดยตรง. มีแค่ Instance เดียวเท่านั้นที่สามารถมีอยู่ได้ใน Scene.[SerializeField] private TextMeshProUGUI scoreText;: เรายังคงเก็บ reference ของ Text UI ไว้ที่นี่ แต่เปลี่ยนจากpublicเป็นprivateและใช้[SerializeField]เพื่อให้ยังสามารถลากScoreTextGameObject ไปใส่ใน Inspector ได้.Awake(): ฟังก์ชันนี้จะถูกเรียกก่อนStart(). เราใช้มันเพื่อตั้งค่าInstanceของScoreManager. ถ้ามีScoreManagerตัวอื่นอยู่แล้ว จะทำลายตัวเองทิ้ง เพื่อให้มั่นใจว่ามีแค่ตัวเดียวในเกม.AddScore(int amount)และDecreaseScore(int amount): เป็นpublicmethod ที่คลาสอื่นจะเรียกใช้เพื่อเพิ่มหรือลดคะแนน.UpdateScoreText(): อัปเดต UI ข้อความคะแนน.
2. ScoreUpObject.cs (Class สำหรับวัตถุที่ชนแล้วคะแนนเพิ่ม)
สร้าง C# Script ชื่อ ScoreUpObject แล้วคัดลอกโค้ดนี้ลงไป:
C#
using UnityEngine;
public class ScoreUpObject : MonoBehaviour
{
// จำนวนคะแนนที่จะเพิ่มเมื่อผู้เล่นชนวัตถุนี้
public int scoreIncreaseAmount = 10;
// ฟังก์ชันนี้จะถูกเรียกเมื่อ Collider 2D ของวัตถุนี้ (ScoreUpObject) ไปชนกับ Collider 2D อื่น
// โดยที่ Collider อื่นนั้นต้องทำเครื่องหมาย Is Trigger ไว้
private void OnTriggerEnter2D(Collider2D other)
{
// ตรวจสอบว่าวัตถุที่ชนเข้ามาคือผู้เล่น (หรือมี Component ที่เราสนใจ)
// ในที่นี้ เราแค่ต้องการให้วัตถุชนกับอะไรก็ตามที่มี Collider2D (เช่นผู้เล่น) ก็ให้คะแนนเพิ่ม
// คุณอาจเพิ่มการตรวจสอบ Tag ของผู้เล่นได้ เช่น if (other.CompareTag("Player"))
if (other.GetComponent<Collider2D>() != null) // ตรวจสอบว่าชนกับวัตถุที่มี Collider2D
{
// เรียกใช้ AddScore() ของ ScoreManager ผ่าน Instance
ScoreManager.Instance.AddScore(scoreIncreaseAmount);
// ทำลายวัตถุนี้หลังจากถูกชน
Destroy(gameObject);
}
}
}
คำอธิบาย ScoreUpObject.cs:
public int scoreIncreaseAmount = 10;: กำหนดค่าคะแนนที่จะเพิ่มเมื่อวัตถุนี้ถูกชน. คุณสามารถปรับค่านี้ได้ใน Inspector สำหรับแต่ละวัตถุScoreUpObject.OnTriggerEnter2D(Collider2D other): ฟังก์ชันนี้จะถูกเรียกเมื่อมีวัตถุอื่นที่มีCollider2Dและเป็นIs Triggerมาชนวัตถุนี้.ScoreManager.Instance.AddScore(scoreIncreaseAmount);: นี่คือส่วนสำคัญ เราเรียกใช้AddScoremethod ของScoreManagerผ่านInstanceเพื่อเพิ่มคะแนน.
3. ScoreDownObject.cs (Class สำหรับวัตถุที่ชนแล้วคะแนนลด)
สร้าง C# Script ชื่อ ScoreDownObject แล้วคัดลอกโค้ดนี้ลงไป:
C#
using UnityEngine;
public class ScoreDownObject : MonoBehaviour
{
// จำนวนคะแนนที่จะลดเมื่อผู้เล่นชนวัตถุนี้
public int scoreDecreaseAmount = 5;
// ฟังก์ชันนี้จะถูกเรียกเมื่อ Collider 2D ของวัตถุนี้ (ScoreDownObject) ไปชนกับ Collider 2D อื่น
// โดยที่ Collider อื่นนั้นต้องทำเครื่องหมาย Is Trigger ไว้
private void OnTriggerEnter2D(Collider2D other)
{
// ตรวจสอบว่าวัตถุที่ชนเข้ามาคือผู้เล่น (หรือมี Component ที่เราสนใจ)
if (other.GetComponent<Collider2D>() != null) // ตรวจสอบว่าชนกับวัตถุที่มี Collider2D
{
// เรียกใช้ DecreaseScore() ของ ScoreManager ผ่าน Instance
ScoreManager.Instance.DecreaseScore(scoreDecreaseAmount);
// ทำลายวัตถุนี้หลังจากถูกชน
Destroy(gameObject);
}
}
}
คำอธิบาย ScoreDownObject.cs:
public int scoreDecreaseAmount = 5;: กำหนดค่าคะแนนที่จะลดเมื่อวัตถุนี้ถูกชน.OnTriggerEnter2D(Collider2D other): ทำงานคล้ายกับScoreUpObjectScoreManager.Instance.DecreaseScore(scoreDecreaseAmount);: เรียกใช้DecreaseScoremethod ของScoreManagerผ่านInstanceเพื่อลดคะแนน.
ขั้นตอนการตั้งค่าใน Unity Editor (สรุป)
- สร้าง Script ทั้ง 3 ตัว:
ScoreManager.cs,ScoreUpObject.cs,ScoreDownObject.cs. - ScoreManager Setup:
- สร้าง Empty GameObject ชื่อ
ScoreManagerใน Hierarchy. - ลาก Script
ScoreManager.csไปใส่ที่ GameObject นี้. - ใน Inspector ของ
ScoreManagerGameObject ให้ลากScoreTextUI ที่คุณสร้างไว้ใน Hierarchy ไปใส่ในช่องScore Text.
- สร้าง Empty GameObject ชื่อ
- ScoreUpObject Setup:
- ไปที่ GameObject ที่เป็นวัตถุเพิ่มคะแนนของคุณ (เช่น เหรียญ).
- ลาก Script
ScoreUpObject.csไปใส่ที่ GameObject นี้. - ตั้งค่า
Score Increase Amountใน Inspector (เช่น 10). - ตรวจสอบว่ามี
Collider2D(Is Trigger) และRigidbody2D(Kinematic).
- ScoreDownObject Setup:
- ไปที่ GameObject ที่เป็นวัตถุลดคะแนนของคุณ (เช่น ระเบิด).
- ลาก Script
ScoreDownObject.csไปใส่ที่ GameObject นี้. - ตั้งค่า
Score Decrease Amountใน Inspector (เช่น 5). - ตรวจสอบว่ามี
Collider2D(Is Trigger) และRigidbody2D(Kinematic).
- Player GameObject:
- ตรวจสอบว่ามี
Collider2D(Is Trigger) และRigidbody2D(Dynamic). - ไม่ต้องมี Script ที่เกี่ยวข้องกับการชนคะแนน.
- ตรวจสอบว่ามี
ตอนนี้โค้ดของคุณถูกแยกเป็น Class ต่างๆ อย่างเป็นระเบียบแล้ว ทำให้จัดการง่ายขึ้นมากครับ! มีคำถามเพิ่มเติมไหมครับ?