Trình phân tích quy tắc chung cho các quy tắc trò chơi bảng RPG - làm thế nào để làm điều đó?


19

Tôi muốn xây dựng một trình phân tích cú pháp chung cho các hệ thống RPG kiểu bút và giấy. Một quy tắc có thể thường liên quan đến 1 đến N thực thể 1 đến N vai trò của súc sắc và tính toán các giá trị dựa trên nhiều thuộc tính của một thực thể.

Ví dụ:

Người chơi có STR 18, vũ khí hiện đang được trang bị của anh ta mang lại cho anh ta phần thưởng +1 STR nhưng là một con số DEX -1. Anh ta tấn công một thực thể quái vật và logic trò chơi bây giờ được yêu cầu để chạy một bộ quy tắc hoặc hành động:

Người chơi tung xúc xắc, nếu anh ta lấy ví dụ 8 trở lên (giá trị tấn công cơ bản anh ta cần vượt qua là một trong những thuộc tính cơ bản của anh ta!) Thì cuộc tấn công của anh ta rất thành công. Con quái vật sau đó tung xúc xắc để tính toán nếu cuộc tấn công xuyên qua lớp giáp của nó. Nếu có, thiệt hại được thực hiện nếu không cuộc tấn công đã bị chặn.

Bên cạnh các quy tắc toán học đơn giản cũng có thể có các ràng buộc như chỉ áp dụng cho một lớp người dùng nhất định (ví dụ: chiến binh vs thuật sĩ) hoặc bất kỳ thuộc tính nào khác. Vì vậy, điều này không chỉ giới hạn trong các hoạt động toán học.

Nếu bạn quen thuộc với các hệ thống RPG như Dungeon và Dragons, bạn sẽ biết tôi đang làm gì.

Vấn đề của tôi bây giờ là tôi không biết làm thế nào để xây dựng chính xác cách này tốt nhất có thể. Tôi muốn mọi người có thể thiết lập bất kỳ loại quy tắc nào và sau đó chỉ cần thực hiện một hành động như chọn người chơi và quái vật và chạy một hành động (thiết lập các quy tắc như một cuộc tấn công).

Tôi đang yêu cầu ít sự giúp đỡ hơn về phía cơ sở dữ liệu nhưng nhiều hơn về cách đưa ra cấu trúc và trình phân tích cú pháp để giữ cho quy tắc của tôi linh hoạt. Bằng cách này, ngôn ngữ được lựa chọn là php.

Chỉnh sửa tôi:

Hãy để tôi tinh chỉnh mục tiêu của mình: Tôi muốn tạo một giao diện thân thiện với người dùng (không yêu cầu ai đó phải học ngôn ngữ lập trình) để xây dựng các quy tắc trò chơi phức tạp hơn hoặc ít phức tạp hơn. Lý do đơn giản: Sử dụng cá nhân để không cần phải nhớ tất cả các quy tắc mọi lúc, chúng tôi chỉ đơn giản là không chơi thường xuyên và đó là một nút chặn để tìm kiếm chúng mỗi lần. Ngoài ra: Trông giống như một nhiệm vụ thú vị để làm và học một cái gì đó. :)

Những gì tôi đã thử cho đến nay: Chỉ nghĩ về một khái niệm thay vì lãng phí thời gian xây dựng một kiến ​​trúc sai. Cho đến nay tôi có ý tưởng cho phép người dùng tạo ra nhiều thuộc tính như họ muốn và sau đó gán bao nhiêu thuộc tính mà họ muốn cho bất kỳ loại thực thể nào. Một thực thể có thể là một người chơi, một con quái vật, một vật phẩm, bất cứ thứ gì. Bây giờ khi tính toán một cái gì đó, dữ liệu được cung cấp cho trình phân tích quy tắc để trình phân tích quy tắc có thể thực hiện những việc như nếu Player.base_attack + dice (1x6)> Monster.armor_check rồi Monster.health - 1; Câu hỏi ở đây là về cách tạo trình phân tích cú pháp đó.

