Làm thế nào tôi có thể thiết kế nhiều loại tấn công khác nhau có thể được kết hợp?


17

Tôi đang tạo một trò chơi 2D từ trên xuống và tôi muốn có nhiều kiểu tấn công khác nhau. Tôi muốn làm cho các cuộc tấn công trở nên rất linh hoạt và có thể kết hợp theo cách mà Binding of Isaac hoạt động. Đây là danh sách tất cả các đồ sưu tầm trong trò chơi . Để tìm một ví dụ hay, hãy xem mục Spoon Bender .

Spoon Bender mang đến cho Isaac khả năng bắn nước mắt.

Nếu bạn nhìn vào phần "hiệp lực", bạn sẽ thấy nó có thể được kết hợp với các bộ sưu tập khác để có hiệu ứng thú vị nhưng trực quan. Ví dụ: nếu nó kết hợp với Mắt trong , thì "Sẽ cho phép Isaac bắn nhiều phát đạn cùng một lúc". Điều này có ý nghĩa, bởi vì Mắt trong

Cung cấp cho Isaac một cú đúp

Một kiến ​​trúc tốt để thiết kế những thứ như thế này là gì? Đây là một giải pháp vũ phu:

if not spoon bender and not the inner eye then ...
if spoon bender and not the inner eye then ...
if not spoon bender and the inner eye then ...
if spoon bender and the inner eye then ...

Nhưng điều đó sẽ ra khỏi tầm tay rất nhanh. Cách tốt hơn để thiết kế một hệ thống như thế này là gì?


Cá nhân tôi sẽ chỉ giữ tất cả các mục được trang bị trong một danh sách và để chúng thực hiện một số loại giao diện chung có một đối tượng bạn biến đổi từ đối tượng này sang đối tượng khác. "cho mỗi vật phẩm sửa đổi cuộc tấn công theo kế hoạch" để một vật phẩm có thể nhân đôi lượng đạn, một vật phẩm có thể thêm màu sắc và thay đổi thiệt hại (vì vậy nếu một vật phẩm tạo ra bu lông đỏ và một vật phẩm khác có màu vàng, bạn sẽ có một cuộc tấn công màu cam sau khi cả hai sửa đổi cuộc tấn công) . Bạn cũng có thể chỉ có một lớp vật phẩm chung có các tham số để quyết định cách nó sửa đổi cuộc tấn công theo kế hoạch.
Benjamin Danger Johnson

2
Tôi muốn chỉ ra rằng Kirby 64 đã sử dụng phương pháp vũ phu và các hiệu ứng khác nhau được lập trình cứng cho tất cả các khả năng kết hợp có thể, vì vậy điều đó là có thể.
Kevin - Tái lập Monica

Câu trả lời:


16

Bạn hoàn toàn không cần kết hợp mã tay. Thay vào đó, bạn có thể tập trung vào các thuộc tính mà mỗi mục cung cấp cho bạn. Chẳng hạn, mục A đặt Projectile=Fireball,Targetting=Homing. Mục B bộ FireMode=ArcShot,Count=3. Các ArcShotlogic là trách nhiệm gửi ra Countsố Projectilemục trong một vòng cung.

Hai mục này có thể được kết hợp với bất kỳ mục nào khác có thể sửa đổi các thuộc tính này (hoặc khác) một cách tự do. Nếu bạn thêm một loại đạn mới, nó sẽ tự động hoạt động ArcShotvà nếu bạn thêm chế độ bắn mới, nó sẽ tự động hoạt động với Fireballcác viên đạn. Tương tự như vậy, Targettinglà một thuộc tính đặt bộ điều khiển cho các viên đạn trong khi FireModetạo các viên đạn, do đó chúng có thể được kết hợp dễ dàng và tầm thường trong bất kỳ kết hợp nào có ý nghĩa.

Bạn cũng có thể thiết lập các phụ thuộc tài sản và như vậy. Chẳng hạn, ArcShotyêu cầu bạn phải có nhà cung cấp Projectile(có thể chỉ là mặc định). Bạn có thể đặt mức độ ưu tiên để nếu bạn có hai mục hoạt động, cả hai đều cung cấp Projectilemã sẽ biết nên sử dụng mục nào. Hoặc bạn có thể cung cấp giao diện người dùng để cho phép người dùng chọn loại đạn nào sẽ sử dụng hoặc đơn giản yêu cầu người chơi hủy bỏ các mục ưu tiên cao mà anh ta không muốn hoặc sử dụng mục gần đây nhất, v.v. Bạn có thể cho phép thêm một hệ thống không tương thích , ví dụ như hai mục vừa sửa đổi Projectilekhông thể được trang bị đồng thời.

