Как создать меню для игры на 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]);
		}
	}

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

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

Заключение

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

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

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

Курс

Разработчик игр с 0 до PRO


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

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