Làm thế nào tôi có thể cải thiện việc thực hiện cơ sở dữ liệu kẻ thù này?


7

Tôi đang phát triển một game nhập vai và tôi đang ở điểm cần bắt đầu xây dựng cơ sở dữ liệu về kẻ thù. Có một vài thách thức liên quan đến vấn đề này và một vài giải pháp tôi đã xem xét.

Đây là những gì tôi cần làm trong cơ sở dữ liệu kẻ thù của mình:

Tôi có hai lớp kẻ thù chính mà tôi cần để trình bày dữ liệu về:

Một lớp kẻ thù cơ sở bao gồm:

Base Stats
Status Resistance Table
Elemental Resistance Table
Steal Table
Drop Table
Level
Unique ID
Base XP
AI Hook
Name
Display Name

Và một lớp dẫn xuất có thêm khả năng thêm thiết bị, thêm các trường sau:

Main Weapon
Secondary Weapon/Equipment
Armor
Accessories

Tôi có thể thêm các trường bổ sung hoặc các lớp bổ sung trong tương lai nếu nó có ý nghĩa. Tôi đã xem xét hai định dạng có thể cho kẻ thù cơ sở dữ liệu.

Tệp XML

Về cơ bản tôi sẽ làm như thế này:

<?xml version="1.0" encoding="utf-8"?>
<Enemies>
  <Enemy name="Red Dragon" type="BaseEnemy" level="56" displayname="Red Dragon">
    <Stats HP="55000" MP="2500" SP="2500" Strength="212" Vitality="125" Magic="200" Spirit="162" Skill="111" Speed="109" Evasion="100" MgEvasion="100" Accuracy="100" Luck="55"/>
    <StatusResistances>
      <Resistance name="Sleep" value="100" />
      <Resistance name="Stop" value="100" />
    </StatusResistances>
    <ElementResistances>
      <Resistance name="Fire" value="75" />
    </ElementResistances>
    <LootTable>
      <Item name="Elixir" rate="0.03" count="1"/>
    </LootTable>
    <DropTable>
      <Item name="Elixir" rate="0.03" count="1"/>
    </DropTable>
    <AIScript value="BasicBehaviour.py" />
    <BaseXP value="4800"/>
  </Enemy>
  <Enemy name="Gaverick 1" type="HumanoidEnemy" level="33" displayname="Gaverick">
  <!--Same Stuff as above here-->
    <Equipment>
      <Weapon name="Dark Eclipse"/>
      <Armor name="Terra Defense"/>
      <Accessory name="Ribbon"/>
    </Equipment>
  </Enemy>
</Enemies>

Ưu điểm:

  • Dễ dàng mở rộng nếu tôi cần thêm / sắp xếp lại các tham số
  • dễ dàng gán giá trị mặc định
  • Tôi đã có một trình phân tích cú pháp XML (pugixml) cho các tệp cấu hình, bản đồ được xếp chồng và tải mô tả tài nguyên

Nhược điểm:

  • có khả năng chậm (cơ sở dữ liệu của tôi có thể sẽ tấn công hàng trăm kẻ thù)
  • không thể truy vấn kẻ thù tùy ý, do đó có thể sẽ cần giữ tất cả kẻ thù trong bộ nhớ.
  • Điều này có nghĩa là tôi cũng cần phải khởi động lại trò chơi để tải dữ liệu kẻ thù đã thay đổi

SQLite

Đối với điều này, về cơ bản, tôi sẽ tạo một bảng có các cột biểu thị tất cả dữ liệu tôi cần và để trống các trường không cần thiết

Ưu điểm

  • Truy vấn tùy ý có thể giữ dữ liệu kẻ thù không cần thiết ra khỏi bộ nhớ
  • Cảm thấy có cấu trúc hơn
  • Kích thước tệp nhỏ hơn

Nhược điểm

  • Khó khăn hơn để mở rộng / sắp xếp lại các đơn hàng tham số
  • Chi phí không cần thiết cho các trường không sử dụng
  • Sẽ cần phải viết một trình bao bọc giao diện cơ sở dữ liệu cho sqlite

Với suy nghĩ này, tôi đã tò mò về việc có được một số kinh nghiệm bên ngoài về những gì người khác đã làm. Tôi có thể đang nghĩ về điều này hoàn toàn sai, và nếu vậy, xin vui lòng đề xuất một giải pháp thay thế cho hai khả năng tôi có ở đây.

