Есть ли лучший способ написать мою систему разблокировки предметов/оружия?

Я действительно борюсь с созданием системы разблокировки оружия/предметов через внутриигровой магазин. Игрок должен иметь возможность выбирать оружие только по индексам, которые были разблокированы или куплены.

Я потратил два дня на лучший способ добиться этого, и я до сих пор не нашел решения.

На данный момент это то, что у меня есть:

У меня есть скрипт WeaponUnlock, который обрабатывает dictionary оружия, и еще один скрипт WeaponSwitcher, который обращается к значениям из этого скрипта, чтобы проверить, разблокировано оно или нет.

public class WeaponUnlockSystem : MonoBehaviour
{

    private Dictionary<string, bool> weaponUnlockState;    

    void Start()
    {
        // Seeding with some data for example purposes
        weaponUnlockState = new Dictionary<string, bool>();
        weaponUnlockState.Add("Shotgun", true);              
        weaponUnlockState.Add("Rifle", true);
        weaponUnlockState.Add("FireballGun", false);
        weaponUnlockState.Add("LaserGun", false);
        weaponUnlockState.Add("FlamethrowerGun", false);
        weaponUnlockState.Add("SuperGun", false);
    }

    public bool IsWeaponUnlocked(string weapon_)
    {
        if (weaponUnlockState.ContainsKey(weapon_))
            return weaponUnlockState[weapon_];              // this will return either true or false if the weapon is unlocked or not
        else
            return false;
    }

    public void UnlockWeapon(string weapon_)            //this will be called by the button..
    {
        if (weaponUnlockState.ContainsKey(weapon_))
            weaponUnlockState[weapon_] = true;
    }
}

WeaponSwitcher получает название оружия от вложенных дочерних элементов каждый раз, когда нажимается кнопка nextWeapon:

weaponName = this.gameObject.transform.GetChild(weaponIdx).name.ToString();     //get the name of the child at current index

        if (weaponUnlock.IsWeaponUnlocked(weaponName))      //ask weaponUnlockSystem if this name weapon is unlocked or not, only enable the transform if true is returned
            selectedWeapon = weaponIdx;

Это...... работает..... но я знаю, что это непрактично. Поскольку скрипт находится на игровом объекте, и каждый раз, когда он вызывается, вызывается Start(), который сбрасывает все разблокированные значения. Также мне придется сделать его постоянным через DontDestroyOnLOad() через сцены?

Я могу использовать PlayerPrefs и установить значение для каждого оружия, но это тоже не идеально, а также, чтобы избежать его сброса каждый раз, когда кто-то открывает мою игру, мне пришлось бы выполнять проверки PlayerPrefs.HasKey() для каждого оружия. Тоже не практично.

Должен быть лучший способ сделать это. Забавно, что я не могу найти много помощи в Интернете для этого и не знаю, как все обходят это.

Спасибо

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

Adam G 27.05.2019 13:44

Поскольку скрипт находится на игровом объекте, и каждый раз, когда он вызывается, вызывается Start(), который сбрасывает все разблокированные значения. Также мне придется сделать его постоянным через DontDestroyOnLoad() через сцены?

StuckInPhDNoMore 27.05.2019 13:51

Просто создайте класс, который не является моноповедением, со «стандартными» логическими переменными и используйте ссылку на этот класс в чем-то вроде GameManager?

Jichael 27.05.2019 14:10

Возможный дубликат Лучший способ сохранить данные в игре Unity

derHugo 27.05.2019 18:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
223
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Недавно у меня был проект Unity, где нам нужно было хранить и обрабатывать некоторые простые данные между сценами. Мы только что создали статический класс, который не расширяет моноповедение. Кроме того, если вы ищете эффективность, почему бы просто не сохранить набор разблокированного оружия?

В общем, почему бы не попробовать что-то вроде этого:

public static class WeaponUnlockSystem
{

    private static string[] unlockedWeapons = InitialWeapons();

    private static string[] InitialWeapons(){
        string w = new string[]{
            "Shotgun",
            "Rifle",
        }
    }

    public static bool IsWeaponUnlocked(string name)
    {
        int i = 0;
        bool found = false;
        while(i < unlockedWeapons.Length && !found){
            if (string.Equals(unlockedWeapons[i],name)){
                found = true;
            }
            i++;
        }
        return found;
    }

    public static void UnlockWeapon(string name)
    {
        string[] weapons = new string[unlockedWeapons.Length+1];
        int i = 0;
        bool found = false;
        while(i < unlockedWeapons.Length && !found){
            if (string.Equals(unlockedWeapons[i],name)){
                found = true;
            } else {
                weapons[i] = unlockedWeapons[i];
            }
        }
        if (!found){
            weapons[unlockedWeapons.Length] = name;
            unlockedWeapons = weapons;
        }
}

Я не запускаю свою С# IDE, поэтому прошу прощения, если есть какие-либо синтаксические ошибки. Должен быть эффективным, простым и, поскольку он статичен, вам не нужно помещать его в пустой GameObject, чтобы он работал.

Ответ принят как подходящий

Вы создаете класс, который не является GameObject, а является обычным классом. Там вы можете инициализировать словарь и иметь методы для разблокировки или проверки того, разблокировано ли оружие.

Поскольку я не знаю, как выглядит ваша архитектура остального кода, я продолжу и предположу, что у вас есть какая-то модель постоянного проигрывателя.

Вы можете просто добавить WeaponUnlockSystem в свой GameObject игрока и оттуда управлять разблокировкой. Для меня это имело бы наибольший смысл, так как игрок, вероятно, тот, кто разблокирует оружие, поэтому к нему должна быть подключена Система Разблокировки Оружия.

Вот действительно простой пример кода:

public class WeaponUnlockSystem {

    private Dictionary<string, bool> weaponUnlockState;

    public WeaponUnlockSystem() 
    {
        weaponUnlockState = new Dictionary<string, bool>();
        weaponUnlockState.Add("Shotgun", true);              
        weaponUnlockState.Add("Rifle", true);
        weaponUnlockState.Add("FireballGun", false);
        weaponUnlockState.Add("LaserGun", false);
        weaponUnlockState.Add("FlamethrowerGun", false);
        weaponUnlockState.Add("SuperGun", false);
    }

    public bool IsWeaponUnlocked(string weapon)
    {
        if (weaponUnlockState.ContainsKey(weapon))
            return weaponUnlockState[weapon];         
        else
            return false;
    }

    public void UnlockWeapon(string weapon) 
    {
        if (weaponUnlockState.ContainsKey(weapon))
            weaponUnlockState[weapon] = true;
    }
}

public class Player : MonoBehaviour {

    private WeaponUnlockSystem weaponUnlockSystem;

    void Start()
    {
        weaponUnlockSystem = new WeaponUnlockSystem();
        ...
    }

    public void NextWeapon(string weapon) 
    {
        ...
    }
}

Я бы также посоветовал не использовать здесь статический класс для удобства. Статический следует использовать только в том случае, если вы не хотите изменять состояние объекта или вам не нужно создавать экземпляр объекта.

Другие вопросы по теме