Mã hóa các trạng thái khác nhau trong Trò chơi Phiêu lưu


12

Tôi đang lên kế hoạch cho một trò chơi phiêu lưu, và không thể tìm ra cách thức phù hợp để thực hiện hành vi của một cấp độ tùy thuộc vào trạng thái tiến triển câu chuyện.

Trò chơi một người chơi của tôi có một thế giới rộng lớn, nơi người chơi phải tương tác với mọi người trong một thị trấn ở nhiều điểm khác nhau trong trò chơi. Tuy nhiên, tùy thuộc vào tiến trình câu chuyện, những thứ khác nhau sẽ được trình bày cho người chơi, ví dụ: Trưởng nhóm sẽ thay đổi địa điểm từ quảng trường thị trấn sang các địa điểm khác nhau trong thành phố; Cửa sẽ chỉ mở khóa vào những thời điểm nhất định trong ngày sau khi kết thúc một thói quen cụ thể; Các sự kiện cắt màn hình / kích hoạt khác nhau chỉ xảy ra sau khi đạt được một mốc cụ thể.

Tôi ngây thơ nghĩ đến việc sử dụng câu lệnh {} ban đầu để quyết định NPC nên nói gì hoặc có thể tìm thấy gì và làm cho các mục tiêu nhiệm vụ chỉ có thể tương tác sau khi kiểm tra điều kiện của biến game_state toàn cầu. Nhưng tôi nhận ra rằng tôi sẽ nhanh chóng chạy vào rất nhiều trạng thái trò chơi và trường hợp chuyển đổi khác nhau để thay đổi hành vi của một đối tượng. Câu lệnh chuyển đổi đó cũng sẽ rất khó để gỡ lỗi và tôi đoán nó cũng có thể khó sử dụng trong trình chỉnh sửa mức.

Vì vậy, tôi nghĩ, thay vì có một đối tượng có nhiều trạng thái, có lẽ tôi nên có nhiều phiên bản của cùng một đối tượng, với một trạng thái. Bằng cách đó, nếu tôi sử dụng một cái gì đó như trình soạn thảo cấp độ, tôi có thể đặt một phiên bản của NPC tại tất cả các vị trí khác nhau mà anh ta có thể xuất hiện và cũng là một ví dụ cho mỗi trạng thái hội thoại mà anh ta có. Nhưng điều đó có nghĩa là sẽ có rất nhiều đối tượng trò chơi vô hình, không hoạt động trôi nổi xung quanh cấp độ, có thể gây rắc rối cho bộ nhớ hoặc đơn giản là khó thấy trong trình chỉnh sửa cấp độ, tôi không biết.

Hoặc đơn giản, tạo một cấp độ giống hệt nhau, nhưng riêng biệt cho từng trạng thái trò chơi. Điều này cảm thấy cách sạch nhất và không có lỗi để làm mọi thứ, nhưng nó có cảm giác như công việc thủ công khổng lồ đảm bảo mỗi phiên bản của cấp độ thực sự giống hệt nhau.

Tất cả các phương pháp của tôi cảm thấy không hiệu quả, vì vậy để tóm tắt lại câu hỏi của tôi, có cách nào tốt hơn hoặc tiêu chuẩn hóa để thực hiện hành vi của một cấp độ tùy thuộc vào trạng thái tiến triển câu chuyện không?

Tái bút: Tôi chưa có trình chỉnh sửa cấp độ - nghĩ đến việc sử dụng một cái gì đó như JME SDK hoặc tự tạo.

Câu trả lời:


9

Tôi nghĩ những gì bạn cần trong trường hợp này là Mẫu thiết kế nhà nước . Thay vì có nhiều phiên bản của mỗi đối tượng trò chơi, hãy tạo một thể hiện duy nhất, nhưng gói gọn hành vi của nó trong một lớp riêng biệt. Tạo nhiều lớp, một lớp cho mỗi hành vi có thể và cung cấp cho tất cả các lớp cùng một giao diện. Liên kết một với đối tượng trò chơi của bạn (trạng thái ban đầu) và khi điều kiện thay đổi (đạt được một mốc quan trọng, thời gian trong ngày trôi qua, v.v.) bạn chuyển trạng thái của đối tượng đó (tức là liên kết nó với một đối tượng khác tùy thuộc vào logic trò chơi của bạn) và cập nhật các thuộc tính của nó nếu có.