Ngoài ra, bất kỳ đề xuất nào về cách cải thiện một trong hai khả năng này sẽ được đánh giá cao. Thực sự, tôi chỉ muốn biết nếu tôi đi đúng hướng.

Tôi sẵn sàng sử dụng bất kỳ thư viện miễn phí nào và đã kết hợp tăng cường

Câu trả lời:


12

Tôi thấy không cần sự phức tạp của một cơ sở dữ liệu quan hệ đầy đủ. Cơ sở dữ liệu quan hệ tồn tại để làm cho các hoạt động tìm kiếm phức tạp trở nên dễ dàng, cũng như xử lý tìm kiếm trên các bộ dữ liệu lớn . Nếu tất cả những gì bạn đang làm trong trò chơi đang lập chỉ mục một trong số này mỗi khi kẻ thù xuất hiện, thì bạn đang sử dụng một công cụ cực kỳ phức tạp để làm điều đó.

Nói tóm lại, SQLite là quá mức cần thiết.

Tại thời điểm đó, câu hỏi không phải là SQLite so với XML. Đó là cách bạn lưu trữ nó trên đĩa và cách bạn muốn thể hiện dữ liệu trong trò chơi. Nếu các loại truy vấn duy nhất bạn làm trong trò chơi là tìm kiếm theo tên, thì đơn giản std::maplà đủ. Thật vậy, bạn có thể dán chúng vào std::vectorvà sắp xếp chúng sau khi tải để tìm kiếm nhanh.

Đối với biểu diễn trên đĩa, bạn nên quan tâm nhất đến định dạng giúp dễ chỉnh sửa nhất , không đọc. Đọc là một cái gì đó bạn có thể làm đủ dễ dàng trong mã; chỉnh sửa bạn phải làm một lần cho mỗi kẻ thù. Khi bạn thiết kế kẻ thù mới, bạn sẽ phải chỉnh sửa dữ liệu của họ rất nhiều.

Đối với tôi, sự phân đôi nằm giữa XML và Lua , hoàn toàn có thể sử dụng như một ngôn ngữ mô tả dữ liệu. Ví dụ: tệp XML mẫu có thể được biểu diễn trong Lua dưới dạng:

return
{
    {
        name = "Red Dragon", type="BaseEnemy", level=56, displayname="Red Dragon",
        stats = {
            HP=55000, MP=2500, SP=2500, Strength=212, Vitality=125,
            Magic=200, Spirit=162, Skill=111, Speed=109,
            Evasion=100, MgEvasion=100, Accuracy=100, Luck=55
        },
        status_resistances = {
            {name="Sleep", value=100},
            {name="Stop", value=100},
        },
        element_resistances = {
            {name="Fire", value=75},
        },
        loot_table = {
            {name="Elixir", rate=0.03, count=1},
        },
        drop_table = {
            {name="Elixir", rate=0.03, count=1},
        },
        script = "BasicBehaviour.py",
        xp = 4800,
    },
    {
        name="Gaveric 1", type="HumanoidEnemy", level=33, displayname="Gaveric",
        --Same Stuff as above here
        equipment = {
            weapon = "Dark Eclipse",
            armor = "Terra Defense",
            accessory = "Ribbon",
        }
    }
}

Ưu điểm lớn nhất đối với cách tiếp cận dựa trên kịch bản Lua là ... đó là Lua. Trong khi nó có thể được dữ liệu nguyên chất, nó không được. Vì vậy, nếu bạn có một số lần lặp lại các khối stat, bạn có thể dễ dàng có tập lệnh Lua tạo các dữ liệu này cho bạn. Tất cả điều này là một tập lệnh Lua trả về một bảng; bảng là những gì bạn đọc vào cấu trúc dữ liệu trong bộ nhớ của bạn.

Nhược điểm của phương pháp này chủ yếu là nếu bạn không sử dụng một công cụ để ghi các tệp này. Nếu bạn có một công cụ mà bạn sử dụng để chỉnh sửa các tệp kẻ thù này, thì phương pháp Lua vẫn ổn. Nhưng nếu bạn đang chỉnh sửa chúng bằng tay, thì điều đó có nghĩa là mã tải của bạn đi qua bảng Lua cần xác minh đầu vào. Nó cần kiểm tra xem các trường cần thiết có ở đó không, mỗi giá trị số là một số hợp lệ, v.v.

