Khái niệm bảng Loot hiện đại


7

Đầu tiên, cho phép tôi xin lỗi, bởi vì đây sẽ là một bài viết khá dài. Tôi đã đưa ra chủ đề này rất nhiều suy nghĩ, và thậm chí đã thử nghiệm các khái niệmtriển khai trước đó .

Khi tôi tưởng tượng một bảng loot, tôi luôn nghĩ về một cái gì đó giống như cách World of Warcraft thực hiện chúng. Dưới đây là một ví dụ hình ảnh:

nhập mô tả hình ảnh ở đây

Bây giờ, chỉ sử dụng các tín hiệu trực quan, khi có thể phân tích khá nhiều cách thức hoạt động của hệ thống loot, nhưng chúng ta cũng hãy tiếp tục và sử dụng một số thống kê của Wowhead để hiểu rõ hơn về những gì chúng ta đang giải quyết. Đây là một giả lập nhanh chóng: nhập mô tả hình ảnh ở đây

Như bạn có thể thấy, hệ thống loot mà World of Warcraft sử dụng khá năng động. Nó không chính xác là một roulette, nhưng có thể, ở cấp độ cơ sở, giống như một trong những cách. Lần thực hiện đầu tiên của tôi về Bảng Loot đã tránh được khái niệm roulette và thậm chí là một thợ cơ khí (điều này mang lại xác suất cao hơn cho việc lấy từ bàn và để lại những người khác). Tôi không thích ý tưởng cân vật phẩm trong tự nhiên này. Vì vậy, tôi đã làm một cái gì đó như thế này:

nhập mô tả hình ảnh ở đây

Bảng Loot này là một "Danh sách". Về cơ bản, tôi sẽ lặp qua từng mục, kiểm tra xác suất của nó và nếu thành công, tôi sẽ thêm nó vào danh sách các giọt. Điều này hoạt động tốt trên lý thuyết, nhưng tôi đã nhanh chóng nhận thấy một lỗ hổng chết người trong hệ thống.

Xem xét đầu ra này:

Ore_Copper x1
Nugget_Copper x2
Gem_Diamond x1
Gem_Emerald x1
Gem_Topaz x1

Đó là một sự phóng đại, nhưng nếu bạn nhìn vào cấu trúc cơ bản thì hoàn toàn có thể ... nhưng nếu chúng ta không muốn bỏ 4 loại đá quý thì sao? Ngoài ra, xác suất tập thể của các viên đá quý cũng khiến bạn thực sự được đảm bảo nhận được ít nhất một, bởi vì bạn có 10% * 5 cơ hội để có được một. Bây giờ, điều này có thể ổn cho một trò chơi, nhưng đó không phải là những gì tôi dự định. Tôi muốn có khả năng thả đá quý, nhưng chỉ có một cơ hội. Tôi muốn xác suất nhận được một viên đá quý chính xác là 10%. Vì vậy, làm thế nào để chúng tôi sửa lỗi này? Đây là những gì tôi nghĩ ra:

nhập mô tả hình ảnh ở đây

Vậy chuyện gì đang xảy ra bây giờ? Về cơ bản chúng tôi đã xây dựng một hệ thống roulette. Thay vì một bộ sưu tập trực tiếp của LootTableItems, giờ đây chúng tôi trì hoãn các mục thành các bộ sưu tập độc lập. LootTableListS. Mỗi danh sách có xác suất riêng, giống như bản gốc của tôi LootTable, nhưng bây giờ chúng tôi có thể sắp xếp thành công các mục vào "nhóm" của riêng mình trong một nhóm LootTable. Nếu chúng tôi muốn một mặt hàng ít hiếm hơn một mặt hàng khác, chúng tôi chỉ cần thêm các trường hợp bổ sung vào mong muốn LootTableList. Sau đó, khi tôi LootTableđang chạy thuật toán của nó, nó sẽ chọn một mục từ LootTableList. Điều này là tuyệt vời, nhưng nó cũng đưa ra một vấn đề khác. Điều gì sẽ xảy ra nếu tôi muốn tất cả các mục trong một LootTableListbị rơi, hoặc có cơ hội rơi? Vâng, tôi đã đi trước và thêm một lĩnh vực, được gọi làCollectAll. Khi trường này được chọn, nó sẽ tránh chọn một mục và thay vào đó chọn tất cả các mục trong LootTableList.