Một ví dụ về giao diện trạng thái trông như thế nào (hoàn toàn được tạo ra - chỉ để minh họa mức độ kiểm soát mà sơ đồ này mang lại cho bạn):

interface NPCState {
    Scene whereAmI(NPC o);
    String saySomething(NPC o);
}

Và hai lớp thực hiện:

class Busy implements NPCState {
    Scene whereAmI(NPC o) {
        return o.getWorkScene();
    }
    String saySomething(NPC o) {
        return "Can't talk now, I'm busy!";
    }
}

class Available implements NPCState {
    Scene whereAmI(NPC o) {
        return TAVERN;
    }
    String saySomething(NPC o) {
        String[] choices = o.getRandomChat();
        return choices[RANDOM.getInt(choices.length)];
    }
}

Và chuyển trạng thái:

// The time of day passed from "afternoon" to "evening"
NPCState available = new Available();
for ( NPC o : list ) {
    Scene oldScene = o.state.whereAmI(o);
    o.state = available;
    Scene newScene = o.state.whereAmI(o);
    moveGameObject(o, oldScene, newScene);
    ...

Các NPC quan trọng có thể có trạng thái tùy chỉnh, logic chọn trạng thái có thể tùy chỉnh nhiều hơn và bạn có thể có các trạng thái khác nhau cho các khía cạnh khác nhau của trò chơi (trong ví dụ này, tôi đã sử dụng một lớp duy nhất để nói cả vị trí và trò chuyện, nhưng bạn có thể tách rời chúng và làm nhiều kết hợp).

Điều này cũng hoạt động tốt với các trình soạn thảo cấp độ: bạn có thể có một hộp tổ hợp đơn giản để chuyển trạng thái "toàn cầu" của cấp độ, sau đó thêm và định vị lại các đối tượng trò chơi khi bạn muốn chúng xuất hiện ở trạng thái đó. Công cụ trò chơi sẽ chịu trách nhiệm chỉ thực sự "thêm" đối tượng đó vào cảnh khi nó có trạng thái chính xác - nhưng các tham số của nó vẫn có thể chỉnh sửa theo cách thân thiện với người dùng.

(Tuyên bố miễn trừ trách nhiệm: Tôi có ít kinh nghiệm trong thế giới thực với các biên tập viên trò chơi, vì vậy tôi có thể tự tin nói về cách các biên tập viên chuyên nghiệp làm việc; tài nguyên.)


vâng, bạn có thể kết hợp mẫu thiết kế Bang này với mảng kết hợp mà tôi đã mô tả. Bạn có thể mã hóa các đối tượng trạng thái như được mô tả ở đây, sau đó chọn giữa các đối tượng trạng thái khác nhau bằng cách sử dụng một mảng kết hợp như tôi đề xuất.
jhocking

Tôi đồng ý, cũng tốt khi tách trò chơi khỏi công cụ của nó và logic trò chơi mã hóa tăng cường sự kết hợp giữa chúng (giảm khả năng tái sử dụng). Tuy nhiên, có một sự đánh đổi, vì tùy thuộc vào sự phức tạp của hành vi dự định của bạn khi cố gắng "mã mềm", mọi thứ có thể dẫn đến sự lộn xộn không cần thiết . Trong trường hợp này, một cách tiếp cận hỗn hợp có thể được mong muốn (nghĩa là có logic chuyển đổi trạng thái "chung", nhưng cũng cho phép mã tùy chỉnh được kết hợp)
mgibsonbr

Vì vậy, theo tôi hiểu, có một bản đồ một-một-btwn NPCState và GameState. Sau đó, tôi đặt NPC vào một mảng và lặp lại thông qua nó, gán NPCState mới khi quan sát thấy thay đổi trạng thái trò chơi. NPCState phải có khả năng biết cách xử lý mọi NPC khác nhau được gửi đến nó, vậy về cơ bản NPCState có chứa hành vi của tất cả các NPC cho một trạng thái nhất định không? Tôi thích rằng tất cả các hành vi lưu trữ sạch sẽ trong một NPCState duy nhất, ánh xạ rõ ràng để thực hiện trình chỉnh sửa trò chơi, nhưng điều đó làm cho NPCState khá lớn.
Cardin

Ồ, tôi nghĩ rằng tôi đã hiểu nhầm bạn. Tôi đã thay đổi nó một chút để bao gồm các nhà quan sát. Vì vậy, đó là một NPCState khác nhau cho mọi NPC khác, ngoại trừ những NPC siêu chung như Crowd NPC có thể chia sẻ trạng thái. Đối với mỗi trạng thái trò chơi, NPC sẽ tự đăng ký và NPCState của nó với một Người quan sát. Do đó, Người quan sát sẽ biết chính xác NPC nào được đăng ký để thay đổi hành vi ở trạng thái trò chơi nào và chỉ cần lặp lại qua chúng. Và về phía biên tập viên trò chơi, biên tập viên trò chơi chỉ cần truyền tín hiệu đến Người quan sát để thay đổi trạng thái của toàn bộ cấp độ.
Cardin

1
Vâng, đó là ý tưởng! Các NPC quan trọng sẽ có nhiều trạng thái và quá trình chuyển đổi trạng thái sẽ phụ thuộc chủ yếu vào các cột mốc đã hoàn thành. Đôi khi các NPC chung cũng có thể phản ứng với các mốc quan trọng và thậm chí có trạng thái được chọn phụ thuộc vào một thuộc tính bên trong (giả sử tất cả các NPC có trạng thái ban đầu mặc định và khi bạn nói chuyện với một trong số họ lần đầu tiên anh ta tự giới thiệu, sau đó nhập vào chu kỳ chuyển đổi trạng thái bình thường).
mgibsonbr

2

Các lựa chọn tôi sẽ xem xét là làm cho các đối tượng riêng lẻ phản ứng với các trò chơi khác nhau hoặc phục vụ các cấp độ khác nhau trong các trò chơi khác nhau. Sự lựa chọn giữa hai thứ đó sẽ phụ thuộc vào chính xác những gì tôi đang cố gắng làm trong trò chơi (các trạng thái khác nhau là gì? Làm thế nào để trò chơi chuyển đổi giữa các trạng thái? V.v.)

Dù bằng cách nào, tôi sẽ không làm điều đó bằng cách mã hóa các trạng thái vào mã trò chơi. Thay vì một câu lệnh chuyển đổi lớn trong các đối tượng NPC, tôi sẽ thay vì các hành vi NPC được tải vào một mảng kết hợp từ một tệp dữ liệu và sau đó sử dụng mảng kết hợp đó để chạy các hành vi khác nhau cho các trạng thái liên kết của chúng, đại loại như sau:

if (state in behaviors) {
  behaviors[state]();
}

Tập tin dữ liệu đó có phải là một loại ngôn ngữ scripting không? Tôi nghĩ rằng một tệp dữ liệu văn bản đơn giản có thể không đủ để mô tả hành vi. Ở bất cứ giá nào, bạn đúng rằng nó nên được tải động. Tôi hoàn toàn không thể nghĩ đến việc sử dụng một trình soạn thảo trò chơi để tạo mã Java hợp lệ, nó chắc chắn phải được phân tích cú pháp phần nào.
Cardin

1
Vâng, đó là suy nghĩ ban đầu của tôi, nhưng sau khi thấy câu trả lời của mgibsonbr, tôi nhận ra rằng bạn có thể mã hóa các loại bevavi khác nhau thành các lớp riêng biệt và sau đó trong tệp dữ liệu chỉ cần nói các lớp hành vi đi với trạng thái nào. Tải dữ liệu đó vào một mảng kết hợp trong thời gian chạy.
jhocking

Oh .. Yea chắc chắn đơn giản hơn! : D So với kịch bản nhúng thứ gì đó như Lua haha ​​..
Cardin

2

Điều gì về việc sử dụng một mẫu quan sát để tìm kiếm các thay đổi quan trọng? Nếu một thay đổi xảy ra, một số lớp sẽ nhận ra điều này và xử lý ví dụ một thay đổi phải được thực hiện đối với một npc.

Thay vì mẫu thiết kế trạng thái được đề cập, tôi sẽ sử dụng mẫu chiến lược.

Nếu một npc có n cách để tương tác với các vị trí của nhân vật và m nơi anh ta có thể, thì có tối đa (m * n) +1 lớp bạn phải thiết kế. Sử dụng mô hình chiến lược, bạn sẽ kết thúc với các lớp n + m + 1 nhưng các chiến lược này cũng có thể được sử dụng bởi các npc khác.

Vì vậy, có thể có một lớp xử lý các mốc quan trọng và các lớp quan sát lớp này và xử lý npc hoặc kẻ thù hoặc bất cứ điều gì nên được thay đổi. Nếu các nhà quan sát được cập nhật, họ sẽ quyết định xem họ có phải thay đổi điều gì đó thành các trường hợp mà họ cai trị hay không. Ví dụ, lớp NPC sẽ, trong hàm tạo, thông báo cho NPC-Manager khi anh ta phải cập nhật và những gì phải cập nhật ...


Mẫu Observer có vẻ thú vị. Tôi nghĩ rằng nó có thể để lại tất cả các trách nhiệm với NPC để đăng ký chính nó với người quan sát nhà nước. Mẫu Chiến lược cảm thấy rất giống các hành vi Kích hoạt và AI của Unity Engine, được sử dụng để chia sẻ hành vi của các đối tượng trò chơi khác nhau (tôi nghĩ). Nghe có vẻ khả thi. Tôi không chắc những ưu / nhược điểm hiện tại là gì, nhưng Unity cũng sử dụng phương pháp tương tự cũng phần nào trấn an haha ​​..
Cardin

Tôi chỉ sử dụng hai mẫu này một vài lần để tôi không thể nói cho bạn biết về nhược điểm: - / Nhưng tôi nghĩ rằng nó là tốt trong trường hợp chịu trách nhiệm duy nhất và có sẵn để kiểm tra mọi chiến lược :) Nó có thể gây nhầm lẫn nếu sử dụng một chiến lược trong nhiều lớp khác nhau và bạn muốn tìm mọi lớp sử dụng nó.
TOAOGG