Nói chung, khi có thể, thích bất kỳ cách tiếp cận dựa trên dữ liệu (hoặc khai báo ) nào hơn các cách tiếp cận theo thủ tục (nếu điều khác xảy ra nếu có khác) khi nói đến các đối tượng và như vậy trong trò chơi của bạn. Logic chung cấp cao hơn có thể định cấu hình bằng dữ liệu đơn giản sẽ được ưu tiên hơn nhiều so với các danh sách quy tắc được mã hóa cứng.


Nit nhỏ, nhưng dường như bạn không có thuộc tính chính xác cho các ví dụ bạn đang sử dụng. "Spoon Bender" thêm homing và "Inside Eye" thêm ba lần bắn. Không thêm hồ quang và cả hai đều là nước mắt. Nếu bạn đang sử dụng các thuộc tính tùy ý trong ví dụ của mình để trừu tượng hóa thiết kế, sẽ dễ đọc hơn nếu chúng không được đặt tên theo cách gây hiểu lầm. Tôi thích "Mục A" và "Mục B" hơn thế này.
Daniel Kaplan

1
@tieTYT: Tôi đã khái quát các tên và mở rộng ví dụ để bao gồm các chế độ nhắm mục tiêu ngoài các loại đạn và chế độ bắn. Chưa bao giờ chơi BoI trong hơn một vài phút vì vậy tôi không có tên nào được nội hóa như những cái khác. :)
Sean Middleditch

Dường như với tôi rằng phần khó khăn là xác định các loại tài sản. ví dụ: Nhắm mục tiêu là một, FireMode là khác, Count có thể là thứ 3 ... hoặc có thể không. Có thể 3 quả đạn có thể là một quả cầu lửa và 5 quả có thể là lựu đạn mặc dù đó là một vũ khí.
Daniel Kaplan

@tieTYT: hoàn toàn. Bạn có thể mở rộng hệ thống hơn nữa để cho phép các kết hợp đặc biệt hoặc logic, chắc chắn, nhưng đó phải là ngoại lệ chứ không phải là quy tắc. Tối ưu hóa cho trường hợp phổ biến, không phải trường hợp góc.
Sean Middleditch

Dưới đây là một video tuyệt vời về việc tại sao bạn sai đang liên quan đến lập trình thủ tục youtu.be/QM1iUe6IofM , cũng là dữ liệu điều khiển cách bạn mô tả bản đồ bất kỳ nếu / khối khác vào bộ dữ liệu cá nhân, về cơ bản không làm gì để giảm bao nhiêu đặc biệt trường hợp kịch bản bạn phải chương trình, vì bạn phải lập trình tất cả ...
RenaissanceProgrammer

8

Nếu bạn đang sử dụng ngôn ngữ OOP, thì đây có vẻ là một nơi tốt để sử dụng Mẫu trang trí . Khi bạn muốn sửa đổi cách thức một cuộc tấn công xảy ra, chỉ cần trang trí nó với sự gia tăng thích hợp.

Ví dụ c ++ thô:

class AttackBehaviour
{
    /* other code */
    virtual void Attack(double angle);
};

class TearAttack: public AttackBehaviour
{
    /* other code */
    void Attack(double angle);
};

class TripleAttack: public AttackBehaviour
{
    /* other code */
    AttackBehaviour* baseAttackBehaviour;
    void Attack(double angle);
};

void TripleAttack::Attack(angle)
{
    baseAttackBehaviour->Attack(angle-30);
    baseAttackBehaviour->Attack(angle);
    baseAttackBehaviour->Attack(angle+30);
}

Phương pháp này sẽ là tốt nhất nếu bạn có một số lượng lớn các cuộc tấn công và bạn cần phải thực hiện tất cả chúng theo cách tương tự. Nếu bạn muốn thay đổi đáng kể cách thức tấn công xảy ra với công cụ sửa đổi (ví dụ: hoạt hình mới với công cụ sửa đổi) thì phương pháp này không dành cho bạn.