Sau khi lên kế hoạch cho tất cả những điều này và làm bài tập về nhà của tôi về chủ đề này, tôi đã đến để tạo ra loại LootTable này. Tôi cũng khá chắc chắn rằng đây cũng là loại LootTable mà World of Warcraft đang sử dụng, hoặc ít nhất là về mặt khái niệm chúng rất gần gũi. Đây là mã:

using System;
using System.Collections.Generic;
using System.Linq;
using GrimoireDevelopmentKit.Framework.Interfaces;
using GrimoireDevelopmentKit.Framework.Maths;
using GrimoireDevelopmentKit.Framework.Utilities;

namespace GrimoireDevelopmentKit.Framework.Collections
{
    [Serializable]
    public class LootTable : Dictionary<string, LootTableList>, ICopy<LootTable>
    {
        public string Identifier { get; set; }
        public AdvancedRandom Random { get; set; }

        public int TotalItems
        {
            get
            {
                int total = 0;
                foreach (LootTableList list in this.Values)
                {
                    total += list.Values.Count;
                }
                return total;
            }
        }

        public LootTable(string identifier = null)
            : this(identifier, new AdvancedRandom())
        {
        }

        public LootTable(string identifier, AdvancedRandom random)
        {
            Identifier = identifier;
            Random = random;
        }

        public void Add(LootTableList list)
        {
            if (!Contains(list))
            {
                Add(list.Identifier, list);
            }
            else
            {
                throw new ArgumentException("Key: '" + list.Identifier + "' already exists!");
            }
        }

        public bool Remove(LootTableList list)
        {
            return Remove(list.Identifier);
        }

        public bool Contains(string listIdentifier)
        {
            return ContainsKey(listIdentifier);
        }

        public bool Contains(LootTableList list)
        {
            return Contains(list.Identifier);
        }

        public List<LootTableResult> Next()
        {
            Range probabilityScope = new Range(0, 100);
            List<LootTableResult> drops = new List<LootTableResult>(TotalItems);
            foreach (LootTableList list in Values)
            {
                bool success = Random.NextRange(probabilityScope) <= list.Probability;
                if (success)
                {
                    if (list.CollectAll)
                    {
                        foreach (LootTableItem item in list.Values)
                        {
                            int quantity = Random.NextRange(item.Quantity);
                            if(quantity > 0)
                            {
                                drops.Add(new LootTableResult(item.Identifier, quantity));
                            }
                        }
                    }
                    else
                    {
                        LootTableItem item = list.ElementAt(Random.NextInteger(0, list.Count)).Value;
                        int quantity = Random.NextRange(item.Quantity);
                        if(quantity > 0)
                        {
                            drops.Add(new LootTableResult(item.Identifier,quantity));
                        }
                    }
                }
            }
            return drops;
        }

        public void Copy(LootTable other)
        {
            this.Clear();
            this.Identifier = other.Identifier;
            this.Random = other.Random;
            foreach (LootTableList list in other.Values)
            {
                this.Add(list.MakeCopy());
            }
        }

        public LootTable MakeCopy()
        {
            LootTable copy = new LootTable();
            copy.Copy(this);
            return copy;
        }
    }

}

Câu hỏi của tôi:

Có một nền tảng khái niệm tốt hơn và hiện đại hơn mà tôi có thể sử dụng để đạt được loại bảng loot này không?

Có nhà phát triển trò chơi nào trên trang web này đã tạo ra Loot Bàn về bản chất này không? Tôi chỉ muốn biết liệu tôi có thể cải thiện khái niệm của mình không chỉ là mã mà còn là chính khái niệm đó. Tôi chắc chắn có nhiều điều có thể được thực hiện để cải thiện công việc của tôi. Tôi chỉ tìm kiếm lời khuyên từ những người có kinh nghiệm trong chủ đề này.

Tôi cũng có thể đăng triển khai của mình vào một dự án riêng nếu nó giúp mọi người giúp tôi . Trên thực tế, tôi nghĩ rằng tôi sẽ thực hiện nó ngay bây giờ trên thực tế.

BIÊN TẬP

Chỉ nhận ra rằng tôi đã quên mã số lượng Số lượng trong LootTableLists, nếu được mã hóa, sẽ cho phép LootTableList được thu thập từ nhiều lần trong cùng một lần thả.


