Задать вопрос
@Varhelm

Как лучше хранить и доставать ресурсы в unity?

Всем привет!

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

Задача:
Хранить и использовать разные спрайты, в разных местах. (Кастомизация персонажа, аукцион, предметы в почте, покупка в магазине и так далее). Информация, что подгружать будет приходить от сервера

Описание:
Игра 2д
У меня спрайты:
-Одежды в виде нарезки (то есть элемент поделен на 12 кусков)
-Оружия
-Иконок для магазина и прочих мест

Возьмем пример с кастомизации персонажа при его создании, логика следующая:
при старте игры идет запрос к серверу, откуда в файл записывается информация о классах всех и какая у него экипировка. Далее префаб игрока надевает это на себя в зависимости от выбора игрока.
Сам персонаж нарезан на куски (типо тело, голова, оружие и тому подобное), и на каждой части есть spriteRender куда я креплю спрайт
Примерно тот же алгоритм для иконок, которые доступны для Кастомизации (глаза, волосы и прочее), тут я имею ввиду кнопки для выбора смены спрайта. То есть нужно грузить иконку для отображения кнопки и спрайт потом для изменения персонажа.
Тут можно сделать статику, на этапе создания персонажа. Но дальше статика уже не очень подходит, так как Кастомизацию планирую делать не совсем открытую так скажем, то есть спрайты будут также динамически и какой-нибудь пагинацией наверное.

Что пробовал:
папка resource - почитал и просто не понравилось
assetsBandle - интересно, вроде работает как надо. Но из-за того, что спрайты нарезаны одежды, то мне на каждую экипировку надо делать свой бандл, то есть не разделить по категориям, а прям на каждый спрайт. Так как если запрашивать у него один файл, то он отдает только первый. Если все, то вообще все, а названия там у всех одинаковые будут (типо рука, рука1, рука2) и имя закэшировано. Из-за этого не удобно для меня лично стало. Но тут не спорю, возможно, я туповат и не понял, как правильно с ним работать, но вроде всё по доке делал
Что-то ещё пробовал и забыл.

Сейчас реализовано, что в начале игры у меня загружается "вечный" префаб "database" с прикрепленным к нему scriptableObjects где есть вся инфа по спрайтам. Сделано в следующем формате:
public class ItemCollection: ScriptableObject
    {
        [SerializeField] private Item[] _item;
        public Item[] Item => _item;

        public Item[] GetItemCollection()
        {
            return _item;
        }
    }
public class Item
    {
        public int id;
        public string name;
        public Types type;
        public Sprite[] sprites;
        public Sprite icon;
    }

