วิธีการสร้างและเขียน 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]
เพื่อให้ยังสามารถลากScoreText
GameObject ไปใส่ใน Inspector ได้.Awake()
: ฟังก์ชันนี้จะถูกเรียกก่อนStart()
. เราใช้มันเพื่อตั้งค่าInstance
ของScoreManager
. ถ้ามีScoreManager
ตัวอื่นอยู่แล้ว จะทำลายตัวเองทิ้ง เพื่อให้มั่นใจว่ามีแค่ตัวเดียวในเกม.AddScore(int amount)
และDecreaseScore(int amount)
: เป็นpublic
method ที่คลาสอื่นจะเรียกใช้เพื่อเพิ่มหรือลดคะแนน.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);
: นี่คือส่วนสำคัญ เราเรียกใช้AddScore
method ของ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)
: ทำงานคล้ายกับScoreUpObject
ScoreManager.Instance.DecreaseScore(scoreDecreaseAmount);
: เรียกใช้DecreaseScore
method ของScoreManager
ผ่านInstance
เพื่อลดคะแนน.
ขั้นตอนการตั้งค่าใน Unity Editor (สรุป)
- สร้าง Script ทั้ง 3 ตัว:
ScoreManager.cs
,ScoreUpObject.cs
,ScoreDownObject.cs
. - ScoreManager Setup:
- สร้าง Empty GameObject ชื่อ
ScoreManager
ใน Hierarchy. - ลาก Script
ScoreManager.cs
ไปใส่ที่ GameObject นี้. - ใน Inspector ของ
ScoreManager
GameObject ให้ลากScoreText
UI ที่คุณสร้างไว้ใน 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 ต่างๆ อย่างเป็นระเบียบแล้ว ทำให้จัดการง่ายขึ้นมากครับ! มีคำถามเพิ่มเติมไหมครับ?