Chỉnh sửa II:

Dưới đây là một ví dụ về giá trị khá cơ bản nhưng để tính toán chính xác, có rất nhiều điều và biến khác nhau cần tính đến:

Phần thưởng tấn công cơ bản (Thuật ngữ) Phần thưởng tấn công cơ sở của bạn (thường được gọi là BAB bởi cộng đồng d20) là phần thưởng cuộn tấn công xuất phát từ cấp độ và cấp độ nhân vật. Phần thưởng tấn công cơ bản tăng ở các tỷ lệ khác nhau cho các lớp nhân vật khác nhau. Một nhân vật nhận được đòn tấn công thứ hai mỗi vòng khi phần thưởng tấn công cơ bản của anh ta đạt +6, phần ba với phần thưởng tấn công cơ bản là +11 hoặc cao hơn và phần tư với phần thưởng tấn công cơ bản là +16 hoặc cao hơn. Phần thưởng tấn công cơ bản thu được từ các lớp khác nhau, chẳng hạn như cho một nhân vật đa giác, ngăn xếp. Phần thưởng tấn công cơ bản của một nhân vật không cấp thêm bất kỳ đòn tấn công nào sau khi đạt +16, không thể nhỏ hơn +0 và không tăng do cấp độ lớp sau khi cấp độ nhân vật đạt đến 20. Một phần thưởng tấn công cơ sở tối thiểu là cần thiết cho một số chiến công nhất định.

Bạn có thể đọc nó ở đây http://www.dandwiki.com/wiki/Base_Attack_Bonus_(Term) bao gồm các liên kết đến các lớp và chiến công có quy tắc riêng để tính các giá trị cần thiết cho cuộc tấn công cơ sở.

Tôi bắt đầu nghĩ rằng việc giữ nó càng chung chung càng tốt cũng sẽ khiến cho việc phân tích quy tắc tốt được thực hiện khá khó khăn.



2
Tôi thực sự đã suy nghĩ về chính xác loại vấn đề này sáng nay (không liên quan đến RPG, nhưng công cụ xử lý quy tắc) và cố gắng nghĩ về cách tiếp cận máy phi trạng thái để xử lý quy tắc và cách trình phân tích cú pháp kết hợp rất hiệu quả trong việc hoàn thành một nhiệm vụ thường được thực hiện bởi máy nhà nước. Tôi nghĩ rằng có nhiều khả năng cho các tổ hợp đơn nguyên tiếp cận hầu hết các vấn đề máy móc nhà nước sạch sẽ hơn. Điều đó nghe có vẻ vô nghĩa nhưng tôi nghĩ có ý tưởng này, chỉ 2 xu của tôi. Hệ thống RPG là một vấn đề thực hành thú vị kinh điển mà tôi thích mã hóa, có lẽ tôi sẽ thử phương pháp này.
Jimmy Hoffa

1
@jk. bài viết đó nhắc nhở tôi về một mẫu mà tôi thích để phân tích đối số chương trình dòng lệnh, sử dụng một từ điển Funcs để khởi tạo trạng thái chương trình dựa trên các đối số làm khóa cho từ điển. Ngạc nhiên là tôi chưa bao giờ thấy bài đăng đó từ Yegge trước đây, rất tuyệt, cảm ơn vì đã chỉ ra nó.
Jimmy Hoffa

4
Tôi không thực sự chắc chắn tại sao điều này được đóng lại là "không phải là một câu hỏi thực sự". Đây là một câu hỏi "bảng trắng" ở cấp độ cao hơn về cách kiến ​​trúc một ứng dụng có một bộ yêu cầu cụ thể (hệ thống quy tắc RPG). Tôi đã bỏ phiếu để mở lại nó, nhưng nó vẫn sẽ cần 4 phiếu mở lại khác để được mở lại.
Rachel

