Задать вопрос
  • Как лучше организовать структуру БД?


    Но есть "проблема". При добавлении новой фразы для героя, она всегда будет в конце таблицы т.к. это новая запись.
    Т.е. при дополнении таблицы фразами - для 1 героя, для второго, придумали новую фразу для 1 героя, они будут идти в разнобой. Это визуально не удобно для отслеживания, понимания, не красиво.

    Это не проблема. При выборке фраз ты можешь спокойно указать нужный порядок.

    База данных - это не эксель, и даже в экселе это не было бы проблемой благодаря сортировкам.

    Первое что приходит на ум - Одна таблица для всех героев с 3 полями
    id - автоинкремент
    имя героя
    фраза героя

    Лучше для героев завести отдельную таблицу, а в этой таблице держать только id героя.

    Вариант 2. Для каждого героя своя таблица. Таблица Hero1 Hero2 и т.д.
    id - автоинкремент
    фраза героя
    И далее, делать выборку всех записей из таблицы т.к. в ней фразы для нужного героя.
    Просто, интуитивно понятно, все фразы идут "друг за другом", но много таблиц.

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

    Тебе должно быть пофиг, как эти данные структурируются с точки зрения человека.
    Структурируй с точки зрения запросов и программы, которая будет с этими данными работать.
    Ответ написан
    Комментировать
  • Как лучше организовать структуру БД?

    XXXXPro
    @XXXXPro
    Fullstack Web developer
    С точки зрения адекватного проектирования баз данных — однозначно первый вариант (и, желательно, с индексом по имени героя). А если очень хочется просматривать отдельные выборки по героям без дополнительных действий — использовать для этого такую штуку как Views, если база их поддерживает и позволяет редактировать. Но вообще, во всех нормальных менеджерах баз данных есть возможность выборки с фильтрацией по содержимому поля, и лучше использовать их.
    Ответ написан
    Комментировать
  • Как бы вы оптимизировали большую сцену в 2D игре?

    K0TlK
    @K0TlK
    Буллю людей.
    Разделить мир на ячейки, обновлять и отрисовывать только те сущности, которые находятся от игрока на определенном радиусе. Не знаю что там тебе и откуда нужно подгружать, 100 на 100 юнитов это небольшая сцена, все ее содержимое спокойно будет помещаться в оперативной памяти, с диска там ничего подгружать не нужно. Гугли spatial hashing, выбирай алгоритм, который тебе лучше подходит
    Ответ написан
    2 комментария
  • Как бы вы оптимизировали большую сцену в 2D игре?

    mayton2019
    @mayton2019
    Bigdata Engineer
    Когда объекты крупные в сцене то пользователь видит их скорость кадров. Можно ставить 60 fps.
    Когда пользователь смотрит на объекты размером с пиксель - то и не нужно их обновлять часто.
    Сделай хоть 10-15 fps и будет норм.

    Ну тоесть я как-бы взял level of detalization но применительно не к пространству а ко времени.
    Ответ написан
    6 комментариев
  • Как и где хранить данные сохранения игрока в Unity?

    GavriKos
    @GavriKos Куратор тега Unity
    У стима наверняка должно быть свое апи - там же сохранение хранится на серверах стима.

    Но если отбросить стим - то есть PersistentDataPath у юнити - там и храните все что угодно.
    Ответ написан
    1 комментарий
  • Как сделать картинку (панель) на весь экран?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Тут есть несколько моментов.

    1. Перевожу на русский, что вы пытаетесь сделать:
    Взять текущее разрешение экрана (не окна Game, а именно что экрана) - что значит, что у вас в консоли должно выводиться 1920x1080 даже при 1152x864. Если вам нужен размер именно окна Game, то его размеры такие:
    int screenWidth = Screen.width;
    int screenHeight = Screen.height;


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

    Создаёте префаб изначально растянутый на весь экран. Внутри него создаёте пустой объект, который и будете включать и выключать, опять же, растянутый на весь экран. А внутри уже нужный вам фон (тоже растянутый) и панелька с текстом и кнопками.
    Таким образом вам достаточно просто включать выключать пустышку, которая будет работать и с фоном и с панелькой. Вот пример:
    650a16e0729f0813232153.png


    3. Непрошенный совет. Это касается не столько функциональности, сколько архитектуры кода. Если вы хотите качественно улучшить скрипты, попробуйте по мере возможности сразу хардкодить ссылки, тем более что это части одного объекта.
    Вот пример:

    Было
    public class DialogWindowController : MonoBehaviour {
    
    	private GameObject backgroundPanel;
    	RectTransform backgroundPanelRectTransform;
    
    	void OnEnable() {
    		// Получаем ссылку на панель и устанавливаем её размер на весь экран.
    		backgroundPanel = transform.Find("BackgroundPanel").gameObject;
    		backgroundPanelRectTransform = GetComponent<RectTransform>();
    		backgroundPanelRectTransform.sizeDelta = new Vector2(Screen.currentResolution.width, Screen.currentResolution.height);
    
    		// Отладка. Разрешение совпадает с реальным. Всё верно.
    		string str = Screen.currentResolution.width + "x" + Screen.currentResolution.height;
    		Debug.Log(str);
    		using (StreamWriter writer = new StreamWriter("test.txt")) {
    			writer.WriteLine(str);
    		}
    	}
    }


    Стало:
    public class DialogWindowController : MonoBehaviour {
    
    	[SerializeField] private RectTransform _background;
    
    	void OnEnable() {
    		_background.sizeDelta = new Vector2(Screen.currentResolution.width, Screen.currentResolution.height);
    
    		// Отладка. Разрешение совпадает с реальным. Всё верно.
    		string str = Screen.currentResolution.width + "x" + Screen.currentResolution.height;
    		Debug.Log(str);
    		using (StreamWriter writer = new StreamWriter("test.txt")) {
    			writer.WriteLine(str);
    		}
    	}
    }


    Ответ написан
    3 комментария
  • Как исправить ошибку RenderTexture.Create failed: width and height must be larger than 0?

    @SalamiTrain
    Если ошибка стала возникать без изменений в коде, после какого-то действия - есть вероятность, что какое-то из окон стало 0 по одному из измерений - может, ассет превью в инспекторе? Оно, конечно, снеппится, закрываясь, если делать его сильно маленьким, но я не знаю, как обстоит дело в других версиях, у меня 2021.3.23f1
    Можно попробовать выставить один из дефолтных лейаутов редактора, посмотреть, на что это повлияет
    Ответ написан
    1 комментарий
  • Как правильно создавать верхнее меню (жизни монеты) игрока?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Если простым языком, опция Render Mode используется следующим образом:
    1) Overlay - стандартный вариант, когда у вас одна камера на все задачи;
    2) Camera - показать специфический интерфейс для определённой камеры;
    3) World - вообще отвязать от камер, сделав объектом сцены.

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

    Далее размер зоны Canvas-а на сцене. В режиме Overlay он огромен неспроста - он имеет размер экрана. Например, если эран 2960:1440, то и канвас будет иметь такой размер, почти 3к в ширину и 1.5к в высоту. Но на камеру он будет накладываться так, чтобы вложиться в её границы. Единственное неудобство в том, что чисто визуально сложно представить, как это дело будет выглядеть в игре. Чтобы каждый раз не прыгать в плеймод, можно просто вкладку Game расположить где-нибудь рядом. Ну или делать как мои знакомые. Заметил среди знакомых тренд, что они в простых гиперказуалках просто ставят режим Render Mode - Camera и сразу так работают. Сценический размер и положение канваса подстраиваются под камеру и им удобно.

    Касательно масштабирования, обычно разработчики выбирают эталонное разрешение экрана, которое указывают в Canvas Scaler (рядом с Canvas на одном объекте). Там опция - UI Scale Mode, режим Scale With Screen Size. А ползунком ниже указывают как именно интерфейс будет зависеть от ширины и высоты. Затем нужно перейти во вкладку Game и там слева вверху есть выпадающий список с размерами экрана. Нужно выбрать или создать и выбрать то же самое разрешение.

    Если вы хотите, чтобы определённый объект был привязан, например, к левому верхнему краю экрана, этот объект обязательно должен иметь RectTransform. В компоненте вы можете заметить вот такую фичу:
    64742aa24ddcc140401392.png
    Открываем, согласно подсказке жмём Shift+Alt и нажимаем на левый верхний квадрат:
    64742acbe889e101758998.png
    Осталось только в самой компоненте задать такие Pos X / Pos Y, чтобы вам нравились отступы от левого и верхнего краёв экрана.

    Делать основной канвас дочерним игроку - плохая практика. Максимум на уровне префаба и сразу вытащить из игрока при спавне, но и это хз зачем, если её можно сразу поставить на сцену и не мучаться. Если у вас много сцен с таким канвасом, то просто сделайте сам канвас префабом и меняйте его содержимое не для конкретной сцены, а на уровне префаба. Собственно, так обычно и делают, разве что у вас всего 1 сцена игры, на которой вы спавните префаб нужного уровня.

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

    Figma-designer
    @Figma-designer
    Когда камера вложена в объект игрока, она меняет свои позиции относительно игрока, а не мира. Соответственно, когда игрок не в 0, то камера будет отдаляться от игрока и показывать что-то совсем другое.
    Ответ написан
    Комментировать
  • Как исправить скрипт камеры?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Я так понимаю, камеру дочерней сделали вы, чтобы всё спавнить вместе? Если я угадал, тогда вы прямо в префабе можете руками сделать ссылку на игрока, а затем на старте этого скрипта просто вызвать
    transform.parent = null;
    Чтобы отправить камеру в свободное плавание, что и предполагается скриптом слежки.
    Ответ написан
    1 комментарий
  • Влияет ли размер тайлов на игру (быстродействие, отображение)?

    @Ezekiel4
    Охотник на пиратов и сборщик монолитов
    Так как ваша сетка не движется, то единственное, чем она ваш комп грузит - это добавляет свои данные в Draw call Batching. А учитывая специфику этого процесса, выгоднее сделать меньше больших, чем больше маленьких. Но речь идёт о каких-то безумных числах, вроде 10 тыс клеток при условии, что они будут ВСЕ у вас на экране в границах активной камеры. Но даже так, пока изменение тайлмапа (большими порциями за раз) не происходит в рантайме вы не словите каких-то ощутимых лагов.
    Если же говорить про оптимизацию процесса, то выгоднее сделать более мелкую сетку по одной простой причине - вы можете рисовать как одной клеткой за раз, так и их энным количеством (как буд-то вы рисуете более большой сеткой), а вот уменьшить исходно большую если и возможно, то я хз как.
    Ответ написан
    1 комментарий
  • Почему медленно загружается 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 комментарий
  • Как установить префаб по сетке?

    @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

    Ответ написан
    Комментировать
  • Как лучше настроить определение земли игроком?

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

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

    @Zerg89
    Если это планируется как клиент серверное приложение(mmo)то это в корне неправильно, если это просто однопользовательская игра то не важно
    Ответ написан
    Комментировать
  • Будет ли этот код работать некорректно при разной частоте обновления экрана?

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

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

    freeExec
    @freeExec
    Участник OpenStreetMap
    Это не баг, а разные подходы и алгоритмы в физике, имеющие свои плюсы и минусы.
    Ответ написан
    Комментировать
  • Почему не работает вложенное пространство имен?

    Я считаю, что ответ в следующем: автор статьи неправ. К сожалению, в статье отсутствует дата публикации; возможно, такой синтаксис работал какое-то время, а потом его отменили. Мануал на эту тему категоричен:
    импортируемые имена должны быть абсолютными и не обрабатываются относительно текущего пространства имён.


    Возможно, автор статьи имел в виду вот это:
    namespace MyCompany\classes
    {
        $myClass1 = new addons\MyClass1();
    }
    
    namespace MyCompany\classes\addons
    {
        class MyClass1
        {
            function __construct()
            {
                echo 'MyClass1 создан.';
            }
        }
    }
    Ответ написан
    2 комментария
  • Как называть классы, при использовании пространства имен?

    Adamos
    @Adamos
    Классы надо называть так, как завещано патриархами программирования - с использованием существительного. Ваше String - скорее прилагательное, вы забыли указать, что именно делает этот класс со строками. StringParser? StringContainer?
    StringTester, наконец, по тому огрызку кода, что тут приведен :)
    Ответ написан
    2 комментария
  • Как называть классы, при использовании пространства имен?

    @Vitsliputsli

    Писать пространство имен полностью, что не очень красиво AnotherPHPProject\Strings()

    Не устаю писать, красиво это не когда мало букв, а когда все понятно с первого взгляда.
    IDE подставит за вас длинный namespace. А по нему отлично видно, что данный класс не внутренний, а подключенная внешняя зависимость.
    А вот алиасы часто использовать не очень хорошо, т.к. по нему сразу не видно, что это за класс.
    Ответ написан
    1 комментарий