Và trong khi đó không phải là mã chính xác để viết, nó cực kỳ tẻ nhạt. Ưu điểm với XML là bạn có thể xác thực nó bằng lược đồ RelaxNG hoặc WXS. Thậm chí có những trình soạn thảo XML có chỉnh sửa hướng dẫn lược đồ, do đó không thể ghi tệp XML không hợp lệ .

Nếu bạn cần thêm một trường mới, chỉ cần điều chỉnh lược đồ của bạn và bạn sẽ ổn. Nếu bạn thay đổi cấu trúc tệp, một lần nữa, điều chỉnh lược đồ của bạn và xác nhận lại các tệp, sửa lỗi nơi chúng xuất hiện. Bạn thậm chí có thể viết một công cụ XSLT để tự động chuyển đổi các tệp từ phiên bản định dạng này sang phiên bản định dạng khác.

Tất nhiên, bạn phải biết cách viết các lược đồ và bạn phải có định dạng XML dựa trên lược đồ. Nếu không, tập lệnh Lua sẽ không tệ hơn, vì bạn phải xác thực dữ liệu theo bất kỳ cách nào. Và kịch bản Lua được cho là dễ dàng phân tích hơn, vì nó cho phép bạn truy vấn dữ liệu trực tiếp. Đưa ra một bảng Lua có chứa định nghĩa kẻ thù, bạn có thể truy vấn các "phần tử" cụ thể theo tên. Với trình phân tích cú pháp XML, bạn phải xử lý các phần tử khi chúng đến với bạn, thường phức tạp hơn một chút để viết.

không thể truy vấn kẻ thù tùy ý, do đó có thể sẽ cần giữ tất cả kẻ thù trong bộ nhớ.