1
Thành thật tôi nghĩ rằng trang web này là chính xác cho loại câu hỏi khái niệm này trong khi stackoverflow.com được cho là cho các vấn đề về mã / triển khai.
burzum

Câu trả lời:


9

Những gì bạn đang yêu cầu về cơ bản là một ngôn ngữ dành riêng cho tên miền, một ngôn ngữ lập trình nhỏ cho mục đích hẹp, trong trường hợp này là xác định quy tắc RPG của P & P. Thiết kế một ngôn ngữ về nguyên tắc không khó, nhưng có một lượng kiến ​​thức đáng kể mà bạn phải đạt được để có thể làm việc hiệu quả. Thật không may, không có tài liệu tham khảo trung tâm nào cho công cụ này mà bạn phải chọn nó thông qua bản dùng thử, lỗi và rất nhiều nghiên cứu.

Đầu tiên, tìm một tập hợp các hoạt động nguyên thủy, theo đó các hoạt động khác có thể được thực hiện. Ví dụ:

  • Nhận hoặc đặt thuộc tính của người chơi, NPC hoặc quái vật

  • Nhận kết quả của một cuộn chết

  • Đánh giá các biểu thức số học

  • Đánh giá biểu thức điều kiện

  • Thực hiện phân nhánh có điều kiện

Thiết kế một cú pháp thể hiện nguyên thủy của bạn. Làm thế nào bạn sẽ đại diện cho số? Một tuyên bố trông như thế nào? Là tuyên bố dấu chấm phẩy chấm dứt? Dòng mới chấm dứt? Có cấu trúc khối? Làm thế nào bạn sẽ chỉ ra nó: thông qua các biểu tượng hoặc thụt đầu dòng? Có biến không? Cái gì tạo thành một tên biến hợp pháp? Là các biến có thể thay đổi? Làm thế nào bạn sẽ truy cập thuộc tính của các đối tượng? Là đối tượng hạng nhất? Bạn có thể tự tạo chúng không?

Viết một trình phân tích cú pháp biến chương trình của bạn thành một cây cú pháp trừu tượng (AST). Tìm hiểu về phân tích cú pháp với trình phân tích cú pháp gốc đệ quy. Tìm hiểu về cách phân tích các biểu thức số học với gốc đệ quy gây khó chịu và trình phân tích cú pháp ưu tiên toán tử từ trên xuống (trình phân tích cú pháp Pratt) có thể làm cho cuộc sống của bạn dễ dàng hơn và mã của bạn ngắn hơn.

Viết một thông dịch viên đánh giá AST của bạn. Nó chỉ đơn giản có thể đọc từng nút trong cây và thực hiện những gì nó nói: a = btrở new Assignment("a", "b")thành vars["a"] = vars["b"];. Nếu nó làm cho cuộc sống của bạn dễ dàng hơn, hãy chuyển đổi AST thành một hình thức đơn giản hơn trước khi đánh giá.

Tôi khuyên bạn nên thiết kế những thứ đơn giản nhất sẽ hoạt động và vẫn có thể đọc được. Đây là một ví dụ về ngôn ngữ có thể trông như thế nào. Thiết kế của bạn sẽ nhất thiết phải khác nhau dựa trên nhu cầu và sở thích cụ thể của bạn.

ATK = D20
if ATK >= player.ATK
    DEF = D20
    if DEF < monster.DEF
        monster.HP -= ATK
        if monster.HP < 0
            monster.ALIVE = 0
        end
    end
end

Ngoài ra, hãy tìm hiểu cách nhúng ngôn ngữ kịch bản lệnh hiện có như Python hoặc Lua vào ứng dụng của bạn và sử dụng ngôn ngữ đó. Nhược điểm của việc sử dụng ngôn ngữ có mục đích chung cho một nhiệm vụ cụ thể theo miền là sự trừu tượng bị rò rỉ: tất cả các tính năng và vấn đề của ngôn ngữ vẫn còn tồn tại. Ưu điểm là bạn không phải tự mình thực hiện nó và đó là một nhược điểm đáng kể. Hãy xem xét nó.


