game manager unity что это
Системы событий в Unity3D
Доброго времени суток!
Сегодня хотелось бы кратко рассказать об использовании событий для избавления от мусора и предоставления комплексной и динамической функциональности коду. Следует заметить, что данная статья ориентирована скорее на начинающих, которым хочется узнать больше о системах событий.
Разбирать все это дело мы будем на примере системы управления звуком. Данная система будет позволять нам включать/отключать музыку и звуки в настройках игры.
Прежде чем мы создадим класс-менеджер, который будет управлять настройками звука и музыки, мы создадим простой сериализуемый класс. Он будет использоваться в качестве модели данных для сохранения в JSON.
Теперь можно приступить к написанию класса-менеджера. Его мы будем устанавливать на самой первой сцене. Данный менеджер будет глобальным объектом и не будет удаляться при переходе со сцены на сцену.
Теперь, когда менеджер готов, вы можете создать на вашей начальной сцене пустой объект и назвать его, к примеру «_AUDIO_MANAGER», после чего добавить на него наш класс-менеджер. Сделать это можно просто вызвав меню добавления компонента на объекте и выбрав «Game Managers» => «Audio Manager».
После этого, нам необходимо написать компонент, который мы будем пристыковывать к каждому объекту с AudioSource.
Таким образом мы можем управлять звуками/музыкой в игре. Данный пример не в коем случае не говорит, как следует делать это правильно, а лишь демонстрирует работу системы событий и слушателей в Unity3D.
И напоследок хочется поговорить о том, что мы сейчас использовали. В примере ниже, был объявлен делегат, из которого был создан слушатель:
Вы можете установить выполнение слушателя при определенных условиях и цеплять к ним определенные методы, которые будут выполняться при достижении этих условий.
А при помощи делегатов, на основе которого мы создали слушатель, вы можете создавать Callback-функции. Особенно полезно это может быть для асинхронных методов (к примеру при отправке асинхронных POST-запросов).
Надеюсь, вам пригодится мой небольшой опыт в этом деле и вы сможете применить данный пример для своих проектов. Также буду рад ответить на ваши вопросы (если кому-то что-то непонятно).
Full Unity 2D Game Tutorial 2019 – Game Manager
Full Unity 2D Game Tutorial 2019 – Game Manager
A Game Manager is a c# script we can create which will be used to help coordinate the game. We will use it to spawn new enemies when there isn’t enough and in the future use it to spawn power-ups and health pickups.
Full Unity 2D Game Tutorial 2019 – Creating the Game Manager
To create our Game Manager we will first create a new empty object and name it GameManager. We will then add a c# script component and also name that GameManager. Now if you look in you assets you will see the newly create Game Manager and it will look different to the usual c#Script because Unity knows us developers like to use a Game Manager class to manage certain game mechanics.
So now we have one we will want to spawn enemies. The easiest way for us to do that is to create an Enemy prefab that we can use in our Game Manager to Instantiate. Drag and drop the EnemyObject into the prefabs folder to create our new prefab. You should end up with your EnemyObject turning blue in the Hierarchy window. This lets us know the Item has ascended from standard object to a prefab.
Full Unity 2D Game Tutorial 2019 – Game Manager Code
Code Notes:
We check if there is enough enemies and if not create 1 more. (we only create 1 per frame as Instantiate is an expensive process and we are not using pooling)
Added a method to decrease enemy amount to be called by Enemy when they die.
Rect is simple a Rectangle object that stores the position of each side. (we use this to define the spawn area)
Remember to set the Game Manager up with the enemy prefab and the spawn locations. Now, if we run our Game we should be able to see some enemies.
That’s it for the Game Manager. Quite a short section of the tutorial so let’s do something extra. If, like me, your sick of seeing loads of Knobs on the screen, then have I got news for you.
Full Unity 2D Game Tutorial 2019 – Replacing Images
Look at my amazing artwork. This took me a whole 10 minutes in Photoshop. This is going to be our spaceship for our player and for our enemies. I created this as a 256 by 256 pixel image as its square with the image in the middle it is easy to to rotate with no issues, its a power of two image (2,4,8,16,32,64,128,256,512,1024 etc) so its compatible/optimised with older rendering tech. I’m sure you could create something much better so go ahead and make your own.
To import this image into our project we simple drag it from our desktop environment into our project window. Preferably the Images folder 😉 then in the Inspector for the Image (not the Player’s sprite) set the pixels per meter to 128. This means for every unit in unity 128 pixels is shown. Apply the image to our Player sprite by selecting the player sprite and choosing the spaceship for our Sprite. Since our player is about 1/10th of a unit, set the sprite scale to 0.1. This should make the sprite match the size of our collider.
Press play and have a play about. If you notice the pixelation that is due to the image being 256 pixels being compressed to a smaller amount of pixels. There’s a few things we can do to help reduce this issue such as using mipmaps, changing the filter type or using images closer to the actual render size. These however are outside the scope of this section of the tutorial. Later we will attempt to fix this issue.
We have added the image to our player so now lets update our enemy. Simply open the enemy prefab and change the spite to the spaceship image. The colour you applied will still be in effect and should change the enemy to that colour. Using this colour works well with grey-scale images but images with high colour tend to not look good.
That’s enough for this tutorial. The finished project source is available here on Github.
Creating a simple GameManager using Unity3D
In this post we will show you how to create a simple game manager for Unity3D games. We will assume that you have some previous knowledge in Unity, but if you haven’t get the chance to know it, please go to the Official Learn Unity page and get started. We are going to create the scripts using the C# language.
1 – The Singleton Pattern
For the implementation, we will use the Singleton pattern. Why? Some reasons:
We will not explain the design of the Singleton pattern because it’s not the purpose of this post. If you wish to know more about it, you can go here.
2 – The GameManager code
Create a new project on Unity and add a first csharp script called SimpleGameManager.cs and add the following code:
Explaining the code in parts, we have:
First we are making some enums for easily check the Game State, so for this example we will have:
Then we will have an event delegate method that we will use as a callback when a game state changes. This is ideal for changing scenes.
Moving forward we will have the gameState attribute, that is a getter for the current Game State.
It automatically sets the new gameState for the instance and call the callback OnStateChange method.
3 – Creating Sample Scenes
For testing our new Game Manager, we will create 2 Unity scenes: Intro and Menu. The Intro scene will just show some debug messages, simulating an Intro game scene, and after 3 seconds it will change to the Menu Scene were we have the Game Menu code.
Create a new scene called Intro and create a csharp script called Intro.cs. Put the following code into the script:
You can see here that we just need to call the Game Manager instance inside the Awake method. The same initialization will happen on the others scripts, to get the current Game Manager state.
After getting the Game Manager instance we set the OnStateChange event, which is load the Menu scene after 3 seconds. You can notice that the first line of the event sets the new Game State by calling the SetGameState method.
If you run this scene however, you will get an error because we don’t have the Menu.cs Scene yet. So let’s create it!
Create a new scene called Menu and add a csharp script called Menu.cs into this Scene. Add the following code to Menu.cs:
We added simple Unity GUI elements for this scene just for example. Run the Intro Scene and check the Debug logs, You should see the messages when the Game State is changing from the old state to the new state and keeping the instance between scenes. And there you have it! You can add more GameStates for multiple screens like Credits, High Score, Levels, etc. The code for this examples is on github, feel free to fork and use it in your games!
About this Author
Ellison Leão (@ellisonleao) is a passionate software engineer with more than 6 years of experience in web projects and contributor to the MelonJS framework and other open source projects. When he is not writing games, he loves to play drums.
Unity3D: Автоматический агрегатор скриптов-менеджеров
Вступление
В этой статье речь пойдет об одном виде организации взаимодействия между скриптами-менеджерами (синглтонами именуемыми), а конкретно — использование отдельного класса-агрегатора, в котором содержаться ссылки на все instance менеджеров. Идея создать класс-агрегатор пришла мне в голову после прочтения этой статьи.
Задачи
Класс-Singleton
В классической реализации синглтона в Unity используется статическая переменная instance. В методе Awake() производится проверка, определен ли instance. Если нет, то получаем ссылку на экземпляр класса с помощью ключевого слова this. Но т.к. в конкретной реализации используется «шаблонная» переменная класса Т, использовать this не получилось. Но мы с легкостью можем получить компонент Т с объекта, на котором висит скрипт. Если же instance определен, то его необходимо уничтожить. Таким образом объект всегда будет на сцене в единственном экземпляре.
В методе Awake() в класс-агрегатор добавляется новый элемент, а в методе OnDestroy() элемент удаляется из класса-агрегатора.
Создание синглтона класса MyClass происходит так:
Если надо использовать метод Awake() в классе MyClass, то надо воспользоваться ключевым словом base (подробнее о base и наследовании):
Класс-агрегатор
Класс является статическим, т.е. у него не может быть экземпляра на сцене. Таким образом он будет доступен из любой сцены в любое время.
Все скрипты-менеджеры (синглтоны) хранятся в словаре Managers. Ключом для каждого менеджера является имя класса этого менеджера. Возможно, новички в программировании зададут вопрос: «Ба, а что это словарь хранит MonoBehaviour, а все классы наследуются от Singleton?». Это хороший вопрос, ответ на который и является ключом к реализации автоматического агрегатора менеджеров любых классов.
В программировании существует понятие upcasting — преобразование типа к базовому классу. Благодаря тому, что все классы в Unity наследуются от MonoBehaviour, их можно апкастить к MonoBehabiour. Поэтому словарь Managers содержит только объекты класса MonoBehaviour.
Рассмотрим методы класса-агрегатора:
Этот метод вызывается в методе Awake() класса Singleton. Аргументом является статическая переменная класса instance. Далее создается ключ по имени класса, которому принадлежит instance, и менеджер добавляется в словарь.
Функция принимает аргументом строку с именем класса, откуда вызывается метод. Это сделано исключительно для удобного дебага (в консоли отображается класс, откуда вызывается метод). Пример использования этого метода в класса AnotherMyClass:
Удаляет из словаря менеджер типа Т, если он содержится в словаре.
Итоги
Фактически, из трех функций класса-агрегатора разработчику достаточно использовать только метод getManager. Особым плюсом является хорошая видимость сообщений дебага на все случаи жизни. По желанию, конечно же, их можно отключить. Я же считаю, что будет очень удобно увидеть в какой момент времени, какой класс пытается что-то получить и что он пытается получить.
Надеюсь, эта статья была для вас полезной и вы узнали что-то полезное для себя!
Использование Singleton в Unity3D
Вступление
Организация любого, хотя-бы малость серьезного проекта требует хорошей организации кода. Проекты, разрабатываемые в среде Unity3D не являются исключением и, по мере роста проекта, его организация может сыграть не малую роль в качестве исходного продукта.
В данной статье мы постарались не только описать такой подход к организации кода, как Singleton (в народе называемый паттерном проектирования), но и рассмотреть наиболее комфортные и правильные подходы к обработке событий и поговорить об удобности кода в целом.
Итак, в этой статье мы затронем следующие моменты:
Как работает Singleton
Прежде чем начать разбираться в схеме работы паттерна Singleton, необходимо понять что это. Singleton (Синглтон) — некий менеджер, через который производится управление игровыми скриптами. Как правило, синглтоны сохраняются от сцены к сцене без повторной реинициализации (наподобие глобального объекта).
На простейшем примере работу Singleton можно объяснить следующим образом:
В игре присутствуют глобальные объекты (менеджеры), которые будут находиться в игре всегда и могут быть доступны из любого скрипта, что может быть полезно для создания классов управления музыкой, сетевыми функциями, локализацией и всем тем, что используется в единственном экземпляре. Помимо менеджеров в игре будут использоваться и множественные объекты: интерфейсы, игровые персонажи и объекты игрового мира. Все эти объекты будут плотно взаимодействовать с нашими менеджерами для достижения конечной цели.
Рассмотрим для примера организацию работы в мобильной игре:
В нашем случае Singleton — это объект переходящий от сцене к сцене, служащий для управления всеми объектами определенного типа в рамках игровой сцены (игры в целом).
На схеме ниже мы изобразили схему работы на примере мобильной пошаговой онлайн-игры:
Чтобы иметь полную картину, рассмотрим архитектуру этой игры. В данном случае помимо объектов Singleton у нас будут присутствовать следующие элементы:
Реализация Singleton в Unity3D
Для более легкого восприятия мы продолжим рассматривать архитектуру мобильной онлайн игры и посмотрим, как все что мы описали выше, будет выглядеть на практике.
Основа всего метода проектирования — собственно сами классы менеджеры, которые находятся в игре в единственном экземпляре и могут быть вызваны в любой момент. Для создания такого класса менеджера мы можем описать следующий код:
На примере выше мы создали основу для одного из игровых менеджеров (в нашем случае это менеджер Audio). Не обязательно проводить инициализацию через метод Start(). Вы также можете использовать для этого метод Awake(), чтобы ваш объект был готов еще до старта сцены.
Теперь мы допишем наш класс, чтобы он умел загружать и сохранять параметры звука и музыки в игре:
Итак, готово. Теперь наш менеджер аудио умеет загружать и сохранять настройки звуков и музыки. Теперь встает следующий вопрос о том, как мы можем это использовать. На примере ниже, мы продемонстрировали простой пример взаимодействия с менеджером:
На примере выше мы создали компонент, позволяющий нам автоматически включать/отключать AudioSource на объекте на основе статичных полей music и sounds в нашем менеджере.
Допустим, что у вас уже существует несколько менеджеров. Для того, чтобы не выгружать их в каждую сцену как объект отдельно, вы можете создать так называемый Bootstrap-класс, который будет цеплять объекты из заранее созданных префабов. Обязательности в Boostrap-объекте нет, однако мы рекомендуем использовать его просто для вашего удобства.
Рассмотрим наш класс Boostrap-а:
Теперь мы можем использовать Boostrap и добавлять в него новые префабы менеджеров без необходимости их размещения на каждой сцене игры.
Использование моделей данных необязательно, однако вы можете создать их для быстрой обработки данных с сервера и хранения данных в клиенте без необходимости повторных запросов. (к примеру для кеширования данных о пользователях в игре).
В нашем случае после запроса к серверу мы будем выгружать полученные данные в модели и обрабатывать их данные. Рассмотрим простейшую модель данных:
На примере выше у нас изображена модель данных, которая будет служить для обработки базовых статусов, получаемых с сервера в формате JSON. Таким образом, когда мы обращаемся к нашему игровому серверу мы получаем 2 вида ответа:
При успешном обращении мы получаем ответ следующего вида:
А при ошибке мы получаем ответ следующего вида:
Таким образом мы можем парсить ответ сервера при помощи JSON десериализации и нашей модели данных:
Контроллеры будут служить нам для работы множественных объектов в игре (к примеру, противники в игре, либо контроллер игрока). Контроллеры создаются самым обычным способом и цепляются на объекты в игре в качестве компонентов.
Пример простого контроллера игрока:
На примере выше в части кода, где мы обновляем части тела игрока, мы используем модель данных с информацией о профиле игрока, которая была непосредственно подключена в менеджере сети.
Рассмотрим данную строку:
Здесь мы видим, что идет сравнение индекса в цикле с идентификатором волос в модели данных игрока. Данная модель представлена в экземпляре объекта менеджера сети (NetworkManager), где был инициализирован объект для работы с авторизацией (auth), внутри которого размещены модели данных (player_data => profile_data => body).
Взаимодействие с Singleton
Для взаимодействия с менеджерами мы будем использовать либо экземпляр объекта (instance), либо прямое обращение для статических параметров.
Пример работы с instance:
На примере выше мы использовали свойство instance для получения данных о волосах игрока в менеджере NetworkManager.
Пример прямого взаимодействия со static-параметрами:
На примере выше мы обратились напрямую к статичному свойству sounds в менеджере AudioManager.
О плюсах и минусах Singleton
+ Нет необходимости постоянной настройки и описаний полей скриптов в инспекторе
+ К менеджерам можно обращаться через свойство instance
+ Удобный рефакторинг кода
+ Компактность кода
— Сильная зависимость кода
— Доступ только к скриптам-менеджерам в единственном экземпляре
Немного практических примеров
Использование делегатов
Мы можем сделать наш код более отзывчивым, добавив в менеджеры функции-делегаты. Таким образом для каждой функции может быть создан метод обратного вызова (callback).
Рассмотрим данный пример:
На простом примере выше мы создали метод, который вызываем функцию success, если параметр number был меньше 10 и функцию error, когда параметр был больше или равен 10 соответственно.
Использовать данный метод можно следующим способом:
Таким образом мы можем создавать код с управляемым результатом. Теперь мы плавно переходим к примеру использования вместе с Singleton.
Делегаты в связке с Coroutine в Singleton
Для наиболее удобного и правильного взаимодействия с сервером мы можем использовать связку Coroutine-функций и делегатов, тем самым получая возможность отправлять асинхронные запросы и обрабатывать ответ сервера. Ниже мы подготовили пример NetworkManager-а с использованием Coroutine-функций и делегатов.
Рассмотрим данный пример NetworkManager-а:
Теперь мы можем использовать это по назначению:
Таким образом, вы можете выполнять код NetworkManager и управлять его методами при помощи Callback-функций из любой сцены игры.
Заключение
Вообще, тема Singleton-ов и паттернов в целом в рамках проектов на Unity3D заслуживает отдельной книги и рассказать все в одной статье не получится. Ниже мы прикрепили несколько полезных материалов, где вы можете почитать об этом подробнее.