2
Tôi không chắc chắn những gì bạn đang hỏi ở đây. Không thể trả lời "làm thế nào tôi có thể làm điều này tốt hơn" nếu bạn chưa đưa ra tiêu chí về những gì cấu thành "tốt hơn". Thay vào đó tôi thấy rằng bạn có một số vấn đề về thiết kế - làm thế nào tôi chỉ có thể bỏ một mục hoặc bỏ tất cả các mục - nhưng bạn đã giải quyết chúng rồi.
congusbongus

Tôi sẽ chỉnh sửa để làm cho nó rõ ràng hơn.
Krythic

1
Chỉnh sửa của bạn chỉ thêm một nhận xét; nó không làm gì để làm rõ hơn những gì bạn thực sự yêu cầu .
Gnemlock

2
Điều gì là sai với cách tiếp cận không quá hiện đại? Có điều gì bạn muốn làm mà bạn không thể làm với một giải pháp đơn giản hơn không? - Chẳng hạn, bạn không thích sử dụng tạ, có điều gì bạn muốn làm mà trọng lượng sẽ ngăn bạn làm không? - Thực hiện rằng bạn không muốn sử dụng các trọng số không đủ để biết hướng đi nào - Có vẻ như bạn chỉ muốn biết trạng thái của nghệ thuật. Nếu đó là ý tưởng, điều đó có nghĩa là ngay khi một cái gì đó "hiện đại hơn" xuất hiện cùng với tất cả các câu trả lời sẽ bị lỗi thời.
Theraot

1
Nếu bạn muốn hệ thống loot của mình mang lại trải nghiệm trò chơi cân bằng và cân bằng hơn mà không xóa bỏ hoàn toàn sự ngạc nhiên, bạn có thể thấy câu hỏi này thú vị: Làm thế nào tôi có thể tạo ra một trình tạo ngẫu nhiên trực tuyến bị thiên vị bởi các sự kiện trước?
Philipp

Câu trả lời:


2

Bạn đang đi đúng hướng. Đó là nơi tôi sẽ bắt đầu. Tất cả các thành phần của bạn chia sẻ định danh và số lượng. Nó có ý nghĩa để thêm tài sản cơ hội và sử dụng mô hình tổng hợp .

public class Droppable
{
    public string Name { get; private set; }
    public uint QTY { get; private set; }
    public float Chance { get; private set; }

    public Droppable(string name, float chance, uint qty)
    {
      this.Name = name;
      this.QTY = qty;
      this.Chance = chance;
    }

    public virtual bool ShouldDrop()
    {
    // random drop check
    }
}

Sau đó, bạn có thể tạo Droppablethành phần mở rộng bảng loot của bạn .

public class DropBundle extends Droppable
{
    public bool CollectAll { get; private set; }
    private List<Droppable> _items;

    public DropBundle(string name, float chance, uint qty, bool collectAll, List<Droppable> items): base(name, chance, qty)
    {
        CollectAll = collectAll
        _items = items;
    }

    public override bool ShouldDrop()
    {
    // random drop check and if yeas run should drop check for other items
    }
}

Bạn cũng cần lớp vật phẩm của bạn cũng sẽ mở rộng Droppable

public class DropItem extends Droppable
{

   public override bool ShouldDrop()
   {
      // random drop check
   }
}

Để ý CompositeItem giữ các tham chiếu đến các Droppablethành phần khác . Điều đó có nghĩa là bạn có thể tiếp theo họ nhiều như bạn muốn, ví dụ:

  • 5% tìm kiếm 10 đồng vàng (DropItem)
  • 10% trong việc tìm kiếm đồng xu (CompositeItem) có thể là vàng (20%) hoặc bạc (80%)
  • 20% tìm kiếm rương (CompositeItem) có thể có 10% cơ hội tìm thấy đồng xu (CompositeItem) có thể là vàng, bạc hoặc đồng, v.v.

Tất cả các scenerios sau đó có thể mà không thay đổi cây phụ thuộc quá nhiều. Điều duy nhất bạn phải nhớ rõ ràng là thực hiện ngẫu nhiên hóa và hãy nhớ rằng tổng số cơ hội của các phân nhỏ lồng nhau phải là 1 (100%) vì đơn giản.

Một lợi thế lớn khác của việc sử dụng mẫu tổng hợp là khả năng sử dụng triển khai đó cho dữ liệu mà bạn có thể đọc động từ tệp XML (hoặc JSON) tĩnh.

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.