2
Không phải là một cách tiếp cận tồi nhưng tôi luôn nghi ngờ về DSL, họ có rất nhiều việc phải làm (đặc biệt là nếu bạn đang nói về một DSL thực sự với cú pháp tùy chỉnh và tất cả, trái ngược với một số API thông thạo mà mọi người có đã bắt đầu gọi "DSL", vì vậy bạn nên chắc chắn rằng mình sẽ sử dụng cái quái gì đó, nếu bạn thì nó cũng đáng. Thông thường tôi nghĩ mọi người muốn thử DSL trong đó họ sẽ chỉ sử dụng nó cho một công cụ quy tắc nhỏ. Đây là quy tắc của tôi: Nếu việc triển khai + sử dụng DSL ít mã hơn không có DSL, hãy thực hiện nó, tôi không nghĩ rằng điều đó sẽ xảy ra trong trường hợp này.
Jimmy Hoffa

1
@JimmyHoffa: Đủ công bằng. Bản chất của tôi là tiếp cận các giải pháp dựa trên ngôn ngữ, đặc biệt là các trò chơi. Tôi có lẽ đánh giá thấp sự khó khăn của việc tạo ra một cái gì đó nhỏ và chức năng bởi vì tôi đã làm nó nhiều lần. Tuy nhiên, có vẻ như một khuyến nghị thích hợp trong trường hợp này.
Jon Purdy

Tôi đoán tôi nên nói rằng đó là cách tiếp cận đúng đắn cho loại vấn đề này, nhưng điều đó được khẳng định dựa trên người thực hiện là một người có đủ kỹ năng. Đối với việc học, DSL rất tốt cho đàn em, nhưng đối với sản phẩm đáng tin cậy thực tế, tôi sẽ không bao giờ muốn thấy bất kỳ ai dưới cấp cao viết DSL, và đối với một thiếu niên, một vấn đề có thể giải quyết DSL phải được giải quyết theo một cách khác.
Jimmy Hoffa

Sau khi đọc nó, tôi nghĩ rằng tôi có thể chỉ đơn giản là eval lua script cho điều đó. Nhược điểm ở đây là người dùng phải có khả năng viết các tập lệnh lua. Mục tiêu cá nhân của tôi là viết một giao diện có thể được sử dụng mà không cần kiến ​​thức lập trình, như trình xây dựng quy tắc trong magento (ứng dụng thương mại điện tử). Bởi vì tôi muốn mọi người có thể thêm các quy tắc riêng của họ. Tôi không triển khai bất cứ thứ gì thương mại, chỉ là một công cụ để cho tôi và bạn bè của tôi tham gia vào các quy tắc của hệ thống RPG, chúng tôi chơi trên một cơ sở bất thường và trở lại các quy tắc và áp dụng chúng là một nỗi đau sau một thời gian ...
burzum

1
@burzum: Điều gì về việc giao diện của bạn tạo ra các tập lệnh lua?
TMN

3

Tôi sẽ bắt đầu bằng cách xác định các "Giai đoạn" khác nhau của mỗi hành động.

Ví dụ: Giai đoạn chiến đấu có thể bao gồm:

GetPlayerCombatStats();
GetEnemyCombatStats();
GetDiceRoll();
CalculateDamage();

Mỗi phương thức này sẽ có quyền truy cập vào một số đối tượng khá chung chung, chẳng hạn như PlayerMonster, và sẽ thực hiện một số kiểm tra khá chung chung mà các thực thể khác có thể sử dụng để sửa đổi các giá trị.

Ví dụ: bạn có thể có một cái gì đó trông giống như điều này được bao gồm trong GetPlayerCombatStats()phương thức của bạn :

GetPlayerCombatStats()
{
    Stats tempStats = player.BaseStats;

    player.GetCombatStats(player, monster, tempStats);

    foreach(var item in Player.EquippedItems)
        item.GetCombatStats(player, monster, tempStats);
}

Điều này cho phép bạn dễ dàng thêm vào bất kỳ thực thể nào bằng các quy tắc cụ thể, chẳng hạn như Lớp Người chơi, quái vật hoặc Thiết bị.

Một ví dụ khác, giả sử bạn muốn có Kiếm Giết mọi thứ trừ Mực , thứ mang lại cho bạn 4 điểm so với mọi thứ, trừ khi thứ đó có xúc tu, trong trường hợp đó bạn phải thả thanh kiếm của mình xuống và nhận được -10 trong trận chiến.

Lớp trang bị của bạn cho thanh kiếm này có thể có một GetCombatStatsthứ trông như thế này:

GetCombatStats(Player player, Monster monster, Stats tmpStats)
{
    if (monster.Type == MonsterTypes.Tentacled)
    {
        player.Equipment.Drop(this);
        tmpStats.Attack -= 10;
    }
    else
    {
        tmpStats.Attack += 4;
    }
}

Điều này cho phép bạn dễ dàng sửa đổi các giá trị chiến đấu mà không cần biết về phần còn lại của logic chiến đấu và nó cho phép bạn dễ dàng thêm các phần mới vào ứng dụng vì chỉ có các chi tiết và logic triển khai của Thiết bị (hoặc bất kỳ thực thể nào) cần tồn tại trong chính lớp thực thể.

Điều quan trọng để tìm ra là điểm nào có thể thay đổi giá trị và yếu tố nào ảnh hưởng đến các giá trị đó. Một khi bạn có những thứ đó, việc xây dựng các thành phần riêng lẻ của bạn sẽ trở nên dễ dàng :)


