Nhảy tới nội dung

Máy Trạng Thái (State Machine)

Mẫu thiết kế Máy Trạng Thái (State Machine Design Pattern) là một phương pháp thiết kế hệ thống có thể tồn tại ở một trong nhiều trạng thái (chế độ) cụ thể, đi kèm các quy tắc chuyển đổi giữa các trạng thái này. Mỗi trạng thái đại diện cho một hành vi hoặc hành động khác nhau, và hệ thống di chuyển giữa chúng dựa trên các sự kiện hoặc điều kiện nhất định. Mẫu thiết kế này rất hữu ích trong việc tổ chức các hệ thống có hành vi thay đổi linh hoạt như giao diện người dùng hay trò chơi.

Mẫu Thiết Kế Máy Trạng Thái

interface State {
enter(): void;
exit(): void;
update(dt: number): State;
}
class StateMachine {
private currentState: State;

constructor(initialState: State) {
this.currentState = initialState;
this.currentState.enter();
}

public changeState(newState: State): void {
this.currentState.exit();
this.currentState = newState;
this.currentState.enter();
}

public update(dt: number): void {
var state = this.currentState.update(dt);

// nếu trạng thái thay đổi, cập nhật trạng thái hiện tại
if (state && state !== this.currentState) {
this.changeState(state);
}
}
}

Chúng ta có lớp StateMachine quản lý trạng thái hiện tại của hệ thống. Nó chứa các phương thức để chuyển đổi và cập nhật trạng thái hiện tại. Interface State định nghĩa các phương thức mà mỗi trạng thái phải triển khai.

Hãy cùng triển khai một ví dụ sử dụng mẫu thiết kế máy trạng thái.

Hệ Thống Vũ Khí (Weapon System)

Một vũ khí có thể có các trạng thái khác nhau như Idle (Chờ), Firing (Bắn), Reloading (Nạp đạn), v.v. Chúng ta cần một máy trạng thái để quản lý các trạng thái này.

class Weapon {
public fireRate: number; // số viên / giây
public reloadTime: number; // giây
public magazineSize: number;
public currentAmmo: number;

private stateMachine: StateMachine;

constructor() {
this.stateMachine = new StateMachine(new IdleState(this));
}

public update(dt: number): void {
this.stateMachine.update(dt);
}

public spawnBullets(): void {
// tạo đạn
// phương thức này cũng có thể là một trạng thái
}

public startFiring(): void {
this.stateMachine.changeState(new FiringState(this));
}

public stopFiring(): void {
this.stateMachine.changeState(new IdleState(this));
}
}

Mỗi trạng thái của hệ thống vũ khí sẽ triển khai interface State, và chúng cần nắm giữ tham chiếu tới đối tượng vũ khí. Do đó, chúng ta cần một lớp WeaponState để tất cả các trạng thái mở rộng (extend).

class WeaponState implements State {
protected weapon: Weapon;

constructor(weapon: Weapon) {
this.weapon = weapon;
}

public enter(): void { }
public exit(): void { }
public update(dt: number): State { }
}

Hãy định nghĩa các trạng thái cụ thể.

class IdleState extends WeaponState {
public enter(): void {
console.log("Vũ khí đang ở trạng thái chờ");
}

public update(dt: number): State {
// không làm gì cả
return this;
}
}
class FiringState extends WeaponState {
private timeSinceLastShot: number;

constructor(weapon: Weapon) {
super(weapon);
this.timeSinceLastShot = 0;
}

public enter(): void {
console.log("Vũ khí đang bắn");
}

public update(dt: number): State {
this.timeSinceLastShot += dt;
if (this.timeSinceLastShot >= 1 / this.weapon.fireRate) {
this.weapon.currentAmmo--;
this.timeSinceLastShot = 0;
weapon.spawnBullets();

// hết đạn, chuyển sang trạng thái nạp đạn
if (this.weapon.currentAmmo <= 0) {
return new ReloadingState(this.weapon);
}
}

// tiếp tục bắn
return this;
}
}
class ReloadingState extends WeaponState {
private timeSinceReload: number;

constructor(weapon: Weapon) {
super(weapon);
this.timeSinceReload = 0;
}

public enter(): void {
console.log("Vũ khí đang nạp đạn");
}

public update(dt: number): State {
this.timeSinceReload += dt;
if (this.timeSinceReload >= this.weapon.reloadTime) {
this.weapon.currentAmmo = this.weapon.magazineSize;
return new FiringState(this.weapon);
}

return this;
}
}

Giờ đây chúng ta đã có một hệ thống vũ khí tự động bắn đạn sau khi gọi Weapon.startFiring(). Nó sẽ tự động nạp đạn khi hết đạn và tiếp tục bắn cho đến khi Weapon.stopFiring() được gọi.

Toàn bộ logic cho từng trạng thái được đóng gói sạch sẽ trong lớp trạng thái tương ứng, giúp hệ thống dễ dàng quản lý và mở rộng.