Как создать меню для игры на Unity

Без меню игроку не изменить настройки, не сохраниться или не загрузить прошлый прогресс. Объясняем, как сделать меню в Unity.

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

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

Для создания интерфейсов, в том числе и меню, в Unity используются
UI-объекты. К ним относятся:

  • кнопки;
  • изображения;
  • списки;
  • слайдеры;
  • чекбоксы;
  • выпадающие списки и другие элементы.

Чтобы работать с ними, нужно создать объект Canvas и дать ему понятное название. Например MenuCanvas. Добавьте в него объект Panel и задайте какое-нибудь фоновое изображение или цвет.

После этого можно начинать верстать меню. Создайте внутри MenuCanvas объект типа Empty и назовите его MainMenu. Внутрь него можно добавить элементы типа Text и Button.

Менять надпись на кнопке можно с помощью вложенного объекта Text. Добавьте их столько, сколько вам необходимо. Затем разместите их на холсте так, чтобы получить что-то вроде этого:

Ваше главное меню готово. Нужно ещё добавить отдельные подменю для настроек, сохранения и загрузки.

Евгений Кучерявый

Пишет о разработке сайтов, в свободное время создает игры. Мечтает открыть свою студию и выпускать ламповые RPG.


Как добавить несколько меню в Unity

Чтобы создать несколько экранов меню, добавьте ещё несколько объектов типа Empty и поместите новые элементы в них. Например, в этом проекте будут созданы SaveMenu, LoadMenu и SettingsMenu.

При добавлении объекта он становится активным, поэтому все кнопки и слайды будут просто налезать друг на друга. Чтобы отключить какое-нибудь меню, нажмите на его объект и в Inspector возле его названия уберите галочку.

Этому действию соответствует метод SetActive(), который можно использовать, чтобы переключать меню при нажатии кнопки. Для этого выберите кнопку и в окне Inspector найдите поле On Click ().

В нём описаны действия, которые будут выполняться при клике на кнопку.

На скриншоте показано отключение основного меню и включение меню с сохранениями при нажатии кнопки SaveButton. Сделано всё это без использования кода.

Как создать меню настроек в Unity

Отдельно рассмотрим создание настроек игры. Чтобы реализовать их, нужно сначала сверстать меню с помощью объектов Toggle, Dropbox и Slider:

Дальше создайте скрипт Menu.cs и прикрепите его к MenuCanvas: он будет отвечать за работу со всеми настройками.

В него нужно добавить следующие библиотеки:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; //Работа с интерфейсами
using UnityEngine.SceneManagement; //Работа со сценами
using UnityEngine.Audio; //Работа с аудио

Затем добавьте эти поля:

public bool isOpened = false; //Открыто ли меню
public float volume = 0; //Громкость
public int quality = 0; //Качество
public bool isFullscreen = false; //Полноэкранный режим
public AudioMixer audioMixer; //Регулятор громкости
public Dropdown resolutionDropdown; //Список с разрешениями для игры
private Resolution[] resolutions; //Список доступных разрешений
private int currResolutionIndex = 0; //Текущее разрешение

Не забудьте добавить в скрипт выпадающий список и регулятор громкости:

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

public void ShowHideMenu()
{
	isOpened = !isOpened;
	GetComponent<Canvas> ().enabled = isOpened; //Включение или отключение Canvas. Ещё тут можно использовать метод SetActive()
}

Вызываться этот метод будет при нажатии на кнопку Esc:

void Update() 
{
	if(Input.GetKey(KeyCode.Escape)) 
	{
		ShowHideMenu();
	}
}

Дальше нужно создать методы, которые будут вызываться при изменении настроек в меню:

public void ChangeVolume(float val) //Изменение звука
{
	volume = val;
}

public void ChangeResolution(int index) //Изменение разрешения
{
	currResolutionIndex = index;
}

public void ChangeFullscreenMode(bool val) //Включение или отключение полноэкранного режима
{
	isFullscreen = val;
}

public void ChangeQuality(int index) //Изменение качества
{
	quality = index;
}

Выберите необходимый объект, например, список с уровнями качества, и добавьте обработчик события On Value Changed.

Для этого перетащите объект MenuCanvas и выберите Menu.ChangeQuality. Обратите внимание, что метод указан без скобок. В таком случае значение будет передано ему автоматически. Здесь это индекс выбранного пункта.

Чтобы настройки вступили в силу, нужен ещё один метод:

public void SaveSettings()
{
	audioMixer.SetFloat("MasterVolume", volume); //Изменение уровня громкости
	QualitySettings.SetQualityLevel(quality); //Изменение качества
	Screen.fullScreen = isFullscreen; //Включение или отключение полноэкранного режима
	Screen.SetResolution(Screen.resolutions[currResolutionIndex].width, Screen.resolutions[currResolutionIndex].height, isFullscreen); //Изменения разрешения
}

Добавьте вызов этого метода при нажатии на кнопку сохранения настроек.

Меню можно улучшить, если сделать автоматическое добавление всех доступных разрешений:

resolutionDropdown.ClearOptions(); //Удаление старых пунктов
resolutions = Screen.resolutions; //Получение доступных разрешений
List<string> options = new List<string> (); //Создание списка со строковыми значениями