а к "базе" так скажем обращаюсь следующим образом:
public class Database: MonoBehaviour
    {
        [SerializeField] private ItemCollection HeavyArmor;
        [SerializeField] private ItemCollection LightArmor;
        [SerializeField] private ItemCollection Swords;
        [SerializeField] private ItemCollection Stuffs;

        private Dictionary<string, Item> _lightArmor = new Dictionary<string, Item>();
        private Dictionary<string, Item> _heavyArmor = new Dictionary<string, Item>();
        private Dictionary<string, Item> _swords = new Dictionary<string, Item>();
        private Dictionary<string, Item> _stuffs = new Dictionary<string, Item>();
        
        private static Database instance;
        
        public static Database Instance
        {
            get
            {
                if (instance != null) return instance;
                
                instance = FindObjectOfType<Database>();
                
                return instance;
            }
        }

        private void Awake()
        {
            if (instance == null)
            {
                instance = this;
                DontDestroyOnLoad(gameObject);
            }
            else
            {
                Destroy(gameObject);
                return;
            }

            var heavyArmorCollection = HeavyArmor.GetItemCollection();
            var lengthHeavyArmor = heavyArmorCollection.Length;
            for (var i = 0; i < lengthHeavyArmor; i++)
            {
                _heavyArmor.Add(heavyArmorCollection[i].name, heavyArmorCollection[i]);
            }
            
            var lightArmorCollection = LightArmor.GetItemCollection();
            var lengthLightArmor = lightArmorCollection.Length;
            for (var i = 0; i < lengthLightArmor; i++)
            {
                _lightArmor.Add(lightArmorCollection[i].name, lightArmorCollection[i]);
            }
            
            var swordsCollection = Swords.GetItemCollection();
            var lengthSword = swordsCollection.Length;
            for (var i = 0; i < lengthSword; i++)
            {
                _swords.Add(swordsCollection[i].name, swordsCollection[i]);
            }
            
            var stuffsCollection = Stuffs.GetItemCollection();
            var lengthStuff = stuffsCollection.Length;
            for (var i = 0; i < lengthStuff; i++)
            {
                _stuffs.Add(stuffsCollection[i].name, stuffsCollection[i]);
            }
        }

        public Item GetLightArmorByName(string key)
        {
            return _lightArmor.GetValueOrDefault(key, null);
        }

        public Item GetHeavyArmorByName(string key)
        {
            return _heavyArmor.GetValueOrDefault(key, null);
        }
        
        public Item GetSwordByName(string key)
        {
            return _swords.GetValueOrDefault(key, null);
        }
        
        public Item GetStuffByName(string key)
        {
            return _stuffs.GetValueOrDefault(key, null);
        }

        public Dictionary<string, Sprite> PrepareSpriteEquipSet(Sprite[] sprites)
        {
            if (sprites.Length != 12)
            {
                throw new Exception("Invalid count Item");
            }
            
            return new Dictionary<string, Sprite>
            {
                { Config.APP_EQUIP_PART_SET_ARM_L, sprites[0] },
                { Config.APP_EQUIP_PART_SET_ARM_R, sprites[1] },
                { Config.APP_EQUIP_PART_SET_WRIST sprites[2] },
                { Config.APP_EQUIP_PART_SET_SHOULDER_L, sprites[3] },
                { Config.APP_EQUIP_PART_SET_SHOULDER_R, sprites[4] },
                { Config.APP_EQUIP_PART_SET_HAND_L, sprites[5] },
                { Config.APP_EQUIP_PART_SET_HAND_R, sprites[6] },
                { Config.APP_EQUIP_PART_SET_LEGS, sprites[7] },
                { Config.APP_EQUIP_PART_SET_PELVIS, sprites[8] },
                { Config.APP_EQUIP_PART_SET_SHIN, sprites[9] },
                { Config.APP_EQUIP_PART_SET_SLEEVE, sprites[10] },
                { Config.APP_EQUIP_PART_SET_TORSO, sprites[11] }
            };
        }
    }

P.S. код набросок, для моих тестов и чтоб всем понятно было)
в целом работает как надо, пока даже не ломается. Но я очень не уверен, что с ростом ресурсов эта ситуация останется на таком же уровне.

Что требуется:
помочь выбрать логику для моей задачи, потому что мне кажется, что я где-то рядом брожу и не вижу очевидного решения!)
  • Вопрос задан
  • 229 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 1
@DrRen7
хмм тут нужен контекст что бы разобраться полностью
сначала создаем ScriptableObject, что главное что б в нем было все совпадающие поля , допустим если где то нету условной иконки спрайта но тут не должно быть этого .
using UnityEngine;

public class Item : ScriptableObject
{
    public enum ObjType
    {
        HeavyArmor, LightArmor, Swords, Stuffs
    }
    public int _id;
    public string _name;
    public ObjType _Objtype;
    public Sprite[] _sprites;
    public Sprite icon;
}

Далее создаем то что будет создавать нам ассеты я как пример взял оружие
using UnityEngine;
[CreateAssetMenu]
public class Weapon : Item
{
    public float _damage;
    public float _speedAttack;
}

теперь его можно создавать правой кнопкой
662ff298535c1517918359.png
Ну а потом уже где все будет хранится
using System.Collections.Generic;
using UnityEngine;
using static Item;

public class ItemHolder : MonoBehaviour
{
    [SerializeField]List<Item> _allITemList = new List<Item>();

    [SerializeField]List<Item> _sword=new List<Item>();

    private void Awake()  
    {
        CreateNewList(_sword, ObjType.Swords,false);
    }
    void CreateNewList(List<Item>newlist,ObjType type,bool delete) // как пример создания листа
    {
        foreach (var item in _allITemList)
        {
            if (item._Objtype == type)
            {
                newlist.Add(item);
                if(delete)_allITemList.Remove(item);
            }
        }
    }
}

ну и просто заполняешь лист созданными объектами
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы