Trạng thái dưới dạng lớp
Thuộc phần Kiến trúc trò chơi trong Unity trong hành trình Unity của Coddy. Bài học 35 trên 64.
Câu lệnh switch trên enum ở phần 3 tập trung hoạt động của mọi trạng thái vào một hàm Update. Cách này không còn phù hợp khi các trạng thái có dữ liệu riêng: bộ hẹn giờ chỉ một trạng thái dùng sẽ trở thành một trường của MonoBehaviour, nằm cạnh các trường của mọi trạng thái khác, và mỗi nhánh case phải nhớ đặt lại những gì nó sử dụng. Mẫu trạng thái (state pattern) trong C# tạo một lớp riêng cho mỗi trạng thái, và mỗi lớp triển khai cùng một giao diện. Đèn báo đường này nhấp nháy hoặc sáng liên tục, còn phím Space chuyển đổi giữa hai trạng thái:
public interface IState
{
void Enter();
void Tick();
void Exit();
}
public class BlinkState : IState
{
private Renderer lamp;
private float timer;
public BlinkState(Renderer lamp)
{
this.lamp = lamp;
}
public void Enter() { timer = 0f; }
public void Tick()
{
timer += Time.deltaTime;
if (timer >= 0.5f)
{
timer = 0f;
lamp.enabled = !lamp.enabled;
}
}
public void Exit() { lamp.enabled = true; }
}
public class SteadyState : IState
{
public void Enter() { }
public void Tick() { }
public void Exit() { }
}
public class Beacon : MonoBehaviour
{
public Renderer lamp;
private IState blink;
private IState steady;
private IState current;
void Start()
{
blink = new BlinkState(lamp);
steady = new SteadyState();
SetState(steady);
}
void Update()
{
if (Keyboard.current.spaceKey.wasPressedThisFrame) SetState(current == steady ? blink : steady);
current.Tick();
}
void SetState(IState next)
{
if (current != null) current.Exit();
current = next;
current.Enter();
}
}Các trạng thái là những lớp C# thông thường, không phải MonoBehaviour. Bạn tạo chúng bằng new và truyền cho chúng những gì cần thiết thông qua hàm khởi tạo, ở đây là Renderer của đèn, vì chúng không phải là component và không thể gọi GetComponent hay hiển thị trường trong Inspector. Unity cũng không gọi các phương thức của chúng: Beacon là MonoBehaviour, nên hàm Update của nó gọi current.Tick() mỗi khung hình.
timer chỉ thuộc về BlinkState, và hàm Enter đặt nó về 0 mỗi khi đèn báo bắt đầu nhấp nháy. Exit dọn dẹp khi trạng thái kết thúc: bạn có thể nhấn Space khi đèn đang tắt, và Exit bật đèn trở lại, nhờ đó SteadyState không bao giờ bắt đầu với đèn tối. SetState chạy Exit của trạng thái cũ, rồi chạy Enter của trạng thái mới. Một trạng thái thứ ba, chẳng hạn như nhịp sáng chậm, chỉ cần thêm một lớp nữa, còn hàm Update của Beacon không thay đổi.
Thử thách
Trung bìnhViết trạng thái quét của tháp pháo.
- Trong
IState.cs, khai báopublic interface IStatevớivoid Enter();,void Tick();vàvoid Exit();. - Trong
TurretStates.cs, viếtScanState : IState, truyền vào đầu tháp pháo. Khi vào: đặt góc thành 0, đặt đầu tháp pháo thànhColor.green. Khi cập nhật: quét góc y cục bộ của đầu tháp pháo trong khoảng từ-45đến45, với tốc độ90độ mỗi giây. Turret: gọi hàm vào trạng thái trong Start, cập nhật trạng thái đó trong Update.
Nhấn Chơi: đầu tháp pháo màu xanh lá quét qua lại. Sau đó nhấn Kiểm tra.
Tự làm thử
using UnityEngine;
// ScanState
Tất cả bài học trong Kiến trúc trò chơi trong Unity
1Thành phần, không phải hệ thống phân cấp
Thành phần nhỏTập lệnh kẻ địch cơ sởThành phần trừu tượngCác thành phần phối hợp với nhauÔn tập: tháp pháo mô-đunÔn tập: pháo nòng đôi4Dữ liệu tuần tự hóa
Lớp có thể tuần tự hóaDanh sách trong InspectorKiểu liệt kê trong InspectorÔn tập: Bảng vật phẩm rơiÔn tập: Quay vật phẩm7Máy trạng thái
Trạng thái dưới dạng lớpTrạng thái cảnh báoMáy trạng tháiChuyển trạng tháiTrí tuệ của kẻ địchHiệp sĩ tấn côngÔn tập: trạng thái cửa2Giao diện trong Unity
IDamageableGiao diện và TryGetComponentGetComponentsÔn tập: phím tương tácÔn tập: đối tượng gần nhất trong tầm với5ScriptableObjects
Tài sản dữ liệuChỉ số vũ khíCài đặt dùng chungLưu gióSóng dưới dạng dữ liệuÔn tập: Cơ sở dữ liệu vật phẩmÔn tập: Mua hàng từ cửa hàng8Code có thể tái sử dụng
Phương thức mở rộngSingleton tổng quátCác hàm hỗ trợ tổng quátÔn tập: FindNearest3Sự kiện
Sự kiện C# trong UnityĐăng ký trong OnEnableCác trường UnityEventSự kiện điều khiển UIÔn tập: Cửa sổ bật lên thành tíchÔn tập: Bộ hẹn giờ cửa sổ bật lên6Lưu dữ liệu bằng JSON
JsonUtilityLưu trò chơiTải dữ liệu và giá trị mặc địnhÔn tập: các ô lưuChọn và xóa một ô lưu9Tái sử dụng đối tượng bằng pool
Vì sao cần pool đối tượngPool dùng hàng đợiObjectPool của UnityÔn tập: pool đạnTự luyện tập: Playground Unity