Nếu tôi muốn thay đổi hình ảnh động, tại sao điều này không dành cho tôi? Ngoài ra, nếu tôi đang làm việc trong một ngôn ngữ chức năng hơn thì sao? Bạn có biết một mẫu thiết kế phù hợp với họ không?
Daniel Kaplan

Nó cứng nhắc hơn bởi vì công cụ sửa đổi sẽ luôn luôn gọi Attackphương thức của đối tượng mà nó tổng hợp. Các TripleAttacklớp không nên biết về TearAttacklớp. Nếu điều này là đúng thì nó sẽ dẫn đến nhiều vấn đề đau đầu như else-ifkhối. Điều này có nghĩa là bất kỳ hình ảnh động xé phải nằm trong TearAttackBehaviourđối tượng. Đối tượng này không (và không nên) biết nó được trang trí bởi một TripleAttackđối tượng. Kết quả là 3 hình ảnh động rách tiến hành một cách độc lập, vì độc lập.
Na hảiMile

Tôi đang gặp khó khăn khi giải thích điều này bằng lời, nếu ai đó muốn đâm vào nó, hãy làm khách của tôi.
Na hảiMile

Đối với việc thực hiện điều này bằng một ngôn ngữ chức năng hơn, tôi sẽ suy nghĩ về nó trong một thời gian và sửa đổi câu trả lời của tôi khi tôi đã sẵn sàng.
Na hảiMile

1

Là một fan hâm mộ của Binding of Isaac, tôi cũng đã tự hỏi làm thế nào để đi về một cái gì đó như thế này. Hệ thống trong trò chơi đủ mạnh mẽ, nơi các hành vi mới nổi xuất phát từ sự kết hợp của các hiệu ứng (cái mà tôi nghĩ đến là lấy gương, thìa uốn cong và một số tên lửa đẩy phạm vi dẫn đến một bức tường xé rách, xoáy quanh Isaac, Magneto ). Số lượng tuyệt đối của chúng sẽ làm cho khối "nếu" không thực tế.

Kết luận của tôi là Isaac và những giọt nước mắt của anh ấy là hai thực thể ở trung tâm của Khung thành phần thực thể khổng lồ . Các thực thể có một số chỉ số cơ bản (di chuyển, tuổi thọ, phạm vi, thiệt hại, sprite, v.v.) và mỗi thành phần sẽ mang theo một công cụ sửa đổi chỉ số và một động từ.

Trong mã, Isaac và những giọt nước mắt của anh ấy sẽ có một danh sách chứa những thứ của một giao diện. Isaac sẽ có một danh sách những thứ đăng ký vào giao diện IsaacMutator, và giọt nước mắt của anh ấy. IsaacMutator sẽ có các chức năng để sửa đổi sức khỏe, tốc độ, phạm vi, ngoại hình và một số động từ đặc biệt của Isaacs. TearMutator sẽ tương tự. Mỗi lần lặp lại trò chơi, Isaac sẽ lặp lại tất cả các IsaacMutators mà nó có, và tất cả những giọt nước mắt sống cũng vậy. Để đi theo ví dụ tiếng Anh của bạn, nó sẽ đọc như sau:

Isaac has IsaacMutators:
--spoonbender which gives no stat change and: Tears are made homing
--MeatEater which give +1 health, +1 damage and: nothing
--MagicMirror which gives no stat change and: Tears are made reflecting

Tears have tearMutators:
--(depends on MeatEater) +1 damage and: nothing
--(depends on MagicMirror) no stat change and: +1 vector towards isaac
--(depnds on spoonbender) no stat change and: +1 vector towards enemytype

và như thế. Bởi vì các loại là phụ gia, bạn có thể xếp chồng và thêm và xóa vào nội dung trái tim của bạn.


-5

Tôi nghĩ rằng cách của bạn làm việc tốt nhất. Mỗi loại vật phẩm này cung cấp một điều kiện, nếu được sử dụng cùng nhau, chúng tạo ra một điều kiện khác nhau, thì bạn thực sự cần cả 3 điều kiện có thể được xác định.

Bạn cũng có thể thực hiện bằng cách tạo một loại định nghĩa mới khi có cả hai mục, nhưng điều này thực sự bổ sung cho tích chập:

if spoon bender and the inner eye then new spoon bender inner eye

if spoon bender inner eye then ...
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.