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

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

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

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

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

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() для каждого оружия. Тоже не практично.

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

Спасибо


person StuckInPhDNoMore    schedule 27.05.2019    source источник
comment
Каким образом вы считаете это непрактичным? Конечно, есть и другие решения, но нам нужен контекст того, чем вы недовольны.   -  person Adam G    schedule 27.05.2019
comment
Поскольку скрипт находится на игровом объекте, и каждый раз, когда он вызывается, вызывается Start(), который сбрасывает все разблокированные значения. Также мне придется сделать его постоянным через DontDestroyOnLoad() через сцены?   -  person StuckInPhDNoMore    schedule 27.05.2019
comment
Просто создайте класс, который не является моноповедением, со стандартными логическими переменными и используйте ссылку на этот класс в чем-то вроде GameManager?   -  person Jichael    schedule 27.05.2019
comment
Возможный дубликат Лучший способ сохранить данные в игре Unity   -  person derHugo    schedule 27.05.2019


Ответы (2)


Вы создаете класс, который не является 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) 
    {
        ...
    }
}

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

person Mirko Brandt    schedule 28.05.2019

Недавно у меня был проект 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, чтобы он работал.

person CasualViking    schedule 28.05.2019