Đó là con đường để đi. Trong hầu hết các game nhập vai Bút & Giấy, có các giai đoạn trong tính toán, thường được viết trong sách hướng dẫn. Bạn cũng có thể đặt thứ tự của giai đoạn trong một danh sách được sắp xếp để làm cho nó chung chung hơn.
Hakan Deryal

Điều này nghe có vẻ khá tĩnh đối với tôi và không cho phép người dùng chỉ cần nhập / xây dựng các quy tắc bắt buộc trong UI? Những gì bạn mô tả âm thanh giống như quy tắc mã hóa cứng. Điều này cũng có thể được thực hiện bằng cách có một danh sách các quy tắc lồng nhau. Tôi không muốn mã hóa bất kỳ quy tắc nào. Nếu tôi có thể làm mọi thứ trong mã, tôi sẽ không cần phải hỏi câu hỏi đó, điều đó sẽ dễ dàng. :)
burzum

@burzum Có, điều này có nghĩa là các quy tắc sẽ được xác định bởi mã, tuy nhiên nó làm cho nó rất mở rộng từ mã. Ví dụ, nếu bạn muốn thêm một loại Class mới hoặc một mảnh Trang bị mới hoặc một loại Monster mới, bạn chỉ cần xây dựng các đối tượng lớp cho thực thể đó và điền vào các phương thức thích hợp trong lớp của bạn bằng logic của bạn.
Rachel

@burzum Mình mới đọc bản chỉnh sửa cho câu hỏi của bạn. Nếu bạn muốn có một công cụ quy tắc chỉ cho giao diện người dùng sử dụng, tôi sẽ xem xét thực hiện một hồ bơi của các tổ chức ( Player, Monster, Dice, vv), và thiết lập một cái gì đó cho phép người dùng để miếng thực thể kéo / thả vào một khu vực "phương trình", điền vào các thông số của thực thể (chẳng hạn như điền vào player.base_attack) và chỉ định các toán tử đơn giản như cách các phần khớp với nhau. Tôi thực sự có một cái gì đó được đăng trên blog của tôi phân tích một phương trình toán học mà bạn có thể có thể sử dụng.
Rachel

