В этой статье я представлю две коллекции C #, которые могут быть очень полезны для разработки игр.

Репозиторий статьи: https://github.com/omidizadi/sorted-observable-inventory

На днях я играл в Genshin Impact и заметил, что мои предметы в инвентаре всегда отсортированы по уровню, звезде или уровню. Я думал, что это должно быть легко реализовать. Но мне всегда нравится знать, что у меня есть.

Эти две коллекции, о которых я расскажу, чаще использовались разработчиками .Net, чем программистами Unity.

SortedList

Почти все распространенные структуры данных, такие как список, словарь или хеш-набор, имеют эквивалентный отсортированный тип.

SortedList, SortedDictionary и SortedSet - это встроенные коллекции C #. Как вы можете догадаться, их задача - сортировать элементы каждый раз, когда вы их добавляете или удаляете. Но здесь важно то, как SortedList сравнивает элементы. Что произойдет, если мы попытаемся сохранить GameObjects? Как обрабатывается сравнение GameObject?

Давайте выясним это на примере.

Отсортированный инвентарь

Я создал очень простую сцену с кучей шаров в качестве коллекционных предметов, холстом, чтобы показать пользовательский интерфейс инвентаря, и ландшафтом для удержания шаров (не хотел, чтобы это выглядело слишком просто!)

Затем я реализовал два интерфейса для своих предметов коллекционирования и инвентаря:

Сначала я реализовал абстрактный инвентарь, чтобы иметь возможность извлекать его экземпляр в сцене:

Я использовал здесь шаблон Singleton для простоты использования, но из-за этого я буду осторожен, чтобы не позволять моим зависимостям прятаться между кодами.

Затем я реализовал конкретную версию ICollectible для шаров и определил три уровня (T1 для серого, T2 для фиолетового и T3 для фиолетового).

Теперь при каждом нажатии на шары они добавляются в инвентарь и исчезают.

Отсортированный инвентарь будет таким:

Как видите, я использовал SortedList для хранения элементов. Я забыл упомянуть, что все отсортированные коллекции получают пару ключ-значение как элемент и сортируют их по ключу. Если в качестве ключа вы укажете int, float, enum, string или char, по умолчанию они будут отсортированы в порядке возрастания. Но есть проблема! SortedList не принимает повторяющиеся ключи! Мы знаем, что в некоторых случаях мы должны хранить повторяющиеся элементы в отсортированной коллекции, как в этом примере, когда я хочу хранить разные элементы с одним и тем же уровнем. Решение состоит в том, чтобы предоставить SortedList собственную реализацию IComparer!

При этом мой SortedList будет сортировать элементы в порядке убывания (поскольку элементы T3 более важны, поэтому их следует рассматривать в первую очередь) и рассматривать те же уровни как более высокие.

Обратите внимание, что интерфейс IComparer является общим, поэтому вы можете реализовать сравнение для чего угодно, например, GameObjects, Vectors, Raycast , абсолютно ничего.

в классе SortedInventory я сохранил событие OnItemCollected для любого класса, который хочет получать уведомления, когда что-то собирается.

Итак, я создал класс пользовательского интерфейса, чтобы показать свой инвентарь:

Теперь все готово:

ObservableCollection

В предыдущем разделе вы видели, что я использовал OnItemCollected, чтобы позволить другим классам подписываться на события моего инвентаря. Но теперь я хочу использовать коллекцию с такой же встроенной функциональностью. ObservableCollection дает нам возможность подписаться на его изменения.

Как и в предыдущем примере, я создал сцену с набором GameObject (на этот раз кубики двух цветов)

Я хочу собирать кубики одним щелчком мыши и добавлять их в свою коллекцию. Мне также нужно обновлять свой пользовательский интерфейс всякий раз, когда что-то собирается, но на этот раз я не буду использовать событие C #. Первый мой класс CubeCollectible:

Это почти то же самое, что и SphereCollectible, но с другим перечислением Type.

Теперь для инвентаризации я использую инкапсулированную ObservableCollection:

Другие классы могут подписаться на эту коллекцию, добавив событие в ее CollectionChanged. нравится:

Этот сценарий добавляет UpdateInventoryUI в нашу ObservableCollection, чтобы отображать эквивалентные элементы пользовательского интерфейса при сборе элемента. Я прикрепляю этот скрипт к двум компонентам для каждого цвета внутри моего холста:

Теперь проигрываем сцену:

Как видите, эти два компонента пользовательского интерфейса получают уведомление от ObservableCollection и обновляют пользовательский интерфейс, если собранный цвет куба совпадает с цветом, который они ищут.

Вы можете найти исходный код в этом репозитории Github. Обязательно заходите на мой сайт, подписывайтесь на меня в Linkedin и задавайте свои вопросы, если таковые имеются.

Спасибо за уделенное время!