Mẫu để thực hiện các hành động trò chơi


11

Có một mô hình thường được chấp nhận để thực hiện các hành động khác nhau trong một trò chơi không? Một cách mà người chơi có thể thực hiện các hành động và AI cũng có thể thực hiện các hành động, chẳng hạn như di chuyển, tấn công, tự hủy, v.v.

Tôi hiện có một BaseAction trừu tượng sử dụng khái quát .NET để chỉ định các đối tượng khác nhau được trả về bởi các hành động khác nhau. Tất cả điều này được thực hiện theo một mẫu tương tự như Lệnh, trong đó mỗi hành động tự chịu trách nhiệm và thực hiện tất cả những gì nó cần.

Lý do của tôi là trừu tượng là để tôi có thể có một ActionHandler duy nhất và AI chỉ có thể xếp hàng các hành động khác nhau thực hiện cơ sở. Và lý do chung chung là vì các hành động khác nhau có thể trả về thông tin kết quả có liên quan đến hành động (vì các hành động khác nhau có thể có kết quả hoàn toàn khác nhau trong trò chơi), cùng với một số triển khai trướcAction và afterAction phổ biến.

Vậy ... có cách nào được chấp nhận hơn để làm việc này không, hay âm thanh này có ổn không?


Nghe có vẻ tốt, câu hỏi là bạn có ý nghĩa gì khi xếp hàng? Hầu hết các trò chơi có phản ứng rất nhanh? "AI có thể xếp hàng các hành động khác nhau"
AturSams

Điểm tốt. Không có hàng đợi. Nó chỉ cần biết nếu bận, và nếu không, thực hiện hành động.
Arkiliknam

Câu trả lời:


18

Tôi không nghĩ có một cách được chấp nhận để thực hiện khái niệm này, nhưng tôi thực sự muốn chia sẻ cách tôi thường xử lý vấn đề này trong các trò chơi của mình. Đó là một chút kết hợp của mẫu thiết kế Command và mẫu thiết kế Composite .

Tôi có một lớp cơ sở trừu tượng cho các hành động không gì khác hơn là một trình bao bọc xung quanh một Updatephương thức được gọi là mỗi khung và một Finishedcờ để cho biết khi nào hành động đã chạy xong.

abstract class Action
{
    abstract void Update(float elapsed);
    bool Finished;
}

Tôi cũng sử dụng mẫu thiết kế tổng hợp để tạo ra một loại hành động có khả năng lưu trữ và thực hiện các hành động khác. Đây cũng là một lớp trừu tượng. Luộc xuống:

abstract class CompositeAction : Action
{
    void Add(Action action) { Actions.Add(action); }
    List<Action> Actions;
}

Sau đó, tôi có hai triển khai các hành động tổng hợp, một cho thực thi song song và một cho thực hiện tuần tự . Nhưng điều tuyệt vời là vì song song và trình tự là hành động, chúng có thể được kết hợp để tạo ra các luồng thực thi phức tạp hơn.

class Parallel : CompositeAction
{
    override void Update(float elapsed) 
    {
        Actions.ForEach(a=> a.Update(elapsed));
        Actions.RemoveAll(a => a.Finished);
        Finished = Actions.Count == 0;
    }
}

Và một trong những chi phối hành động liên tiếp.

class Sequence : CompositeAction
{
    override void Update(float elapsed) 
    {
        if (Actions.Count > 0) 
        {
            Actions[0].Update(elapsed);
            if (Actions[0].Finished)
                Actions.RemoveAt(0);
        }
        Finished = Actions.Count == 0;
    }
 }

Với điều này, đó đơn giản chỉ là vấn đề tạo ra các triển khai hành động cụ thể, và sử dụng ParallelSequencecác hành động để kiểm soát luồng thực thi. Tôi sẽ kết thúc bằng một ví dụ:

// Create a parallel action to work as an action manager
Parallel actionManager = new Parallel();