@Rachel những gì bạn mô tả là OOP dễ chết, thậm chí có nhiều ví dụ ngoài tự nhiên sử dụng RPG như công cụ làm ví dụ để dạy OOP. Có những đối tượng này và làm việc với chúng là phần dễ dàng, tôi có thể xây dựng chúng một cách nhanh chóng dựa trên dữ liệu từ cơ sở dữ liệu. Vấn đề trong cách tiếp cận của bạn là các quy tắc cứng như GetEnemyCombatStats () bất cứ điều gì phương thức này cần phải được xác định ở đâu đó thông qua UI và được lưu trữ trong db. Bài viết của bạn có vẻ giống với github.com/bobthecow/Ruler hoặc github.com/Trismegiste/PhpRules .
burzum

0

Tôi sẽ xem maptool cụ thể là khung ed thứ 4 của Rumble . Đó là hệ thống tốt nhất tôi từng thấy để thiết lập những gì bạn đang nói. Thật không may, tốt nhất vẫn là khủng khiếp khủng khiếp. Hệ thống "vĩ mô" của họ đã ... giả sử ... phát triển theo thời gian.

Đối với một "trình phân tích quy tắc", tôi chỉ cần sử dụng bất kỳ ngôn ngữ lập trình nào mà bạn thấy thoải mái, ngay cả khi đó là PHP. Sẽ không có cách nào tốt để mã hóa tất cả các quy tắc của hệ thống của bạn.

Bây giờ, nếu bạn muốn người dùng của mình có thể viết quy tắc THEIR OWN, thì bạn đang xem việc thực hiện ngôn ngữ kịch bản lệnh của riêng bạn. Người dùng kịch bản các hành động cấp cao của riêng họ, php của bạn diễn giải thành một thứ thực sự ảnh hưởng đến các giá trị cơ sở dữ liệu, và sau đó nó sẽ gây ra một loạt lỗi vì đó là một hệ thống tồi tệ khủng khiếp đã bị cắm sừng trong nhiều năm. Thực sự, câu trả lời của Jon Purdy là đúng trên quả bóng.


0

Tôi nghĩ rằng bạn cần có khả năng suy nghĩ trừu tượng về những gì sẽ xảy ra trong không gian vấn đề của bạn, đưa ra một số mô hình và sau đó dựa trên DSL của bạn.

Ví dụ: bạn có thể có thực thể, hành động và sự kiện ở cấp cao nhất. Die roll sẽ là sự kiện xảy ra như là kết quả của hành động. Các hành động sẽ có các điều kiện để xác định xem chúng có khả dụng trong một tình huống nhất định hay không và "kịch bản" của những điều xảy ra khi hành động được thực hiện. Những điều phức tạp hơn sẽ là khả năng xác định một chuỗi các pha trong đó các hành động khác nhau có thể xảy ra.

Khi bạn có một số mô hình khái niệm (và tôi khuyên bạn nên viết nó xuống và / hoặc vẽ sơ đồ để thể hiện nó), bạn có thể bắt đầu xem xét các phương tiện khác nhau để thực hiện nó.

Một lộ trình là xác định cái được gọi là DSL bên ngoài nơi bạn xác định cú pháp của mình và sử dụng một công cụ như antlr để phân tích cú pháp và gọi logic của bạn. Một lộ trình khác là sử dụng các phương tiện có trong ngôn ngữ lập trình để xác định DSL của bạn. Các ngôn ngữ như Groovy và Ruby đặc biệt tốt trong không gian này.

Một cái bẫy bạn cần tránh là trộn logic hiển thị của bạn với mô hình trò chơi đã triển khai của bạn. Tôi sẽ bỏ phiếu để màn hình đọc mô hình của bạn và hiển thị một cách thích hợp thay vì trộn mã hiển thị xen kẽ với mô hình của bạn.

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.