... vì thế? Các cấu trúc dữ liệu, được lấy từ XML mẫu của bạn, sẽ tiêu tốn (không có nỗ lực nén:

  • 14 thống kê * 4 byte mỗi = 56 byte.
  • Tên nội bộ: chuỗi 32 byte.
  • Tên hiển thị: chuỗi 64 byte.
  • loại: một phần của cấu trúc dữ liệu; không cần phải được lưu trữ

Mỗi vũ khí cũng có thể là một chuỗi 32 byte. Vì vậy, tổng cộng trong trường hợp xấu nhất là ... 248 byte. Bạn có thể lưu trữ hơn 3500 trong số một nửa RAM. Tôi không lo lắng về điều đó.

Điều này có nghĩa là tôi cũng cần phải khởi động lại trò chơi để tải dữ liệu kẻ thù đã thay đổi

Tại sao? Tùy bạn. Không có gì nói rằng bạn không thể đổ dữ liệu của kẻ thù và tải lại vào giữa trò chơi. Nếu bạn không thể làm điều đó, thì đó chỉ là do bạn đã không cấu trúc đúng mã của mình để biến điều đó thành có thể.


+1 cho Lua. Ngoài ra, đừng quên YAML.
michael.bartnett

6

Tôi có hai lớp kẻ thù chính mà tôi cần để trình bày dữ liệu. Một lớp kẻ thù cơ bản ... và một lớp dẫn xuất ...

Tôi không tin rằng bạn cần hai lớp cho việc này; một người duy nhất nên đủ. Bạn có thể dễ dàng mô hình hóa điều này với thành phần hơn là kế thừa ; các kỹ thuật thiết kế phần mềm hiện đại đang có xu hướng tránh xa các hệ thống phân cấp sâu vì chúng có xu hướng dễ vỡ và khó bảo trì. Mặc dù hệ thống phân cấp được đề xuất của bạn không sâu lắm, nhưng nó không cần thiết (đó là bước đầu tiên hướng tới "sâu"). Lớp dẫn xuất của bạn chỉ thêm các thuộc tính có thể dễ dàng duy trì trên lớp cơ sở nhưng để trống.

Điều này không chỉ cho phép bạn lặp lại tốt hơn và điều chỉnh hành vi và thuộc tính của từng kẻ thù của bạn sau này, nó cho phép mã của bạn đơn giản hơn khi bạn chỉ xử lý một API công khai duy nhất và xử lý chúng.

Tôi đã xem xét hai định dạng có thể cho kẻ thù cơ sở dữ liệu.

Trong hai cái này, tôi sẽ chọn XML. Nói chung, bạn có thể muốn xem JSON . Tôi không nghĩ rằng việc sử dụng một cơ sở dữ liệu quan hệ thực tế ở đây là được bảo hành. Xem câu hỏi này để biết một số thảo luận về lý do tại sao: phiên bản ngắn là nó phức tạp và ít trực tiếp hơn để truy cập hoặc chỉnh sửa, và vì bạn không cần bất kỳ lợi thế nào mà cơ sở dữ liệu quan hệ cung cấp, tốt hơn hết bạn nên gắn bó với thứ gì đó tương tự.

Cả XML và JSON đều có lợi thế rất lớn là có thể đọc được và có thể chỉnh sửa con người một cách tầm thường mà không cần các công cụ chuyên dụng, điều này thực sự có thể giúp tăng thời gian lặp lại của bạn. XML cho phép bạn sử dụng XSLT để chuyển đổi hàng loạt dữ liệu của mình nếu bạn thay đổi mạnh mẽ lược đồ hoặc cần thực hiện một số loại di chuyển quy mô lớn khác.

Cụ thể cho ba "lợi thế" của bạn đối với SQLite:

  • Bạn có thể dễ dàng giữ dữ liệu ra khỏi bộ nhớ khi nó nằm trong một tệp trên đĩa (có thể phụ thuộc vào trình đọc XML của bạn), nhưng bạn có thể không muốn làm điều này vì đĩa "chậm" và bạn có thể không ' t có đủ dữ liệu để thực sự gây ra nhiều áp lực bộ nhớ.
  • Nó chỉ có cấu trúc như bạn tạo ra và thiết kế các lược đồ cơ sở dữ liệu chuẩn hóa tốt, thực sự không phải lúc nào cũng là một nhiệm vụ tầm thường. Bạn thường chỉ nhận được mức tăng tối đa từ cơ sở dữ liệu khi bạn có một thiết kế lược đồ phù hợp. Thay đổi lược đồ cũng khó hơn nhiều.
  • Bạn luôn có thể chuyển sang định dạng tệp nhị phân để vận chuyển trò chơi của mình nhằm giảm hoặc loại bỏ chi phí vốn có của một định dạng dựa trên văn bản dài hơn như XML hoặc JSON. Nó khá dễ làm.

3

Đây là một cách khác để xem xét nó, tạo cấu trúc dữ liệu điền vào giá trị quái vật của bạn sau đó lưu cấu trúc dữ liệu vào tệp nhị phân và đặt tệp đó vào tệp pak như:

ork_footsoldier.npcdat
ork_chief.npcdat
guard.npcdat
 Into..
NPCData.pak

Sau đó tải pak vào bộ nhớ, phân tích các tệp npcdat, sau đó phân tích dữ liệu trong chúng theo yêu cầu. Nó nhanh hơn XML và SQLLite và chiếm ít không gian hơn.


@Skeith tôi đồng ý. Một tệp văn bản đơn giản được phân định sẽ thực hiện công việc mà người dùng 127817 đang mô tả mà không gặp nhiều rắc rối.
Christopher

@Christopher: Ngoại trừ việc bạn sẽ phải viết một trình phân tích cú pháp cho nó. Và một cái gì đó để tải các tập tin gói. Và, tốt, rất nhiều thứ bạn không phải làm chỉ với việc tải một tệp XML. "Văn bản thuần túy được phân cách" cũng khó chỉnh sửa hơn vì không có công cụ chỉnh sửa được hướng dẫn cho chúng. Bạn có thể dễ dàng nhận được định dạng sai và bạn sẽ không biết cho đến khi bạn cố tải nó.
Nicol Bolas

Viết một trình phân tích cú pháp cho dữ liệu nhị phân nhanh hơn và dễ dàng hơn nhiều so với trình phân tích cú pháp văn bản, cộng với trong một trò chơi sản xuất, việc sửa đổi các giá trị để gian lận sẽ khó hơn nhiều.
Matt Jensen

0

Ưu điểm duy nhất của SQLite mà tôi có thể nghĩ đến là giảm trùng lặp, tức là nếu rơi vào phần lợi thế "Cảm thấy có cấu trúc hơn" của bạn.

Nhưng bạn có thể truy vấn XML bằng XPath, nếu bạn muốn. Nhưng tôi nghĩ rằng đối với hàng trăm (và thậm chí hàng ngàn) lưu trữ tất cả dữ liệu trong bộ nhớ là không quan trọng. Với số lượng kích thước dữ liệu này của tệp db hoặc XML là không quan trọng.

Tôi bỏ phiếu cho XML.

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.