for(int i = 0; i < resolutions.Length; i++) //Поочерёдная работа с каждым разрешением
{
	string option = resolutions [i].width + " x " + resolutions [i].height; //Создание строки для списка
	options.Add(option); //Добавление строки в список

	if(resolutions[i].Equals(Screen.currentResolution)) //Если текущее разрешение равно проверяемому
	{
		currResolutionIndex = i; //То получается его индекс
	}
}

resolutionDropdown.AddOptions(options); //Добавление элементов в выпадающий список
resolutionDropdown.value = currResolutionIndex; //Выделение пункта с текущим разрешением
resolutionDropdown.RefreshShownValue(); //Обновление отображаемого значения

Также сюда стоит добавить возможность выхода из игры:

public void QuitGame()
{
	Application.Quit(); //Закрытие игры. В редакторе, кончено, она закрыта не будет, поэтому для проверки можно использовать Debug.Log();
}

Или перехода на другую сцену:

public void GoToMain()
{
	SceneManager.LoadScene("Menu"); //Переход на сцену с названием Menu
}

Теперь остается только функция сохранения.

Как создать сохранение в Unity

Сохранения представляют собой файлы, в которых хранится информация о текущем состоянии игровых объектов:

  • позиции игрока;
  • уровне;
  • мане;
  • здоровье;
  • опыте и так далее.

Чтобы можно было всё это удобно преобразовать в файл, используется сериализация — специальный инструмент, который позволяет сохранить объект в формате JSON или XML. Лучше сохранять всё в виде бинарных файлов, потому что так игроки не смогут изменить характеристики своего персонажа.

Чтобы сохранить данные (координаты, наличие предметов в инвентаре, здоровье), создается класс SaveData:

[System.Serializable] //Обязательно нужно указать, что класс должен сериализоваться
public class SaveData 
{
	//Создание полей с игровыми параметрами
	public float currHP;
	public float HP;

	public float currMP;
	public float MP;

	public float currXP;
	public float XP;

	public int level;

	public float[] position; //В Unity позиция игрока записана с помощью класса Vector3, но его нельзя сериализовать. Чтобы обойти эту проблему, данные о позиции будут помещены в массив типа float.

	public SaveData(Character character) //Конструктор класса
	{
		//Получение данных, которые нужно сохранить
		HP = character.HP;
		currHP = character.currHP;

		MP = character.MP;
		currMP = character.currMP;

		XP = character.XP;
		currXP = character.currXP;

		level = character.level;

		position = new float[3] //Получение позиции
		{
			character.transform.position.x,
			character.transform.position.y,
			character.transform.position.z
		};
	}

}

Теперь понадобится дополнительный класс, который будет отвечать за сохранение и загрузку данных:

using UnityEngine;
using System.IO; //Библиотек для работы с файлами
using System.Runtime.Serialization.Formatters.Binary; //Библиотека для работы бинарной сериализацией

public static class SaveLoad //Создание статичного класса позволит использовать методы без объявления его экземпляров
{

	private static string path = Application.persistentDataPath + "/gamesave.skillbox"; //Путь к сохранению. Вы можете использовать любое расширение
	private static BinaryFormatter formatter = new BinaryFormatter(); //Создание сериализатора 

	public static void SaveGame(Character character) //Метод для сохранения
	{
		
		FileStream fs = new FileStream (path, FileMode.Create); //Создание файлового потока

		SaveData data = new SaveData(character); //Получение данных

		formatter.Serialize(fs, data); //Сериализация данных

		fs.Close(); //Закрытие потока

	}

	public static SaveData LoadGame() //Метод загрузки
	{
		if(File.Exists(path)) { //Проверка существования файла сохранения
			FileStream fs = new FileStream(path, FileMode.Open); //Открытие потока

			SaveData data = formatter.Deserialize(fs) as SaveData; //Получение данных

			fs.Close(); //Закрытие потока

			return data; //Возвращение данных
		} 
		else 
		{
			return null; //Если файл не существует, будет возвращено null
		}
		
	}
}

Созданные методы будут вызываться из класса Character:

public void LoadCharacter()
	{
		SaveData data = SaveLoad.LoadGame(); //Получение данных

		if(!data.Equals(null)) //Если данные есть
		{
			HP = data.HP;
			currHP = data.currHP;

			MP = data.MP;
			currMP = data.currMP;

			XP = data.XP;
			currXP = data.currXP;

			level = data.level;
			currHP = data.currHP;

			transform.position = new Vector3(data.position[0], data.position[1], data.position[2]);
		}
	}

Можно проверять:

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

Заключение

Полученных из статьи знаний хватит, чтобы создавать другие интерфейсы в игре:

  • полосы здоровья;
  • уровень персонажа;
  • меню паузы.

Также вы сможете использовать другие механизмы сохранения, в том числе и чекпоинты. Если же вы хотите подробнее узнать обо всём этом, записывайтесь на курс «Разработчик игр на Unity». Вы будете работать над своими проектами, для которых будете создавать интерфейсы, графику, скрипты, генерацию мира и многое другое.

Курс

Профессия
Разработчик игр на Unity


Годичный учебный курс с полным погружением в профессию разработчика игр. Вы изучите основы геймдизайна, научитесь разрабатывать 2D-, 3D- и мобильные игры, освоите способы их монетизации и продвижения.

  • Первые полгода учёбы — без оплаты.
  • Неограниченный доступ к материалам курса.
  • Обучение на реальных задачах.
  • Карьерные консультации и помощь в трудоустройстве.

Хочешь получать крутые статьи по программированию?
Подпишись на рассылку Skillbox