Это вторая часть урока на тему “Как сделать простую 2.5D игру для iPhone с помощью Unity”
В первой части мы получили базовое понимание о Unity и о написании кода на C#. Мы создали простую игру, в которой самолет летает вперед-назад, бомбит акул и защищает рыбу-клоуна.
Во второй и заключительной части мы улучшим игру. Добавим музыку и звуковые эффекты, допилим логику игры и добавим еще несколько сцен.
Если у вас нет исходников, то скачайте и запустите проект в Unity. Ок, давайте узнаем о Unity еще больше и прокачаем нашу игрушку.
Добавляем улучшения.
Вы наверняка заметили, что когда бомба попадает в акулу, она просто тихо исчезает и думает про себя: “Фу! Это не круто”.
Но все поправимо, мы добавим крутые подводные взрывы.
Из меню выберите “GameObject/Create other/Particle System”, и вы увидите как на сцене появилась система частиц (particle system). Переименуйте “Particle System” в “Explosion” в панели “Hierarchy” установите позицию Explosion на [1, 1, 8].
Теперь, если вы смыслите в Particle System, взгляните на инспектор и настройте все сами, а если нет, сделайте как у меня. Скопируйте эти значения в инспектор.
Здесь есть еще одно важное свойство – “Autodestruct”. Если свойство включено, то Particle System удалит себя со сцены, когда живых частиц не останется. Это именно то, что нам нужно.
Теперь у вас есть небольшой взрыв, и вам предстоит сделать с ним то же, что и с бомбой – сделать префаб, чтобы клонировать его, когда необходимо.
Щелкните правой кнопкой мыши в панели “Project” в папке “Prefabs” и выбирите “Create/Prefab”, переименуйте префаб в “ExplosionPrefab”. Перетащите объект “Explosion” из “Hierarchy” на новый префаб “ExplosionPrefab”. Клик правой кнопкой на “Explosion” в “Hierarchy” и выберите “Delete”.
Правый клик в панели “Project” и выбор “Sync MonoDevelop Project”, откроется MonoDevelop. Загрузите в эдиторе BombClass.cs и добавьте этот код:
1
2
3
4
5
| //right under definition of "ySpeed" public GameObject explosionPrefab; //inside OnTriggerEnter, right after Destroy(this.gameObject) Instantiate(explosionPrefab, transform.position, Quaternion.identity); |
Теперь вернитесь в Unity и выберите BombPrefab в панели “Project”. В инспекторе вы увидите новое свойство (property) “ExplosionPrefab”. Перенесите “ExplosionPrefab” из “Project” на поле нового свойства и все готово.
Вот и все – нажмите Play посмотрите на взрывы, когда вы попадаете в акулу.
Улучшаем/добавляем звуки.
Как мы могли сделать игру без фоновой музыки? Давайте зайдем в гости к еще одному замечательному парню – Кевину Маклауду, который создает замечательную музыку для фильмов и игр под лицензией CC. Перейдите наhttp://incompetech.com/m/c/royalty-free/index.html?keywords=the%20cannery. Скачайте композицию “The Cannery” и сохраните у себя на диске. Перетащите трек “The Cannery.mp3” в папку “Audio” в панели “Project”.
Нам нужно чтобы музыка играла все время… но вот вопрос, к какому объекту стоит ее прикрепить? Давайте прикрепим ее к камере. Камера тоже объект игры и к ней можно прикрепить другие объекты.
Перетащите “The Cannery” из панели “Project” на “Main Camera” в “Hierarchy”. Выберите “Main Camera” в “Hierarchy” и в инспекторе найдите строчку Audio Source – установите флажок на “Loop” и выставите громкость на “0.22”
Все очень просто – запустите игру и проверьте фоновую музыку.
Создаем GUI в Unity
Давайте изучим еще один немаловажный вопрос – GUI (Графический интерфейс пользователя). В Unity есть некоторые стандартные ярлыки (label) и кнопки, но это не самая сильная сторона Unity. Мы собираемся использовать лейблы для отображения счета игры, поэтому вначале нам нужно реализовать логику оценочной системы. Переключимся в MonoDevelop, откроем класс PlayerClass.cs и добавим новое свойство:
1
| public static int score = 0; |
Кое что новенькое – “static”. Это свойство будет создано, когда класс будет загружен и останется независимо ни от чего. Кроме того это свойство доступно из всех других классов, именно поэтому мы подсчитываем очки в свойстве “static”.
Теперь добавьте метод, который позаботится об обновлении очков:
1
2
3
| public void updateScoreBy( int deltaScore) { PlayerClass.score += deltaScore; } |
Добавьте еще один метод в PlayerClass. Он будет отвечать за вывод очков на экран:
1
2
3
4
5
| void OnGUI() { GUIStyle style = new GUIStyle(); style.fontSize = 20; GUI.Label( new Rect(10,10,100,20), "Score:" +PlayerClass.score, style ); } |
Обработчик события “OnGUI” вызывается каждый слоя GUI, поэтому все, что вам нужно в GUI делается именно здесь.
GUIStyle – это класс, который схож с классом CSS, так что, если вы знакомы с CSS вы можете использовать FontSize, marginLeft и т.д., а если нет, то пока давайте ограничимся только размером шрифта. GUI.Label() – это метод, который содержит 3 аргумента: границы лейбла, строка для рисования и стиль текста. Это все.
Единственная задача – обновлять очки, когда мы попадаем или промахиваемся. Откройте BombClass.cs и внесите следующие изменения:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| //add a new property public PlayerClass player; //replace the existing OnTriggerMethod with void OnTriggerEnter(Collider obj) { if (obj.gameObject.name == "Shark" ) { //reset shark obj.gameObject.transform.rotation = Quaternion.identity; obj.gameObject.transform.position = new Vector3(20f, -3f, 8f); player.updateScoreBy(+1); Destroy(gameObject); Instantiate(explosionPrefab, transform.position, Quaternion.identity); } if (obj.gameObject.name == "ClownFish" ) { //reset fish obj.gameObject.transform.rotation = Quaternion.identity; obj.gameObject.transform.position = new Vector3(-20f, -1f, 8f); player.updateScoreBy(-1); Destroy(gameObject); Instantiate(explosionPrefab, transform.position, Quaternion.identity); } } |
Это очень похоже на то, что мы делали до этого, но у нас появилось новое свойство “player” и когда нам нужно обновить очки мы вызываем player.UpdateScoreBy().
Так же, что бы сделать игру еще интереснее, вы будете получать один балл, когда попадете в акулу и лишаться его, если попадете в рыбу-клоуна. Теперь это выглядит как трудная игра.
Так же, что бы сделать игру еще интереснее, вы будете получать один балл, когда попадете в акулу и лишаться его, если попадете в рыбу-клоуна. Теперь это выглядит как трудная игра.
Еще одна вещь – установить свойство player на бомбу. Сейчас мы не можем сделать это как раньше, потому что бомбы создаются динамически, но к счастью бомбы создаются самим игроком, так что можно установить свойство player на время создания.
Давайте сделаем это – откройте PlayerClass.cs и прямо под строкой “bombObject.transform.position = this.gameObject.transform.position;” добавьте следующий код:
1
2
| BombClass bomb = (BombClass)bombObject.GetComponent( "BombClass" ); bomb.player = this ; |
Давайте обсудим кое-что новенькое. bombObject - это экземпляр GameObject, так что мы вызываем “GetComponent” и таким образом получаем доступ ко всем прикрепленным компонентам к игровому объекту. В итоге мы получаем ссылку на класс C# прикрепленному к игровому объекту. Затем мы просто устанавливаем для него свойство “player” (экземпляр PlayerClass).
Запустите игру и вы увидите счетчик очков!
Объекты и компоненты в Unity.
У вас уже должно быть достаточно практики, чтобы познакомиться с моделью игровых объектов Unity. Хорошо бы понимать, что вы делаете на самом дела, не так ли? Давайте быстренько уясним как игровые объекты соотносятся с компонентами прикрепленными к ним.
Все эти строки мы увидим в панели инспектора – это все компоненты, которые привязываются к игровым объектам. Пустой игровой объект имеет лишь компонент transform (position, rotation, scale). Вот и все. Все остальные компоненты присоединяются вами.
Если вы взгляните на наш BombPrefab, вы увидите много разных компонентов:
- Transform – отвечает за положение (position), поворот (rotation) и scale (масштаб).
- Mesh Filter – отчечает за геометрию видимого объекта.
- Mesh Rendered – рендеринг геометрии.
- Rigidbody – отвечает за физику.
- Audio Source – отвечает за проигрывание аудио.
- Script – программное обновление объектов.
Это лишь часть из тех компонентов, которые можно привязать к объекту. Для лучшего понимания давайте посмотрим на диаграмму.
1
| Destroy( this .gameObject); |
Для того чтобы уничтожить все экземпляры связанные с объектом. Из свойства GameObject мы так же можем получить доступ ко всем другим компонентам, так что мы можем изменять физику, громкость звука и т.д.
Добавляем больше сцен.
Теперь наша игра выглядит куда более лучше, но в нее нельзя выиграть или проиграть.
Давайте добавим экран “You Win”, который будет выводиться, когда игрок наберет более 3-х очков.
Из меню выберите “New Scene”, затем снова из меню “Save Scene”, выбирите папку [your project's directory]/Assets/Scenes и сохраните сцену с именем “WinScene”.
Выберите “Main Camera” в “Hierarchy” и установите: Position [0, 0, 0], Projection на “Orthographic”, Size на “10”, Near на “0.5” и Far на “22”. Из меню выберите “GameObject/Create Other/Directional Light” и установите в инспекторе Position на [0, 0, 0].
Выберите “Main Camera” в “Hierarchy” и установите: Position [0, 0, 0], Projection на “Orthographic”, Size на “10”, Near на “0.5” и Far на “22”. Из меню выберите “GameObject/Create Other/Directional Light” и установите в инспекторе Position на [0, 0, 0].
Все что нам нужно на сцене, это добавить плоскость (как и фон в нашей игре) и наложить на него сообщение “You Win”. Действуем как в первой части урока: Из меню переходим в “GameObject/Create Other/Plane” и в инспекторе устанавливаем Position на [0, 0, 8], Rotation на [90, 180, 0], Scale [3, 1, 2].
Теперь скачайте и сохраните изображение подготовленное Vicki Wenderlich (картинка кликабельна):
Перетащите “gameover_youwin.png” в панель “Project” в папку “Textures”. Текстура экспортируется и вы заметите, что вид у нее не очень. Во всем виновато сжатие. Выберите “gameover_youwin” и найдите в инспекторе раздел “Format”, измените значение на 16bits и нажмите Apply. Теперь перетащите “gameover_youwin” из панели “Project” на “Plane” в “Hierarchy”. В панели “Game” вы должны увидеть “You Win”.
Нам остается только оживить все это. Когда сцена срабатывает необходимо чтобы игра перезапустилась. Щелкните правой кнопкой мыши в панели “Project” в папке “Class”, выберите “Create/C Sharp Script” и переименуйте созданный файл в “GameOverClass”. Правый клик и выбор “Sync MonoDevelop Project”. В MonoDevelop откройте GameOverClass.cs и замените содержимое на это:
1
2
3
4
5
6
7
8
9
10
11
12
| using UnityEngine; using System.Collections; public class GameOverClass : MonoBehaviour { // Update is called once per frame void Update () { if (Input.anyKeyDown) { PlayerClass.score = 0; Application.LoadLevel( "LevelScene" ); } } } |
Когда игрок тапнет по экрану, счет сбросится и загрузится игровая сцена. Application.LoadLevel() содержит имя сцены, которая будет загружена, все просто.
Вернитесь в Unity и перетащите “GameOverClass” из папки “Class” на “Main Camera”. Теперь, чтобы включить эту сцену в проект выберите “File/Build Settings” и в открывшемся окне кликните “Add Current” и закройте окно. Вы добавили сцену в проект.
Давайте быстро добавим экран “You loose”. Как и в тот раз создаем “New Scene”, затем “Save Scane” с именем “LooseScene” в папке Scenes.
Выберите “Main Camera” в “Hierarchy” и установите: Position на [0, 0, 0], Projection на “Orthographic”, Size на “10”, Near на “0.5” и Far на “22”. Из меню перейдите “GameObject/Create Other/Directional Light” и в инспекторе Position на [0, 0, 0]. Из меню “GreateObject/Create other/Plane” и в инспекторе Position на [0, 0, 0], Rotation на [90, 180, 0], Scale на [3, 1, 2]
Скачайте это изображение и сохраните на диске:
Для добавления сцены сделайте все как в прошлый раз:
- Перетащите файл “gameover_youloose.png” в папку “Textures”.
- Выберите “gameover_youloose.png”, в инспекторе найдите “Format”, измените значение на “16bit” и нажмите “Apply”
- Перетащите “gameover_youloose.png” на “Plane” в “Hierarchy”
- Перетащите файл GameOverClass” из папки “Class” на “Main Camera”
- Из меню выбирите “File/Build Settings” и в открывшемся окне нажмите “Add current”. Закройте окно.
Итак, теперь у вас 3 сцены. Нам нужно соединить их.
Двойным нажатием по “LevelScene” в панели “Project” загрузите LevelScene. Переключитесь в MonoDevelop и откройте PlayerClass.cs. Мы собираемся изменить метод updateScoreBy, чтобы проверять, количество очков (3 или -3).
1
2
3
4
5
6
7
8
9
| //replace the updateScoreBy method with this code public void updateScoreBy( int deltaScore) { PlayerClass.score += deltaScore; if (PlayerClass.score>3) { Application.LoadLevel( "WinScene" ); } else if (PlayerClass.score<-3) { Application.LoadLevel( "LooseScene" ); } } |
Теперь сцены настроены. Вы можете протестировать игру нажав кнопку Play в Unity. Чтобы протестировать на iPhone, нажмите “File/Build&Run” и когда Xcode откроется, нажимайте “Run”.
Переходим к 2.5D
Да, время пришло. Пора сделать то, что мы хотели сделать все 2 части урока – 2.5D!
Ранее, в настройках камеры мы использовали опцию “Orthographic” и наша игра выглядела как 2D. Этому пришел конец.
В LevelScene выберите “Main Camera” и в инспекторе в Projection установите значение “Perspective”, а “Field View” установите на “100” (для компенсации перспективы). Это все. Нажмите Play и посмотрите на свою игру в 2.5D. Классно, не так-ли?
Но на этом мы останавливаться не намерены.
Вот план – мы сделаем игру более трудной и будем поворачивать и перемещать камеру каждый раз когда количество очки будет увеличиваться. Таким образом, чем больше попаданий, тем под более странным углом вы будете смотреть на персонажей игры.
Переключитесь в MonoDevelop и внесите следующие изменения в PlayerClass.cs:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| //add the properties public GameObject mainCamera; public GameObject gameBackground; public float nextZ = 0; //at the end of the updateScoreBy method if (PlayerClass.score>0) { nextZ = PlayerClass.score*2.5f; } //at the end of the Update method if (nextZ > mainCamera.transform.position.z) { mainCamera.gameObject.transform.Translate( 3* Mathf.Sin(transform.position.z/2 ) * Time.deltaTime, 0, -Mathf.Sin(transform.position.z /2 ) * Time.deltaTime *0.3f ); mainCamera.gameObject.transform.RotateAroundLocal( Vector3.up, Time.deltaTime*0.1f ); gameBackground.gameObject.transform.RotateAroundLocal( Vector3.up, Time.deltaTime*0.1f ); } |
Отлично. Получилось немало кода, но это все, что нам нужно. Давайте разберемся.
Во-первых мы задекларировали свойства содержащие ссылки на Main Camera и плоскость фона (Background). Мы будем двигать и вращать камеру и фон тоже будет вращаться.
Камера со своего текущего положения Z c позиции 0 примерно до 7.5Z. Каждый раз, когда игрок будет получать очко, nextZ будет установлен на 2.5, затем на 5.0, затем на 7.5 и от этих значений Main Camera пойдет по дуге с помощью функции sin.
Кстати, все математические функции доступны через класс Mathf – для sin это Mathf.Sin (). Так же мы поворачиваем камеру с помощью transform.RotateAroundLocal. Мы вращаем камеру и фон вместе, так что камера всегда лицом к фону (т.е. фон н выйдет за экран).
И еще одно – давайте соединим новые public свойства (public properties). Переключитесь в Unity и выберите объект “Player” в “Hierarchy”. Перетащите “Main Camera” из “Hierarchy” на новое свойство “Main Camera” в инспекторе; перетащите объект “Background” из “Hierarchy” на новое свойство “Game Background” в инспекторе.
Поздравляю, мы наконец-то закончили! Выберите “File/Build&Run” и запустите игру на iPhone и наслаждайтесь бомбежкой акул под разными углами.
Дебаггинг в Unity.
Во время работы над этим проектом у вас могут возникнуть проблемы. Вот несколько вещей, которые надо иметь ввиду:
- Не забывайте про кнопку Pause в тулбаре. Если вам нужно остановить выполнение игры и проверить свойства объектов, просто нажмите Pause, а затем осматривайте сцену и значения в инспекторе.
- Если вы не уверены, что ваш метод запускается, напечатайте в консоле сообщение (как и в Xcode). Используйте: Debug.Log(“message”). Чтобы перейти в консоль выберите “Window/Console”.
- Развивайте в себе привычку: Когда вы закончили кодинг в MonoDevelop и вернулись в Unity, посмотрите в статус бар в нижней части окна. Если вы написали неверный код вы получите соответствующее сообщение красными буквами.
- Если объекты не двигаются, трижды проверьте привязан ли код к объекту.
- Когда игра запущена, вы можете редактировать значения в инспекторе, чтобы выбрать то, что вам подходит. Однако, следует помнить, что эти изменения будут потеряны, когда вы остановите игру. Так что, после тестирования остановите игру и только потом продолжайте разработку.
Что дальше?
Здесь можно скачать законченный проект с изменениями из второй части урока.
Если вы хотите углубиться в изучение Unity, то вам может помоч официальный сайт программы, а именно раздел Support и, конечно же, Форум.
Если того что мы сделали вам не достаточно вы сможете усовершенствовать нашу игру добавив, например, следующее:
Если того что мы сделали вам не достаточно вы сможете усовершенствовать нашу игру добавив, например, следующее:
- Добавить звуки к взрывам и музыку к game over/win сценам.
- Добавить несколько вариантов взрывов со случайной сменой.
- Добавить несколько уровней.
Мы прошли очень простое введение в Unity, но я думаю сейчас у вас есть понимание того, в каком направлении двигаться. Если у вас есть какие-либо предложения, замечания, поправки, то прошу вас оставлять комментарии.
Скачать исходники проекта (конечный вариант) & Скачать с GIt
Уроки не мои и переводил не я, но отредактировано и очищено от вирусов мной. Уроки с сайта http://lookapp.ru/, им говорим спасибо за такой прекрасный перевод статей. Оригинал статьи - http://www.raywenderlich.com/.
Скачать исходники проекта (конечный вариант) & Скачать с GIt
Уроки не мои и переводил не я, но отредактировано и очищено от вирусов мной. Уроки с сайта http://lookapp.ru/, им говорим спасибо за такой прекрасный перевод статей. Оригинал статьи - http://www.raywenderlich.com/.
Ни разу не украл http://www.raywenderlich.com/4551/how-to-make-a-2-5d-game-with-unity-tutorial-part-1
ОтветитьУдалитьСамый самый низ статьи читай
Удалить