• Почему медленно загружается xml файл?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Есть несколько рекомендаций:
    1. Используйте асинхронный код. Что-то типа такого:
    public static async void SetXMLValue(string pathToXMLFile, string nodeName1, string nodeName2, string nodeName2Value) {  
        TextAsset textAsset = Resources.Load<TextAsset>(pathToXMLFile);
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(textAsset.text);
        XmlNode node = xmlDoc.SelectSingleNode("/" + nodeName1 + "/" + nodeName2);
        node.InnerText = nodeName2Value;
        await File.WriteAllTextAsync(Application.dataPath + "/Resources/" + pathToXMLFile + ".xml", xmlDoc.OuterXml);
    }

    2. Используйте более быстрые методы чтения и записи XML. Вместо стандартных методов XmlDocument.LoadXml() и XmlDocument.OuterXml вы можете использовать XmlReader и XmlWriter. XmlReader позволяет читать XML файлы по мере их поступления и не хранить их в памяти целиком, что позволяет сократить время чтения. XmlWriter позволяет записывать XML файлы по мере их создания, что позволяет сократить время записи.
    3. Используйте кэширование данных в памяти. Вместо того, чтобы каждый раз читать настройки из XML файла, вы можете загрузить их в память при запуске программы и хранить в памяти. При изменении настроек вы можете обновить их как в памяти, так и в XML файле. Это позволит избежать чтения XML файла каждый раз при обращении к настройкам.
    4. Используйте более быстрый способ доступа к файлам. Вместо использования метода File.WriteAllText() вы можете использовать методы доступа к файлам, которые более быстры и оптимальны для Unity, например, System.IO.MemoryMappedFiles.
    5. Если вам и правда так припекло использовать XML, вы можете немного ускорить процесс, оптимизировав его структуру. Например, выделить для каждой локали по отдельному файлу. Но лично я вам советую познакомиться с форматом JSON, тем более в юнити есть хороший нативный инструмент JsonUtility, а в шарпе newtonsoft.json.

    Но если ваша цель не решить интересную задачу, а просто иметь под рукой хороший инструмент, советую вам не мучать себя, а просто воспользоваться пакетом Unity.Localization. Ну или если у вас есть лишних $45, то пакетом i2 в ассет сторе.
    Ответ написан
    1 комментарий
  • Скажите пожалуйста правильно я пользуюсь PlayerPrefs в Unity?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Есть несколько рекомендаций:
    1) Загрузка. В строке
    PlayerPrefs.GetInt("money");
    Вы загружаете данные из базы, но никуда не сохраняете. Нужно написать так:
    Money = PlayerPrefs.GetInt("money");

    2) Обновление. Обновлять данные, используя
    void Update() {
    	PlayerPrefs.SetInt("money", Money);
    }

    Но это всё равно, что если вы целый день за рулём, а ваш пассажир каждую секунду спрашивает "мы уже приехали?", "А теперь мы приехали?", "А теперь???".

    Лучше данные сохранять тогда, когда они меняются. Например, добавим метод:
    public void SetMoney(int money) {
    	// Поменяли
    	Money = money;
    	// Сохранили
    	PlayerPrefs.SetInt("money", Money);
    }

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

    3. Раз мы создали метод изменения денег, но у нас всё равно осталось публичное поле, то его стоит спрятать, чтобы случайно не вызвать логику изменения без сохранения в базу (вы же не хотите чтобы ваши игроки читерили, узнав о таком способе?). Потому делаем поле приватным и добавляем геттер:
    private int Money;
    
    // ...
    
    public int GetMoney() {
    	return Money;
    }


    4. Ваше поле Money имеет значение по умолчанию 1, но из базы загружается значение по умолчанию 0. Поэтому метод загрузки мы исправим вот так:
    Money = PlayerPrefs.GetInt("money", 1);

    В итоге получается такой код:
    using UnityEngine;
    
    public class MoneyScriptDemo : MonoBehaviour {
    
    	private int Money = 1;
    
    	private void Start() {
    		Money = PlayerPrefs.GetInt("money", 1);
    	}
    
    	public void SetMoney(int money) {
    		Money = money;
    		PlayerPrefs.SetInt("money", Money);
    	}
    
    	public int GetMoney() {
    		return Money;
    	}
    
    	public void SaveGame() {
    		PlayerPrefs.Save();
    	}
    }


    PS. Ну и так как мы не в Java, а в C#, то вместо геттера и сеттера можем написать аксессор:
    using UnityEngine;
    
    public class MoneyScriptDemo : MonoBehaviour {
    
    	private int Money = 1;
    
    	public int money {
    		get => Money;
    		set {
    			Money = value;
    			PlayerPrefs.SetInt("money", value);
    		}
    	}
    
    	private void Start() {
    		Money = PlayerPrefs.GetInt("money", 1);
    	}
    
    	public void SaveGame() {
    		PlayerPrefs.Save();
    	}
    }
    Ответ написан
    Комментировать
  • Почему Instantiate иногда создаёт объект не в том месте?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Уверен, что проблема в том, что коллайдер пистолета выталкивает коллайдер пули. Это можно проверить в редакторе создав пулю в месте её спавна, а затем, выбрав одновременно пистолет и пулю, посмотреть, не сталкиваются ли их коллайдеры. Проблему можно решить двумя путями:
    1) Переместить точку выстрела туда, где точно нет коллайдеров
    2) Отменить коллизию. Для этого нужно создать два Layer - для пистолета и пули, затем в Edit/Project Settings/Physics в самом низу есть схема коллизий. Там нужно снять одну галочку, между слоем пули и слоем пистолета.

    Если это не помогло, пришлите скрипт оружия и скрипт (если такой есть) пули в комментарий к этому сообщению, посмотрим, мб там что-то влияет.
    Ответ написан
    4 комментария
  • Почему не работает триггер в юнити 3д?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Повесьте на движущийся объект Rigidbody и тогда всё будет работать.
    Ответ написан
  • Почему значение статической переменной не меняется?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Если источник имеет коллайдер, результатом вы всегда будете получать источник. Только поэтому у вас не выпала NullPointerException. Метод Physics2D.Raycast всегда возвращает объект, но его поле collider может быть пустым (null), если луч ушёл в пустоту, тогда попытка вызвать метод collider.CompareTag вообще провалится.
    Если не хотите сильно заморачиваться, просто создайте слой, например, Player и повесьте его на игрока. Таким образом вы заодно избавитесь от необходимости проверять тег.
    https://docs.unity3d.com/ScriptReference/Physics2D...
    Как вы можете увидеть по ссылке выше, метод имеет перегрузку:
    // поле класса
    public LayerMask playerLayer;
    // метод из примера
    RaycastHit2D hitInfo = Physics2D.Raycast(ray2D.origin, ray2D.direction, 10, playerLayer);
    Ответ написан
    Комментировать
  • Почему нельзя выбрать continuous dynamic в collision detection?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Потому что алгоритм Continuous Dynamic это изменённый Continuous с учётом трёхмерности объекта, а вы смотрите двухмерный компонент.
    Ответ написан
  • Почему игрок ходит по стенам?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Зависит от реализации. Не видя зная могу предположить, что дело в наличии силы трения. Создайте физический материал без трения и наложите на коллайдеры нужных объектов.
    Ответ написан
    Комментировать
  • Как лучше настроить определение земли игроком?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    1. Убираете Capsule Collider 2D, вешаете Box Collider 2D
    2. Делаете коллайдеру скругление (да, там есть такая опция), чисто чтобы за углы не цеплялся
    3. Делаете не одну большую точку, а маленьких штуки две (по краям) или три (одна в центре, если у вас есть узкие платформы)
    4. Ищете землю условием ИЛИ. Profit

    Важно, чтобы края поиска земли не доставали до левого и правого краёв коллайдера и при этом был включен режим Rigidbody2D collision detection = continuous. Тогда всё будет работать отлично.
    Ответ написан
    Комментировать
  • Как установить префаб по сетке?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    1. Зная размерность сетки, можно руками поправить координаты в Transform
    2. Можно перетащить префаб во вкладку Hierarchy, а затем перетащить на нужное место через Move Tool с зажатой Ctrl
    3. Можно поместить сразу как надо, и, держа открытой вкладку "Edit >> Grid and Snap Settings...", нажать кнопку "All Axes", и если оно неправильно округлило, то используя способ 2, дотянуть немного.
    4. Можно самому написать скрипт, типа такого:

    скрипт

    using UnityEngine;
    using UnityEditor;
    
    public class SnapPrefab : MonoBehaviour {
        public float cellSize = 0.5f;
    
    #if UNITY_EDITOR
        private void OnValidate() {
            Snap();
        }
    #endif
    
        public void Snap() {
            Vector3 position = transform.position;
            position.x = Mathf.Round(position.x / cellSize) * cellSize;
            position.y = Mathf.Round(position.y / cellSize) * cellSize;
            position.z = Mathf.Round(position.z / cellSize) * cellSize;
            transform.position = position;
        }
    }
    
    #if UNITY_EDITOR
    
    [CustomEditor(typeof(SnapPrefab))]
    public class SnapPrefabEditor : Editor {
        public override void OnInspectorGUI() {
            base.OnInspectorGUI();
    
            if (GUILayout.Button("Snap")) {
                SnapPrefab script = (SnapPrefab) target;
                script.Snap();
            }
        }
    }
    
    #endif

    Ответ написан
    Комментировать
  • Как отключить использование игрой webgl 2.0 в браузере?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Никто не запрещает вам установить версию 2021 и делать там, пишут что в 2022 тоже можно сделать (2022 не проверял). А вот 2023 её просто нет. Пруф
    https://forum.unity.com/threads/webgl-1-deprecatio...
    Ответ написан
    Комментировать
  • Как достать код скрипта из собранного apk файла (il2cpp)?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    При сборке il2cpp точный исходный вид обратно восстановить уже 100% не получится, как минимум потому что теряются исходные наименования (да, я в курсе про global-metadata.dat и дампы ошибок, но их может не быть, а если и есть - это гемор для избранных). Да и задачка там сводится, по сути, к обратному преобразованию из низкоуровневого кода.

    Мне думается, что проще заново написать.. но если вам не влом, можете полазить по гитхабу, там китайцы несколько проектов ведут. Типа такого (не проверял) - https://github.com/Perfare/Il2CppDumper
    Ответ написан
    Комментировать
  • Как можно проверить какой скрипт создает объект?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Если у вас нормальная IDE, можете запустить поиск по всем файлам метода Instantiate. А если не влом руками поковыряться, можете выключить все объекты сцены и понемногу их включать перед каждым перезапуском, проверяя, не прошёл ли спавн.
    Ответ написан
    3 комментария
  • При создании нового проекта в Unity вылазит Enter Safe Mode, что делать?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Сложно сказать, какая тут конкретно проблема. Если у вас нет специфических запросов к Unity, требуюших новейшую версию, то можете просто удалить эту и установить последнюю 2020.* Несмотря на кажущуюся старость, она очень норм.

    Если хочется пободаться с ошибками, то тут может быть много вариантов. Сперва на ум приходит возможность проблем с установкой:
    1) Было мало памяти на диске и не всё установилось;
    2) Некоторые целевые папки были защищены от записи правами учётных записей и туда тоже ничего не установилось;
    3) В системе не найдена или недоступна требуемая DLL;
    4) Антивирус вмешался в процесс установки редактора или вмешивается в процессе работы.
    Но такие ошибки всегда показывают предупреждения и вы бы их не пропустили. Но я допускаю вероятность, что могут быть случаи и без видимых ошибок, поэтому лучше всё проверьте.

    Думая о запросе входа в безопасный режим, на ум приходит невозможность юнити скомпилировать пустой проект, что может быть вызвано:
    5) Недопустимыми символами в пути к проекту;
    6) Нехваткой оперативной памяти;
    7) Ошибкой настройки самого компилятора (например, неверный путь в переменных среды).
    Опять же, всё руками проверить.

    Не нулевая вероятность и проблем с самими пакетами, например:
    8) Пакеты установились с ошибками или имеют ошибки в процессе работы.
    Тут может помочь очистка кеша/реимпорт пакетов.

    Может было что-то ещё, но я сходу не вспомню.
    Ответ написан
  • Как реализовать множественную фильтрацию OfType c LINQ?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Обратите внимание на метод Concat(). С его помощью можно красиво объединять результаты фильтрации.
    var methods = assembly
        .GetTypes()
        .SelectMany(t => t.GetMethods())
        .Where(m => m.GetCustomAttributes().OfType<UpdateHandleAttribute>()
            .Any(v => (v.GetType().GetProperty("Data").GetValue(v).ToString() == data || 
                v.GetType().GetProperty("Data").GetValue(v).ToString() == "*") 
                && v.GetType().GetProperty("State").GetValue(v).ToString() == state.Id.ToString()))
        .Concat(assembly.GetTypes()
            .SelectMany(t => t.GetMethods())
            .Where(m => m.GetCustomAttributes().OfType<AnotherAttribute>().Any()));
    Ответ написан
    Комментировать
  • Какую виртуальную учебную доску (похожую на Miro) можно интегрировать на сайт?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Нужно уточнить спецификации, что конкретно нужно. Вариантов досок много, можно хотя бы начать с их стоимости. Указанный вами Miro очень хорош, и я не могу представить чем он не угодил, но если нужны альтернативы, могу привести минимум 3: Conceptboard, Padlet и Stormboard. Все три норм, но если бы мне нужно было выбрать что-то одно, то это Conceptboard просто из-за простой интеграции с другими сервисами, типа Google Drive и Slack.
    Ответ написан
    Комментировать
  • Как выполнять енное действие через определенное время в Unity?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Способов много. Вот два неплохих - через Invoke и корутины соответсвенно. Плюсы и минусы обоих лучше погуглите, но для вашего запроса в данном случае всё равно какой брать:

    Invoke:
    using UnityEngine;
    
    public class TimerInvokeDemo : MonoBehaviour {
    
    	private void Start() {
    		Debug.Log("Заводим будильник...");
    		Invoke("Example", 5);
    	}
    
    	private void Example() {
    		Debug.Log("Пора на завод.");
    	}
    }


    Корутина:
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class TimerCoroutineDemo : MonoBehaviour {
    
    	private void Start() {
    		StartCoroutine(Example());
    	}
    
    	private IEnumerator Example() {
    		Debug.Log("Заводим будильник...");
    		yield return new WaitForSeconds(5);
    		Debug.Log("Пора на завод.");
    	}
    }
    Ответ написан
    1 комментарий
  • Как исправить ошибку с текстом в юнити3д?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Если верить тексту ошибки, то у вас либо вообще не задана текстура, либо она имеет 0 размер. Такое ещё может быть, что материал по умолчанию потерял ссылку на текстуру атласа шрифта. Если и это не поможет, попробуйте просто удалить и заново импортировать дополнение.
    Ответ написан
    Комментировать
  • Как убрать синхронизацию скайбоксов при переходе между сценами?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Тот скайбокс, что вы поставили во вкладке Lightning, это стандартный общий. Переопределить настройки можно компонентой Skybox для каждой сцены, в которой он будет отдельно. Добавьте на сцену и перетащите туда нужный вам материал неба.
    Ответ написан
  • Хочу сделать типо босс файта, чтобы анимации которые я добавлю в список были рандомными, но у меня куча ошибок, что делать?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    1) Основа вашей идеи - это компонент Animator, на который у вас нет ссылки.
    2) Метод SetBool() имеет два аргумента: ключ и значение вида true или false.
    3) В блоках вида
    if (animText[1] == 1)
    Вы сравниваете элемент списка под номером 1, то есть строку, с числом. Строка это текст, не число.
    4) Ниже вы прописали корутину, которую никто не запускает
    5) Корутина не имеет паузы
    yield return new WaitForSeconds(нужное_время);
    6) В строке
    animText = Random.Range (1f,4f);
    Вы пробуете вставить в ссылку типа списка строк нецелое число.
    7) Допустим, у вас всё бы работало, но SetBool это такой переключатель, который обратно сам не возвращается, он остаётся в состоянии, в которое вы его поставили.

    Критикуя-предлагай, поэтому вот что я скажу.

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

    Как это будет выглядеть:
    using UnityEngine;
    
    public class BossAnimator : MonoBehaviour {
    
    	// Ссылка на аниматор босса
    	[SerializeField] Animator anim;
    
    	// перечень триггеров анимации
    	// убедитесь, что там нет null элементов
    	[SerializeField] string[] triggers;
    
    	// Метод, который начнёт весь движ
    	// Как и где его вызывать - решайте сами по ситуации
    	public void StartFight() {
    		OnAnimationEnded();
    	}
    
    	// Данный метод нужно привязать как событие
    	// к концу каждой анимации
    	public void OnAnimationEnded() {
    		// Выбираем случайный номер из списка - наш следующий триггер
    		int nextTriggerIndex = Random.Range(0, triggers.Length);
    		// Применяем
    		anim.SetTrigger(triggers[nextTriggerIndex]);
    	}
    }

    Разумеется, скрипт сырой и можно его доработать соответсвенно специфик игры, о которых я не знаю, но в целом он универсален, так как вы в инспекторе босса сами можете назначить перечень любых триггеров анимации в любом количестве.
    Ответ написан
    5 комментариев
  • Будет ли этот код работать некорректно при разной частоте обновления экрана?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Заметный эффект будет при переворачивании огромных изображений. Проблемой в этом коде является отслеживание ввода в FixedUpdate. У вас поля ввода (horizontalInput и verticalInput) и так уже в контексте класса, просто перенесите считывание внутрь Update.

    Если вас волнуют микрооптимизации, то рекомендую для начала узнать, что в конструкции if-else может использоваться блок else if
    Ответ написан
    1 комментарий