Зато все понятно...
Реальный кусок кода из банковского сервиса
Реальный кусок кода из банковского сервиса
Очень люблю слушать музыку на пк во время работы через приложение "Яндекс.Музыка" (не реклама), но меня раздражает что у нее нет мини виджета по переключению музыки, или нужно открывать приложение, или использовать кнопки на клавиатуре, коих к сожалению нет на раб ноуте.
У меня появилось желание сделать два самописных виджета для переключения треков и поделится им с сообществом пикабу, вдруг кому-нибудь оно тоже пригодится.
Первый виджет является обычным вызываемым окном через панель значков винды, который показывает название трека, исполнителя и обложку и 3 кнопки, две их которых отвечают за переключение треков, и одна соответственно pause\play.
Второй виджет выполняет аналогичную функцию, только он работает как виджет рабочего стола. который можно перемещать и менять размер через правую кнопку мыши.
Вот ссылка на гитхаб https://github.com/Mistreds/MusicWPF. Readmi к проекту честно писать лень, он элементарный, запустил и пользуйся. Самораспаковывающиеся архивы где Release, MusicWidget виджет для раб стола, MusicControl, всплывающий виджет для панели значков
Но есть несколько но, проект написан на C# в среде .Net 6, для переключения треков используется win sdk, так что проект поддерживается только на windows 10 (возможно и windows 11, я не проверял).
Проверенные плееры:
-Яндекс музыка приложение (работает)
- Яндекс музыка браузерная версия (работает только play\pause и получает название треков без обложки)
-Youtube (когда играет в плейлистах работает переключение, а так получает название, автора канала и обложку видео)
-AIMP (не работает)
-Windows media player (не знаю кто им пользуется, но не работает)
По факту приложение должно поддерживать все плееры, информацию с которых может получать windows. То есть трек должен отображаться в меню когда изменяешь громкость кнопками на клавиатуре.
Прошу прощение за возможные ошибки. Очень надеюсь что приложение может кому то пригодится. Так же разных трупрограммистов прошу за исходный код приложения не осуждать, делал лишь бы работало.
Возможно, кто-то может помочь с поиском работы относительно начинающему .Net разработчику (относительно, потому HR специалисты говорят: "Ваш уровень - уверенный Junior+, но нам нужен мидл или синьор")
Может дело в том, что я очень сильно нервничаю на собесах или просто так складывается, но уже месяц тщетно пытаюсь найти новую работу.
В предыдущих сериях: я собрался написать туториал как создать игру на Unity с нуля и рассказал об этом тут, затем мы установили необходимые программы, создали проект и даже начали делать главное меню. Сегодня продолжаем.
Краткое содержание:
• Скроллинг текста
• Создание скрипта
• Скрипт работы кнопок главного меню
• Внешние ссылки
• Создание локализации с помощью JSON
Сейчас мы сделаем поле для блока "Дополнительно". В своей игре в этом блоке я расположил благодарности членам комьюнити ВК, которые активно срутся в беседе помогают развивать игру. Этот пункт меню в принципе не обязателен, однако на нём мы потренируемся работать с компонентом для скроллинга текста (это один из примархов нашей игры).
Создайте новое поле extrasList аналогично предыдущим. Затем добавьте ему дочерний пустой объект viewport, которому так же добавьте дочерний объект content. В итоге у нас получилась своеобразная матрёшка extrasList -> viewport -> content.
К extrasList прикрепляем компонент Scroll Rect. Эта важная курица будет контролировать работу скроллинга содержимого.
В качестве Content установите наш одноимённый объект content, уберите галочку с Horizontal (нам пока не требуется горизонтальный скроллинг), Movement Type --> Clamped, Viewport --> viewport.
• Movement Type отвечает за поведение контента при достижении нижней или верхней точки скроллинга. Unrestricted унесёт содержимое в дальние дали, Elastic даст ему плавно отскочить и вернуться назад, а Clamped просто резко остановит.
Не хватает только полосы прокрутки. Создайте для extrasList дочерний объект UI/Scrollbar. Как видите - у него есть два компонента (Image и Scrollbar) и два дочерних объекта. В первую очередь сделаем его вертикальным. Для этого в компоненте Scrollbar установите Direction --> Bottom to Top. Теперь нужно разместить его в правой части extrasList и растянуть на всю высоту экрана. Это, равно как и изменение его цветов вы теперь сможете сделать самостоятельно ;) Когда всё будет готово, назначьте объект Scrollbar в качестве Vertical Scrollbar в компоненте Scroll Rect.
Далее сделайте размеры viewport и content побольше - подстать extrasList - и добавьте текстовый компонент в content. Для корректного отображения скроллинга в content нужно добавить еще один компонент - Content Size Fitter и установить:
Horizontal Fit --> Unconstrained
Vertical Fit --> Preferred Size
• Обычно для конструкций скроллинга требуется установка компонента Mask для объекта viewport. Этот компонент будет скрывать текст за пределами границ viewport. Сейчас он нам не нужен, так как текст доходит до края экрана.
При желании попробовать добавьте компоненты Mask и Image для viewport и отключите у Mask галочку на Show Mask Graphic. Текст будет обрезаться на границах viewport.
Полюбуемся результатом.
• В правом нижнем углу можно разместить кнопки, ведущие в ваш Дискорд, ВК, сайт итд. Можете этого не делать, но я далее все равно покажу как это прописать в скрипте.
Каждую сцену нужно добавлять в билд через меню File - Build Settings. Причем сцена, зарегистрированная под номером 0 будет являться стартовой. Давайте добавим нашу сцену в билд.
Я долго откладывал этот момент, но больше тянуть кота за яйца смысла нет - будем писать код. Сейчас нам нужно заставить работать все (ну, почти) кнопки меню.
ВАЖНО! Я постараюсь максимально понятно и просто объяснить что и как работает, но знайте - мои объяснения не обучат вас C#. Вы просто научитесь пользоваться теми функциями, которые использую в своей игре я. Обязательно ищите дополнительную информацию, читайте справочники и учебники и шерстите форумы каждый раз, когда вам что-то непонятно.
Откройте Notepad++ или любой другой редактор кода. Измените кодировку на UTF-8, а синтаксис на C#. Затем сохраните файл как mainMenu.cs в папку Assets/Scripts.
В самом начале скрипта нам нужно указать необходимые пространства имен - говоря проще хранилища функций, которые мы будем использовать. Объяснение каждого из них займёт очень много места и времени, поэтому просто скопируйте их.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine.SceneManagement;
Затем создайте класс mainMenu - он должен называться так же как и сам файл. К классу допишите : MonoBehaviour - это означает наследование от базового класса Unity.
В первую очередь создадим метод для работы кнопки "Новая игра". По плану он должен открывать поле справа, где игрок сможет выбрать слот для новой игры и начать её.
Нам понадобится переменная типа GameObject, которая будет указывать на поле newGameList.
public class mainMenu : MonoBehaviour {
public GameObject newGameList;
}
Слово public перед переменной означает, что она будет доступна для других классов. Пока что все переменные и методы мы будем делать публичными.
Теперь создадим метод menuNewGame(), который будет показывать/скрывать newGameList. Фактически он проверяет активен ли объект newGameList в иерархии - если да, то скрывает, а если нет, то активирует.
public void menuNewGame() {
if (newGameList.activeInHierarchy == true) newGameList.SetActive(false);
else {
newGameList.SetActive(true);
}
}
Подробнее о конструкции if... else
Старайтесь всегда соблюдать отступы в коде и не лепить всё в одну кучу - это просто удобно для чтения.
Теперь сохраним файл и вернемся в Unity. Чтобы всё заработало как надо, мы должны прикрутить к кнопке newGame скрипт mainMenu в качестве компонента. Затем в этом компоненте в поле newGameList указать одноимённый объект. В компоненте Button в событии On Click () укажите нашу кнопку и выберите из списка наш новый метод menuNewGame().
Теперь можно запустить игру и посмотреть как работает кнопка. Если не работает - ищите где что пропустили :)
Аналогичную операцию с переменной, методом и назначением скрипта нужно проделать с кнопками "Загрузить игру", "Настройки" и "Дополнительно".
• Тут есть одна важная деталь. Каждый раз прикручивая скрипт к кнопке, нам придется назначать в инспекторе переменные. Это особенность редактора Unity. Можно, конечно, делать отдельный скрипт и класс для каждой кнопки, но это шило на мыло. А расписывать всё только через скрипт мы не будем (пока что...).
Обратите особое внимание на то, чтобы в каждом методе активация одного поля меню приводила к деактивации другого.
Как видите, я постоянно делаю пометки красным цветом. Это не очень удобно в скриптах - там для этого есть отдельный инструмент комментариев. Если вы поставите двойной слеш //, то вся остальная часть строки будет превращена в комментарий, который никак не будет учитываться компилятором. В комментарии можно заключать сразу целые блоки кода с помощью /* закомментированный блок */.
Всегда комментируйте свой код - причем делайте это так, чтобы ваши записи были понятны другому человеку. Это облегчает работу, понимание структуры, поможет вспомнить свой код. Да и просто это правило хорошего тона.
Я даже специально скриншот для этого сделаю.
Конечно же нет смысла комментировать каждую строку - это слишком громоздко. Я сделал это в качестве примера. Однако, указывать вкратце что и как делает очередной метод стоит. Не перенебрегайте этим! Спасибо мне потом скажете.
Теперь сделаем скрипт для кнопок "Выход" и ссылок на соцсети. Для выхода из приложения используется простая команда Application.Quit(); Её нужно добавить в метод exitGame() и описанным ранее способом привязать к кнопке exit.
Для перехода по ссылке используем команду Application.OpenURL("адрес ссылки"); аналогичным образом.
• Экономьте время и силы. Прикрепите скрипт mainMenu к одному объекту, сделайте все привязки, затем скопируйте компонент. Выделите все необходимые объекты и массово вставьте скопированный компонент со всеми привязками.
Это далеко не единственный способ программировать кнопки. Программирование - это достаточно гибкая штука. Способов, которыми можно реализовать выполнение задачи множество и ни один из них не может быть универсальным идеалом. Ваша задача - найти самый удобный для себя.
Сейчас мы просто обязаны немного поговорить о тексте. Как его хранить в игре?
1. Прописывать прямо в скрипт. Это наихудший вариант из всех, которые только можно представить. Громоздкие файлы, низкая читабельность кода, презрение коллег по цеху, низкая самооценка. Никогда не пишите текст в ваших скриптовых файлах! Ни единого слова!
2. Хранить его в отдельных текстовых файлах, а затем импортировать с помощью библиотек LINQ. Это хороший способ - я так поначалу и делал. На каждую сцену у меня был свой текстовый документ со строками необходимого текста. Проблема наступила, когда его стало слишком много и я начал теряться в структуре. Вторая проблема наступила, когда я решил добавить несколько языков в локализацию - это создало необходимость делать более громоздкий код и в разы больше файлов.
3. Хранить текст в JSON. Этот вариант на данный момент идеален для меня, так как я готовлю локализацию с 11 языками. Этот формат позволяет мне поддерживать хранение текста сразу блоками, а не строками и структурировать его. Подробнее про формат JSON можно почитать тут.
Вот этот формат мы и будем использовать на протяжении всего туториала. Я крайне редко встречал уроки (возможно даже и не встречал) и курсы, где с самого начала ученику предлагают хранить информацию в JSON, так что это будет своего рода эксперимент.
Схема будет такая:
• Создаем базу данных текста в Excel или Google Таблицы
• Создаем класс под эту базу данных в проекте
• Импортируем БД в JSON и добавляем в проект
• Создаем скрипт, распаковывающий JSON, и расставляющий значения переменных текста
Благодаря возможностям JSON, мы сразу получаем возможность делать локализацию своей игры - переводить её на другие языки. Не вижу смысла откладывать эту тему на потом. Такие серьезные моменты лучше решать сразу.
Я буду объяснять на примере Гугл Таблиц (Google Spreadsheets), но тут с Excel различий мало. Создайте новую таблицу.
• В программировании первая цифра, первый элемент, первый объект - это всегда ноль. Всё начинается с нуля. Привыкайте считать с нуля и тогда вы не словите когнитивный диссонанс при написании кода.
Поле id нам нужно по большей мере для себя - чтобы не путаться, а также для повышения производительности. Оно будет нумерально совпадать с индексом элемента в списке, который мы создадим позднее. Начинайте его всегда с нуля и по порядку.
Key - это поле нам нужно для упрощенного обращения к элементу. Мы будем "вызывать" элемент по Key и требовать "какие ваши доказательства" предоставить необходимое значение.
• Не забудьте внести в таблицу весь текст главного меню - кнопки меню, заголовки настроек, текст из "Дополнительно".
• Обратите внимание, что названия языков мы не вносим в таблицу. Они отображаются в родном начертании в компоненте Dropdown объекта optionsList - language - Dropdown.
Хорошо, сделали - что дальше? Как запихать это в игру? Для начала нам нужно превраить нашу таблицу в json. Сохраните её в xlsx - стандартный формат экселя, который поддерживается и гугл таблицами. Далее зайдите на сайт, сохраните его, создайте его закладку, выбейте татуировку ссылки на левой руке - Beautifytools (https://beautifytools.com/excel-to-json-converter.php). Откройте с помощью него нашу таблицу и экспортируйте в json.
Нам понадобится новая папка для хранения текстовых баз данных (а у нас уже именно база данных, представьте себе). Assets/Resources/textDB
Там нам понадобится новый файл с кодировкой UTF-16 LE с BOM и синтаксисом JSON.
Добавляем конвертированную в джейсон таблицу в файл и получаем следующий результат.
• Если вам непонятно почему это так расположено и что это за знаки, то почитайте про синтаксис JSON
Теперь всё это нужно аккуратно запихать в игру. Для начала нам потребуется новый скриптовый файл dataBase.cs. Добавьте ему такие же пространства имен, как и файлу mainMenu. Этот файл будет содержать классы для импорта различных таблиц в формате JSON.
Импорт будет происходить в список List<> - этот класс в языке C# позволяет хранить объекты одного типа, добавлять/удалять элементы, сортировать и прочие прелести жизни. Каждый блок из файла json будет рассматриваться как отдельный объект и импортироваться в список, откуда мы его с лёгкостью будем использовать в игре.
Создадим в скрипте dataBase.cs класс TextDB, в котором объявим список List<Textdata>. Textdata - это класс, который описывает наши текстовые объекты.
• Разъяснение. Текстовым объектом в нашем случае является каждая строка таблицы со своим id, Key и блоками russian, english, japanese.
Так, класс Textdata мы уже начали использовать, однако еще не объявили. Какое нахальство! Давайте скорее это сделаем, пока компилятор не надавал нам по рукам. В этом же скрипте объявите класс Textdata. В нём нам потребуются переменные согласно столбцам таблицы.
public int id; // int - это 32-битный формат целых чисел от -2147483648 до 2147483647
public string Key; // string - это строковый формат. Хранит одну строку текста
public string russian;
public string english;
public string japanese;
"Одна строка" - понятие растяжимое. В языке программирования знак переноса строки ( '\n') - это такой же символ как и буква. Переменная формата string может содержать очень много текста - до 2^31 символов (2 147 483 648).Подробнее о типах данных
Осталась "мелочь" - написать в скрипте mainMenu.cs команду на импорт базы текста и подставить значения в зависимости от языка. Классы, которые наследуют от MonoBehaviour могут использовать специальные методы движка Unity. В нашем случае потребуется метод Start() который выполняется сразу после инициализации объекта. В него мы и добавим инструкции по импорту базы. Также понадобится объявить переменную textDatabase класса TextDB.
public TextDB textDatabase;
void Start() {
TextAsset asset0 = Resources.Load("textDB/mainMenu") as TextAsset;
textDatabase = JsonUtility.FromJson<TextDB>(asset0.text);
}
Для того, чтобы видеть в инспекторе нашу базу данных, добавьте в скрипте dataBase.cs перед классами строку [System.Serializable].
Теперь, если вы запустите игру и выберете объект, к которму прикреплён скрипт mainMenu, вы увидите список импортированных тесктовых объектов.
Прекрасно! Следующий шаг - это настроить функцию выбора языка. Язык мы выбираем при помощи всплывающего списка Dropdown в разделе настроек. Давайте создадим для него переменную public Dropdown langDropdown, чтобы было проще к нему обращаться. Также в скрипте mainMenu создадим новый метод setLanguage(). Прикрепите скрипт mainMenu к объекту Dropdown и в поле Lang Dropdown укажите этот объект. В разделе On Value Changed прикрепите метод setLanguage().
Что будет происходить? Каждый раз, когда вы будете выбирать язык во всплывающем меню, будет меняться числовое значение Dropdown и вызываться метод setLanguage(). У каждого языка получится свой порядковый номер: русский - 0, английский - 1, японский - 2. На основании этого номера мы и будем менять текстовые блоки.
Для быстрого доступа к текстовым блокам создадим для каждого из низ переменную класса Text и назначим их соответствующим полям скрипта mainMenu в инспекторе.
public Text newGameText;
public Text loadGameText;
...
Однотипные переменные можно объявлять через запятую.
public Text newGameText, loadGameText, optionsText, extraText, exitText, langText, audioText, musicText, creditsText;
Теперь напишем смену блоков текста при помощи оператора switch. Этот оператор похож на if...else. Также мы применим цикл foreach, который будет перебирать элементы списка с текстом и выбирать нужный согласно критерию. Критерием будет значение Key. Значение из Dropdown получим с помощью запроса langDropdown.GetComponent<Dropdown>().value
Подробнее об операторе switch можно почитать здесь
Подробнее о циклах и цикле foreach
public void setLanguage() {
switch (langDropdown.GetComponent<Dropdown>().value) {
case 0:
foreach (Textdata p in textDatabase.text) {
if (p.Key == "newgame") newGameText.text = p.russian;
else if (p.Key == "loadgame") loadGameText.text = p.russian;
else if (p.Key == "options") optionsText.text = p.russian;
else if (p.Key == "extra") extraText.text = p.russian;
else if (p.Key == "exit") exitText.text = p.russian;
else if (p.Key == "language") langText.text = p.russian;
else if (p.Key == "ambience") audioText.text = p.russian;
else if (p.Key == "music") musicText.text = p.russian;
else if (p.Key == "credits") creditsText.text = p.russian;
}
break;
}
}
В конструкции switch нам также необходимо прописать блоки для case 1: и case 2:
• Надписи "свободный слот" в меню новой игры и загрузки можно пока не трогать - для них припасен отдельный урок ;)Язык игры - это настройка, а настройка должна сохраняться. Нет смысла сохранять настройки непосредственно в файле сохранения самой игры - для этого нам отлично подойдёт реестр. С помощью функции PlayerPrefs мы можем сохранять числа и текст. Для этого нам нужно создать запись в реестре и передать ей значение - в нашем случае номер языка - а затем сохранить.
PlayerPrefs.SetInt("language", langDropdown.GetComponent<Dropdown>().value);
PlayerPrefs.Save();
Запись с именем "language" будет создана автоматически, а если она уже существует, то поменяет своё значение. Добавьте эти строки в метод setLanguage() до или после конструкции switch.
Теперь нам нужно прописать код, который проведёт операции с локализацией при старте игры.
Что нам нужно:
• Если игра запускается впервые - установить язык как на устройстве пользователя или английский (иначе японец не сможет прочитать надписи на русском и поменять язык)
• Если игра уже запускалась и язык сохранён, то установить этот язык
• Установить значение value объекта Dropdown согласно текущему языку
Нам понадобится новый метод setLangAtStart(), в котором мы определим язык устройства и установим его или английский.
public void setLangAtStart() {
if (!PlayerPrefs.HasKey("language"))
{
if (Application.systemLanguage == SystemLanguage.Russian) PlayerPrefs.SetInt("language", 0);
else if (Application.systemLanguage == SystemLanguage.English) PlayerPrefs.SetInt("language", 1);
else if (Application.systemLanguage == SystemLanguage.Japanese) PlayerPrefs.SetInt("language", 2);
else PlayerPrefs.SetInt("language", 1);
PlayerPrefs.Save();
}
langDropdown.GetComponent<Dropdown>().value = PlayerPrefs.GetInt("language");
setLanguage();
}
Теперь внесём небольшой корректив в конструкцию switch и заменим условие (langDropdown.GetComponent<Dropdown>().value) на (PlayerPrefs.GetInt("language")). Теперь игра будет запускаться с тем языком, который вы установили в прошлый сеанс.
Дополнительно можно сделать так, чтобы менялось название игры при смене языка. Фактически нам нужно просто подменить изображение. Создадим для этого переменную logo класса Image и новый метод changeLogo(). В нём мы используем команду Resources.Load<Sprite>("имя файла"); для обращения к содержимому папки Resources и загрузке оттуда необходимого изображения.
public void changeLogo() {
if (PlayerPrefs.GetInt("language") == 0) logo.sprite = Resources.Load<Sprite>("Images/game_name");
else logo.sprite = Resources.Load<Sprite>("Images/game_name_eng");
}
Единственное, что пока осталось без нашего внимания - это настройки музыки и звуков. К ним мы вернемся позднее отдельной статьей. В следующих постах мы наконец-то создадим свою первую игровую сцену, настроим переходы и научимся сохранять игру. Всем добра и пёсиков!
Содержание туториала (Google Docs с ссылками на Пикабу)
В прошлой части мы скачали Unity, подготовились к работе, создали проект, первую сцену и на ней объекты Canvas и Background. В этот раз мы создадим главное меню нашей игры.
Для начало запомните важную вещь - в 2D игре интерфейс построен на слоях. Одно поверх другого. А также связь Parent - Child (Children) - когда один объект находится в другом и свойства родительского объекта влияют на свойства потомка. Именно по этим принципам мы и будем строить наше меню. Давайте попробуем визуально представить как его можно расположить на экране.
Левый блок - это будет объект mainMenu. Он будет родителем для объектов "название игры", "пункты меню" и "ваше лого". Они тоже будут содержать в себе объекты. Начнем.
Создайте пустой объект (Empty Object) и сделайте его дочерним объекта Canvas (в иерархии перетяните один объект на другой). Другой вариант - клик ПКМ по объекту Canvas и затем выбор создания пустого объекта. Так он автоматически станет дочерним. Переименуйте его в mainMenu.
Чтобы mainMenu стало видно на экране, ему нужно добавить компонент Image через меню Add Component в инспекторе (как добавлять компонент я рассказывал в прошлом посте). Так, ну и где же он?
Чтобы придать нашему меню нужное положение, воспользуемся его компонентом Rect Transform. В разделе Anchors устанавливаем:
- Min X: 0.03 Y: 0
- Max X: 0.3 Y: 1
Затем Left, Right, Top, Bottom ставим по нулям.
Что это всё означает? Anchors (якоря) устанавливают границы нашего объекта относительно размера экрана. Min X: 0.03 прикрепляет левый край (ставит якорь) объекта на уровне 0.03 ширины экрана. Max X: 0.3 прикрепляет правый край на уровне 0.3 - что в итоге дает нам ширину объекта не в пикселях, а в процентах. Он будет занимать в ширину 27% экрана с небольшим отступом слева в 3%. Аналогично с Y - только это уже про высоту объекта.
Теперь установим нашему меню вместо белого пятна приятный глазу цвет. В компоненте Image нажмите на поле Color и установите:
- R - 0.012 (красный)
- G - 0.012 (зеленый)
- B - 0.023 (синий)
- A - 0.7 (альфа-канал или прозрачность)
Для закрепления материала по размещению объекта на экране создадим два декоративных элемента - две полоски по бокам от плашки меню.
1. Создаём два пустых объекта как Child объекта mainMenu - line1 и line2
2. Назначаем Anchors для line1
- Min X: -0.03 Y: 0
- Max X: -0.01 Y: 1
3. Назначаем Anchors для line2
- Min X: 1.01 Y: 0
- Max X: 1.03 Y: 1
4. Устанавливаем обоим объектам цвет как у mainMenu• Если устанавливать Anchor больше или меньше единицы, то границы объекта будут выходить за пределы родительского объекта.
• Можно копировать компонент (например Image) через функцию Copy Component и вставлять его другому объекту или вставлять его значения такому же компоненту другого объекта через функцию Paste Component. Пример того и другого на видео.
Теперь можно похвалить себя и подышать свежим воздухом. Далее нам нужно создать объекты для названия игры, пунктов меню и логотипа. Делаем мы это по тому же принципу - создаем дочерние объекты в mainMenu - top, middle и bottom. Для наглядности сразу добавляем им компонент Image с белым цветом (потом изменим).
• Можно выделить в иерархии сразу несколько объектов про помощи Ctrl+левый клик и добавить компонент всем сразу
Аккуратно распределяем объекты на объекте mainMenu, расставляя значения Anchors.
Top --> X: (0, 1) Y: (0.8, 0.96)
Middle --> X: (0, 1) Y: (0.15, 0.8)
Bottom --> X: (0, 1) Y: (0.04, 0.15)
Для создания небольших отступов или точного корректирования положения объекта можно задавать значения Left, Right, Top, Bottom в компоненте Rect Transform. Попробуйте поставить всем трем объектам эти значения по 2 пикселя. Главное не злоупотреблять этим, а то может верстка перестать быть стабильной.
Итак, мы нашли хорошее расположение для блоков и теперь можем удалить у них компоненты Image и Canvas Renderer, так как больше они нам не понадобятся.
• Вообще старайтесь не оставлять ничего лишнего. Это очень полезная привычка, которая поможет в оптимизации игры
Давайте сделаем для игры графическое название. Можно, конечно, и текстом, но графикой будет симпатичнее. Мы же делаем игру для людей, а не черновик для себя - так ведь?
Откроем Фотошоп и создадим в нём новый файл размером 1000х1000 пикселей.
Затем добавим название игры.
Нарисуем декоративную линию.
Добавьте слоган внизу, затем подрежьте инструментом "Рамка" лист по самые края логотипа.
Далее удаляем слой фона, чтобы сделать логотип прозрачным. Затем устанавливаем размер изображения с шириной в 1000 пикселей. После этого нам очень важно сделать так, чтобы каждая сторона изображения была кратна 4 - это необходимо для применения алгоритмов сжатия, чтобы уменьшить вес игры. Так как обрезать уже нечего, то через "Размер холста" делаем высоту 212 пикселей. Итоговый размер 1000х212.
Когда всё готово, вы должны поменять цвет всех объетов на белый. Зачем? На белое изображение в Unity мы легко сможем наложить любой цвет, если нам приспичит. На чёрный - не получится.
Сохраните полученое изображение в формате PNG и положите его в папку проекта Assets/Resources/Images (создайте её). Сам исходный файл PSD сохраните в отдельной папке вне проекта, где вы будете хранить исходники графики.
Самое время добавить созданное название в игру! Создаем для top дочерний объект gameName, добавляем ему компонент Image и выравниваем на экране. Для того, чтобы изображение не искажалось, в компоненте Image активируем Preserve Aspect - эта функция позволит сохранить пропорции.
Отлично! Гейб Ньюэлл вами был бы доволен.
Теперь займёмся объектом middle и сделаем в нем несколько кнопок, которые будут вести в нужное место - "Новая игра", "Загрузить игру", "Настройки", "Об игре", "Выход".
Нам пригодится полезный компонент под названием Vertical Layout Group. Он выравнивает дочерние объекты по вертикали, регулирует их высоту, ширину и отступы. Это означает, что нам не придётся вручную устанавливать размеры и положение кнопок. Его можно сразу добавить к объекту middle.
• Я предпочитаю пользоваться старой версией компонента Text в Unity. Новая версия называется TextMeshPro. Если в вашей версии Unity нет Button, а есть только Button - TextMeshPro, то посмотрите в подпункте Legacy. Или почитайте как работает TextMeshPro
Таким же образом добавьте еще 4 кнопки и настройте Vertical Layout Group у объекта middle.
Padding - это отступы всего списка кнопок относительно объекта.
Spacing - это отступы между кнопок.
Потыкайте настройки, чтобы понять, как это работает, а потом сделайте как на скриншоте. Как видите, теперь у нас есть аккуратный список кнопок.
Обратите внимание на иерархию - у каждой кнопки есть дочерний объект Text. Это такой же объект, как и все, только с прикрепленным компонентом Text. В нем можно вписать текст объекта, указать шрифт, размер, начертание, цвет, выравнивание. Этих настроек вполне достаточно для нашей игры. Установите размер шрифта 24 пикселя.
• Если вы хотите другой шрифт, то создайте папку Assets/Resources/Fonts и добавьте его туда. Он будет доступен в поле выбора шрифта.
Теперь можно нажать кнопку Play вверху рабочего стола и потыкать по кнопкам.
У каждой кнопки есть компонент Button, у которого есть целый ворох настроек как кнопка будет меняться при нажатии, наведении курсора итд. Однако, для мобильных платформ, где не мышка, а тачскрин, это не нужно. Поэтому отключите эту функцию, поставив Trasition --> none.
Далее можно удалить у кнопок компонент Image - для такого минималистичного дизайна он не нужен. Цвет текста сделайте белым.
В объекте bottom осталось место для вашего логотипа. Подыщите что-нибудь прикольное, нарисуйте в фотошопе и сделайте так же, как мы делали с названием игры.
• В любом случае вы вольны экспериментировать в оформлении и делать как вам нравится. Мы не упустим этот момент - не переживайте. Далее по туториалу нам придётся делать столько кнопок, что они вам в кошмарах сниться будут.
Пришло время для правой части меню - не забыли про неё? Для начала определимся, что будет делать каждая кнопка.
Новая игра - выдает список слотов сохранений, при нажатии на который запустится новая игра и автоматически сохранится в этот слот.
Загрузка игры - аналогично, только загружает сохранение.
Настройки - выбор языка игры, громкости звука и музыки.
Дополнительно - авторы, ссылки, благодарности и прочая второстепенная информация.
Выход - закрывает приложение.
Сделаем на каждую кнопку кроме "Выход" своё поле с информацией, которое будет активироваться при нажатии. Создайте в Canvas дочерний объект newGameList, скопируйте для него компонент Image из объекта mainMenu и установите Anchors --> X: (0.31, 0.9) Y: (0, 1).
В нем создайте 6 кнопок для слотов сохранений и назовите их game_0, game_1, game_2, game_3, game_4, game_5. В этот раз мы не будем распределять их с помощью Vertical Layout Group, но сделаем их с небольшой графикой.
Для начала распределите их равномерно по объекту newGameList, используя Anchors.
Теперь создайте в Фотошопе новое изображение размером 400х400 пикселей. Нарисуйте в нем прямоугольник с границей, но без заливки, как показано на скриншоте.
А затем нарисуйте прямоугольник поменьше, но с заливкой.
Удалите слой фона, сделайте прямоугольники белого цвета и сохраните как PNG в папку Assets/Resources/Images под именем frame_1.
В Unity нам потребуется отредактировать границы спрайта изображения, для того чтобы мы могли его без искажений растягивать в разные стороны. В дереве проекта выберите наше новое изображение frame_1, нажмите в инспекторе Sprite Editor и в открывшемся окне установите Border (границы) на 12 пикселей. Именно в этих местах спрайти будет растягиваться, подгоняясь под размеры кнопки. Закройте это окно и нажмите Save.
Примените новый спрайт ко всем кнопкам и в компоненте Image установите Image Type на Sliced. Надо поправить цвет кнопок.
- R - 0.012 (красный)
- G - 0.012 (зеленый)
- B - 0.012 (синий)
- A - 0.7 (альфа-канал или прозрачность)
Если вам хочется немного свободно места между слотами, то добавьте на кнопки отступы по 5 пикселей с каждой стороны.
Цвет текста кнопок так же меняем на белый.• Не забывайте, что однотипные объекты можно выделять вместе CTRL+клик и массово менять настройки компонентов. Это очень экономит время.
Так как нам нужно точно такое же поле для раздела "Загрузка игры", мы можем просто скопировать это. Деактивируйте объект newGameList, нажав на галочку возле его имени в инспекторе, затем в иерархии щёлкните по нему ПКМ и нажмите Duplicate. Теперь нужно только его переименовать в loadGameList, чтобы не путаться. Деактивируйте его, чтобы не мешался.
Раздел "Настройки". Создайте такое же поле, но только без кнопок. Этот раздел посложнее предыдущего, поэтому сделаем для начала небольшие намётки.
Первым сделаем блок выбора языка с выпадающим списком. Нужно создать объект language внутри optionsList и установить ему Anchors X: (0.03, 0.97) Y (0.85, 0.95). Внутри language создаем объект header, устанавливаем Anchors X: (0, 0.48) Y (0, 1), добавляем ему компонент Text с размером шрифта 24 и выравниванием по правому краю и по центру.
Теперь нам нужно сделать выпадающий список. В Unity уже есть готовое решение - нам нужно только правильно его настроить. Добавьте в language объект UI -> Dropdown и устанвите ему Anchors X: (0.5, 1) Y (0, 1). Сразу же можно установить ему почти чёрный цвет с прозрачностью 0.78.
В нём достаточно много дочерних объектов. Разверните его полностью и внимательно поменяйте настройки. По шаблону "Объект: Компонент --> настройки".
- Dropdown: Dropdown --> Transition "none", список Options - поменять Option A итд на названия языков игры.
- Label: Text --> Русский, размер шрифта 24, цвет белый.
- Arrow: Rect Transform --> PosX -20, Wigth 40, Height 40.
- Template: Rect Transform --> Height 450; цвет сделать как у объекта Dropdown
- Viewport: пропускаем.
- Content: Rect Transform --> Height 80.
- Item: Rect Transform --> Height 80; Toggle --> Transition "none"
- Item Background: цвет сделать как у объекта Dropdown
- Item Checkmark: Rect Transform --> PosY -5
- Item Label: Rect Transform --> Left 25, Top 15; Text --> размер шрифта 24, цвет белый.
Если ничего не пропустить, то результат будет как на видео ниже.
По аналогии с языковой панелью делаем объект music, размещаем в нём объект header с компонентом Text (пишем "Громкость музыки"). Нам понадобится слайдер - добавляем его UI/Slider с Anchors X: (0.5, 1) Y (0.3, 0.7).
В компоненте Slider отключаем Transition.
В дочернем объекте Background делаем черный цвет.
Таким же образом создаём слайдер для "Громкости звуков".
Готово! Вы - великолепны!
Лимит картинок опять исчерпан, поэтому продолжим в следующий раз.
Экспериментируйте с оформлением и не бойтесь трогать все настройки подряд. В этот раз я приложу ссылку на архив с проектом из поста.
Содержание туториала (Google Docs с ссылками на Пикабу)
Для тех, кто не в курсе - это серия туториалов по написанию игры с нуля до выпуска, основанное на моей уже готовой и развивающейся игре. Пост с введением тут. Уровень сложности туториала подходит для орков или маленьких детей. Я рассчитываю, что вы умеете в элементарные операции наподобие: открыть сайт, скачать картинку/программу, переименовать файл, создать папку, помнить где она.
Мы будем делать текстовую RPG с элементарной (но приятной) графикой, сюжетом, прокачкой, открытым миром на движке Unity и языке программирования C# (си шарп), а также будем разжевывать все используемые моменты движка и языка по мере использования. А то многие туториальщики просто бросают в меня кусок кода, как будто я знаю, что с ним делать.
Список того, что нам понадобится:
• Unity. Скачать с официального сайта
• Adobe Photoshop или любой другой удобный вам графический редактор
• Notepad++. Скачать. (очевидно, что подойдёт любой другой редактор кода)
Это наш минимальный набор для начала работы.
Первое, что нам нужно сделать - это правильно установить Unity. Информацию об этом можно найти быстрее, чем узнать, где живёт Джон Коннор, но я обещал с нуля. По ссылке скачивается программа Unity Hub, которая служит этаким вахтёром на пути к работе с движком. Открываем её. Нам нужно сделать две вещи - скачать редактор и создать проект.
Далее следует Очень Важный Момент Который Нельзя Пролюбить! Я сам порой его упускаю. Здесь мы должны выбрать компоненты для установки. Не хотите заморачиваться - выбирайте все пункты.
Минимально необходимый уровень, если вы работаете на Windows:
Всё. Дальше не прерываем процесс и ждём, пока установится. Только после этого можно будет создать свой проект. Попейте чаю и погуляйте с собакой, подготовьте себе рабочее место.
Небольшой оффтоп. Что я узнал для себя за пару лет работы в домашних условиях:
• Соцсети отвлекают - закройте их, отключите уведомления на телефоне
• Стул должен быть удобным, клавиатура должна стоять под комфортным углом, а помещение нужно регулярно проветривать
• Музыка может помочь в работе - ищите такую, которая не заставит вас подпевать, танцевать или махать хаером. Рекомендую Lo-Fi, Binaural Beats и прочую динамически ровную музыку без слов.
• Ходите гулять!
Второй этап - создание проекта.
В следующем окне вы увидите много шаблонизированных проектов, с которыми у вас будет прекрасная возможность ознакомиться самостоятельно. В их числе есть даже обучающие сэмплы. Нам нужен самый простой вариант.
Далее спокойненько ждём пока Unity создаст необходимые файлы для проекта и откроет его. Вуаля! Первый восторг, первое достижение "Открыл редактор" получено!
Тут важно сделать два замечания:
• Я буду знакомить вас с интерфейсом только по мере необходимости. Это мой подход
• Мы будем делать игру с расчётом на мобильные устройства, а не большие экраны стационарных компов и ноутов. Разницу и смысл этого буду объяснять по мере работы
Нам нужно переключить проект в режим Android. Для этого жмём File - Build Settings - Android - Switch Platform (подробно на скрине)
Теперь мы разберемся в проекте и настроим его иерархию. Нам нужно зайти по пути D:/Unity Projects/Piter Quest (ну или путь, который вы выбрали) и открыть там папку Assets. Именно в этой папке будут храниться все наши ресурсы - картинки, текст, скрипты, слёзы. Эта папка - самая главная (намёк на бекапы).
Как вы это всё там расположите движку практически безразлично, а вот нам нет.
Нам понадобится содать папку для хранения всех ресурсов игры под названием Resources. Для хранения сцен уже есть папка Scenes. Для хранения скриптов сделаем папку Scripts.
Папка Resources должна быть сделана именно в таком написании с заглавной буквы. Это специальная папка для движка - впоследствии мы будем получать доступ к её содержимому малюсеньким кусочком кода. Подробнее о ней, а также о других специальных папках можно почитать по ссылке.
Далее поговорим про святая святых - наше рабочее пространство. Ниже скриншот рабочего стола по умолчанию. Можете оставить всё как есть, но как по мне - такое расположение окон не очень удобно для нашей игры.
Настроим интерфейс рабочего поля редактора под меня под себя. Это проще показать, чем объяснить. На видео я перетаскиваю вкладки и меняю размер окон (мамкин программист). Вернуть как было или попробовать заготовленные пресеты можно в Window - Layouts.
"Эй! Мы игру-то делать будем сегодня?!". Да-да, сейчас начнем. Оговорюсь сразу - мы делаем резиновую верстку под альбомную ориентацию.
• Альбомная ориентация - это когда вы переворачиваете телефон (он типа широ-о-окий)
• Резиновая верстка - это термин верстальщиков. Означает, что все элементы оформления интерфейса, которые мы будем создавать в игре, будут автоматически подгоняться под формат экрана мобильного устройства. Их размеры будут задаваться не в пикселях, а в процентах.
Итак, давайте начнём делать нашу первую сцену - Главный Экран Игры или в простонародье главное меню.
Я уже успел переименовать сцену. Чтобы это сделать - кликните правой кнопкой мыши (ПКМ) по SampleScene и выберите Save Scene As. Назовите её MainScene (или как хотите). Затем удалите SampleScene.
В первую очередь нам понадобится главный холст - или как его кличут в Unity - Canvas. В нашем случае Canvas будет содержать в себе все элементы интерфейса игры за исключением фона. Фон мы сделаем позже.
Для начала нажмите на плюс в левом верхнем углу окна Hierarchy или щёлкните ПКМ по пустому месту в этом окне, выберите UI - Canvas.
В иерархии у нас появилось два объекта - Canvas и EventSystem. EventSystem отвечает за все взаимодействия пользователя с игрой и обязательно должен присутствовать в каждой сцене (иначе ни одна кнопка работать не будет). Сейчас мы немного настроим Canvas. Нажмите на него в иерархии и давайте посмотрим что о нём говорит Inspector.
В компоненте Canvas Scaler установите UI Scale Mode --> Scale With Screen. В появившихся новых настройках:
- Reference Resolution установите как 1600 и 900
- Screen Match Mode --> Match Width Or Height
- Match --> 0
- Reference Pixels --> 100
Это мои настройки под мою мою игру, которую мы создаем в этом туториале. Используйте их, если вы пока слабо разбираетесь в Unity. Если же вы разбираетесь неплохо, то устанавливайте свои.
Для поднятия морального духа и понимания того, как мы дальше будем делать главное меню, давайте сделаем симпатичный фон. Нам понадобится сделать новый объект с компонентом Sprite Renderer. Для этого щелкните ПКМ на пустом месте в иерархии или нажмите на плюс в верхнем левом углу и выберите Create Empty. Это пустой объект, к которому мы сами будем добавлять компоненты.
У нас появился новый объект GameObject. Потяните его и перенесите в иерархии выше Canvas.
С этого момента я больше не буду подробно писать как создать объект в Unity. Надеюсь, с двух раз вы запомнили и научились ;)
Переименуем его в Background (через инспектор или нажатием ПКМ) и добавим к нему компонент Sprite Renderer. Для этого в инспекторе нажмите Add Component и выберите Sprite Renderer. Тут есть два способа. Первый - искать по категориям (Render - Sprite Renderer), второй - начать набирать в строке название и Unity отфильтрует лишнее. Мне удобнее второй.
Нам потребуется фоновая картинка. Чтобы не нарушать авторские права возьмите своё творчество, купите или найдите необходимое на бесплатных фотостоках. Рекомендую Pixabay (потребуется VPN). Когда найдёте нужную, создайте в папке проекта Assets/Resources новую папку Backgrounds и поместите картинку туда. Не забудьте переименовать.
Для того, чтобы фон всегда заполнял экран при любом разрешении и не появлялось пустых участков, нам понадобится изменить размер картинки на 2400x1200 в Фотошопе. Этот способ я выработал сам для своей игры и под свои настройки (это важно). Откройте картинку в Фотошопе и сейчас мы её немного трансформируем.
- Изображение --> Размер изображения
- Ширина --> 2400 пикселей. Ок.
- Изображение --> Размер холста
- Высота --> 1200 пикселей. Ок. Сохраняем как jpeg
Формат изображений для Unity не jpeg, а png. Однако, в данном случае нет смысла тратить время на сохранение фонов в png. Unity при сборке сама всё прекрасно переконвертирует. Это только для фонов! К элементам интерфейса мы подойдём гораздо внимательнее.
В компоненте Sprite Renderer объекта Backgroung в поле Sprite выберите нашу новую картинку или перетяните её в это поле из списка файлов проекта (Assets - Resources - Backgrounds). В компоненте Transform измените значения поля Scale (масштаб) на x = 1.2, y = 1.2, z = 1. Этот нехитрый способ поможет нашему фону аккуратно и без пробелов смотреться на экранах с соотношением сторон до 23:9 (это такой длинный смартфон-лопата).
Если вы работаете на не самом новом ноутбуке или мониторе, то выставьте предварительное разрешение на 1280х720. На моем ноуте с разрешением 1600х900 это идеальный вариант.
Заканчивается место в посте. Главное меню будем делать в следующем. Я как раз его пишу и увидим мы его ночью или завтра утром.
Небольшое послесловие. Скорее всего эта серия постов растянется надолго. Моя задача - объяснить вам разные важные моменты, ничего не упустив, и усовершенствовать свои знания. Пока я писал этот пост, я нашел в своих знаниях несколько пробелов и с удовольствием их восполнил. Пишите комментарии - в них сила - только старайтесь сильно не бугуртить. Я критику воспринимаю спокойно и с юмором (с недавних пор).
Не ждите новых постов - занимайтесь игростроем самостоятельно и сами ищите информацию.
Содержание туториала (Google Docs с ссылками на Пикабу)
Язык C# многим нравится: на нем можно писать бекенд, мобильные игры и десктоп приложения. Как правильно изучать этот язык чтобы быстро стать джуном и найти работу? Об этом мы узнаем в этом видео.
Я уже просто не знаю,что делать и куда отписать об этом.
Почему-то Convert.ToInt32 не подсвечивается,всё что можно просмотрел по решению этой проблемы,но просто 0...
.NET SDK ставил,вручную указывал путь к script editor (VS Code) указывал,плагины на C# ставил.
В чём может быть проблема? Смотрел ролики других людей - у них эта часть подсвечивается.
1. скрин - мой результат
2. скрин - взят из видео.
Вот что не так?
UPD
3. скрин - после удаления точки Convert стал распознаваться...Но как мне записывать код,дабы программа его распознавала как на 2 скрине?