// Send character1 to destination
Sequence actionGroup1 = new Sequence();
actionGroup1.Add(new MoveAction(character1, destination));
actionGroup1.Add(new TalkAction(character1, "Arrived at destination!"));
actionManager.Add(actionGroup1);

// Make character2 use a potion on himself
Sequence actionGroup2 = new Sequence();
actionGroup2.Add(new RemoveItemAction(character2, ItemType.Potion));
actionGroup2.Add(new SetHealthAction(character2, character2.MaxHealth));
actionGroup2.Add(new TalkAction(character2, "I feel better now!"));
actionManager.Add(actionGroup2);

// Every frame update the action manager
actionManager.Update(elapsed);

Tôi đã sử dụng thành công hệ thống này để điều khiển tất cả các trò chơi trong một cuộc phiêu lưu đồ họa trước đây, nhưng nó có thể hoạt động cho hầu hết mọi thứ. Nó cũng đủ đơn giản để thêm các loại hành động tổng hợp khác, được sử dụng để tạo các vòng lặp thực thi và các điều kiện.


Đó trông giống như một giải pháp rất tốt đẹp. Vì tò mò, làm thế nào để bạn cho UI biết phải vẽ gì? Các đối tượng trò chơi của bạn (như các nhân vật) có chứa trạng thái được sử dụng để xác định những gì đã xảy ra cho mục đích kết xuất hay chính hành động đó thực hiện điều đó?
Arkiliknam

1
Thông thường hành động của tôi chỉ thay đổi trạng thái của các thực thể và bất kỳ thay đổi nào đối với đầu ra được kết xuất xảy ra là kết quả của sự thay đổi trạng thái đó, không phải do chính các hành động đó. Ví dụ: với trình kết xuất chế độ ngay lập tức, không cần thêm bước vì Drawphương thức đã được xây dựng trên trạng thái của thực thể và các thay đổi là tự động. Trong trình kết xuất ở chế độ giữ lại như Flash, bạn có thể sử dụng mẫu có thể quan sát để thực hiện các thay đổi cho các thực thể của mình truyền đến các đối tượng hiển thị hoặc tạo kết nối theo cách thủ công bên trong chính thực thể.
David Gouveia

1
Trong tình huống đầu tiên, giả sử rằng Characterlớp của bạn có một thuộc Positiontính và một Drawphương thức đọc giá trị hiện tại Positionlà gì và vẽ hình ảnh chính xác ở đó. Trong tình huống này, bạn chỉ cần cập nhật giá trị của Positionkết quả đó sẽ được tự động nhìn thấy trên màn hình.
David Gouveia

1
Tình huống thứ hai là, khi bạn Charactercó một thuộc Positiontính, nhưng nó ủy nhiệm hiển thị cho một loại Spriteđối tượng nào đó được tự động hiển thị bằng biểu đồ cảnh hoặc một cái gì đó. Trong tình huống này, bạn phải đảm bảo rằng cả vị trí của nhân vật và vị trí của nhân vật luôn luôn đồng bộ, liên quan đến công việc nhiều hơn một chút. Tuy nhiên, trong cả hai trường hợp, tôi không hiểu tại sao người quản lý hành động nên làm gì với nó. :)
David Gouveia

1
Cả hai phương pháp đều có ưu điểm và nhược điểm .. Tôi đã sử dụng phương pháp thứ hai cho trò chơi 2D của mình và đôi khi tôi đã hối hận vì điều đó phức tạp hơn đáng kể để giữ mọi thứ đồng bộ. Nhưng cũng có những lợi thế, ví dụ như khi cố gắng phát hiện thực thể nào được nhấp, hoặc cái gì nên được rút ra, bởi vì mọi thứ sẽ được hiển thị đều được chứa trong cùng một cấu trúc dữ liệu thay vì nằm rải rác giữa các loại thực thể N.
David Gouveia
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.