0

Tất cả các phương pháp được đưa ra là hợp lệ. Nó phụ thuộc vào tình huống bạn đang ở bất kỳ thời điểm nào. Nhiều cuộc phiêu lưu hoặc MMO sử dụng kết hợp cả hai.

Ví dụ: nếu một sự kiện quan trọng thay đổi một phần lớn của cấp độ (ví dụ: người đòi nợ sẽ dọn sạch căn hộ của bạn và mọi người trong đó bị bắt), thường sẽ dễ dàng thay thế toàn bộ phòng bằng một phòng thứ hai trông giống nhau.

OTOH, nếu các nhân vật đi quanh bản đồ và làm những việc khác nhau ở những nơi khác nhau, bạn thường có một diễn viên duy nhất xoay qua các đối tượng hành vi khác nhau (Ví dụ: đi thẳng về phía trước / không nói chuyện so với đứng ở đây / nói về cái chết của Mitch), có thể bao gồm "Ẩn" nếu mục đích của họ đã được thực hiện.

Điều đó nói rằng, thường có các bản sao của một đối tượng mà bạn tạo thủ công sẽ không gây ra bất kỳ vấn đề nào. Bạn có thể tạo bao nhiêu đối tượng? Nếu bạn có thể tạo nhiều đối tượng hơn trò chơi của mình có thể lặp lại, hãy nhìn vào thuộc tính "ẩn" của chúng và bỏ qua, công cụ của bạn quá chậm. Vì vậy, tôi sẽ không lo lắng về điều đó quá nhiều. Nhiều trò chơi trực tuyến thực sự làm điều này. Một số nhân vật hoặc vật phẩm luôn ở đó, nhưng không được hiển thị cho các nhân vật không có nhiệm vụ tương ứng.

Bạn thậm chí có thể kết hợp các phương pháp: Có hai cửa trong tòa nhà chung cư của bạn. Một dẫn đến căn hộ "trước người đòi nợ", một đến căn hộ sau. Khi bạn đi vào hành lang, chỉ có một cái áp dụng cho sự tiến triển của bạn trong câu chuyện mới thực sự được hiển thị. Bằng cách đó, bạn có thể có một cơ chế chung cho "mục có thể nhìn thấy tại điểm hiện tại trong câu chuyện" và một cánh cửa với một điểm đến duy nhất. Thay phiên, bạn có thể tạo ra những cánh cửa phức tạp hơn có thể có những hành vi có thể bị tráo đổi, và một trong số đó là "đi đến căn hộ đầy đủ", còn lại là "đi đến căn hộ trống". Điều này có vẻ vô lý nếu thực sự chỉ là điểm đến của cánh cửa thay đổi, nhưng nếu diện mạo của nó cũng thay đổi (ví dụ: một khóa lớn ở phía trước cánh cửa mà trước tiên bạn phải bẻ khóa),

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.