Как создать игру, ничего не умея. Часть вторая: сцена (уровень), квесты, интерактивные объекты

Пост опубликован в блогах iXBT.com, его автор не имеет отношения к редакции iXBT.com (подробнее »)
| Обзор | Компьютерные и мобильные игры
Предисловие

Привет^ народец, сегодня я продолжу свою попытку создать игру^ используя только информацию из интернета.
Первая часть вот тут — ТЫК.

В этой статье я попробую создать игровую комнату, она же сцена, уровень, локация и так далее, а так же попробуем прописать НПЦ (внутриигровых персонажей) с квестами, и взаимодействие с предметами. Ну что, начнём словоблудие!

Сцена

Для начала откроем наш проект над которым мы работали в прошлой статье, и переименуем нашего персонажа в Player.

Далее^ используя наши познания из прошлого урока^ создаём папку Prefabs, для тех^ кто забыл как это делается, нажимаем на Assets в древе, далее правой кнопкой в папке assets, Create -> Folder.

Далее перетягиваем нашего персонажа Player в папочку Prefabs, что даёт нам возможность его сохранить со всеми настройками и скриптами^ которые мы использовали в прошлой статье. Если выползет диалоговое окно, выбираем Original Prefab, а после в папочке Scene аналогичным способом создаем новую сцену под именем Scene_01 (и снова для самых-самых, правой кнопкой тык, и выбираем Create -> Scene). Это и будет наша рабочая сцена на эту статью, дважды тык на Scene_01 и у нас снова пустая рабочая область.

Смотрим в экран и вот тут начинается главная головная боль, необходимо придумать, как будет выглядеть наш первый уровень, который необходимо построить, а главное продумать его так, чтобы он полностью удовлетворял наши потребности. Обычно для таких целей я беру пачку листов А4 и карандаш, а после несколько дней рисую разные варианты уровня, если что-то мне не нравится после рисовки, я всё равно это оставляю на будущее, поскольку в итоге из всех рисунков и собирается один более-менее играбельный уровень для игры. Но мы сейчас всё делаем по велению интернета, поэтому возьмём за идею стандартную ситуацию.

  • Построим закрытые ворота, перед которыми будут стоять стражники, а за воротами будет город, в который нам необходимо попасть.
  • Стражники нас не пропустят, пока мы не выполним квест.
  • Ворота откроются после выполнения квеста.

Вот такой вот незамысловатый сюжет будет в нашей сцене =)

Строительство

Для начала нам нужна земля, заходим в GameObjects -> 3D Object -> Terrain, это создало нам землю, но она довольно большая для моей сцены, поэтому заходим в Inspector, нажимаем на шестеренку (Terrain Setting) и ищем Mesh Resolution (On Terrain Data) для меня подошли показатели:

  • Terrain Width: 70
  • Terrain Length: 70
  • Terrain Height: 120

Тут я наверное немного поясню ситуацию. Данный Terrain я использовать не буду, у меня есть все готовые префабы для создания играбельной сцены, но для людей, которые собираются САМИ создать свою землю и объекты, прийдётся использовать данную функцию. В ней есть всё необходимое, чтобы сделать из этого квадрата равнины, горы, леса, пустыню. Необходимо просто использовать нужную Вам кисть, и натянуть текстуру. Я же в буду использовать префабы, которые шли в комплекте с персонажем, а Terrain послужит мне границами уровня. (Для тех кто всё же хочет, чтобы я создал игровую область без префабов, пишите в комментариях, тогда будет понятно, нужна ли такая информация).

Используя префабы, я начинаю строительство, выбираю для начала зелень и растягиваю её почти на весь Terrain, далее выбираю ворота, стены, горы, деревья, дорогу, и просто перетаскиваю их в сцену, немного позиционирую, а далее делаю копи-паст и собираю простейший уровень, получилось примерно так.

Все префабы ландшафта я поместил в Terrain, чтобы они не загромождали древо сцены. За 5 минут получилось невесть, что, но если провести за этим делом пару дней, то можно собрать что-то подобное.

Давайте посмотрим как поведёт наш персонаж себя в новом месте проживания. Заходим в папку Prefabs и переносим наш префаб Player в сцену, у меня он появился где-то сбоку, но я простым движением переместил его в начало каменной дороги. После удаляю из сцены Main Camera, потому как к нашему персонажу уже прикреплена камера, и дабы не было конфликтов избавляемся от камеры в сцене. Жму кнопку Play и осматриваю новые земли. Персонаж отлично себя чувствует в новом месте. Исходя из этого мы можем перейти наконец к НПЦ и квестам.

  NPC или неигровые персонажи

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

И вот двое из ларца одинаковых с лица стоят и охраняют наши ворота. Им я сразу дал имена NPC_01 и NPC_02, давайте подойдём и посмотрим как это выглядит в игре. 

Да уж, в игре это выглядит так же ужасно, как и в сцене =) Оживим наших горе-охранников, чтобы они не стояли как пугало в поле. Для этого вернёмся к нашей первой статье, где мы оживляли нашего персонажа, и проделываем туже процедуру с болванчиками у ворот. Для тех, кто не помнит, направляемся в mixamo, находим подходящие нам анимации, добавляем их в проект, создаём аниматор контроллер и прикрепляем его к болванчикам.

Я прикрепил анимацию засыпающего человека к одному болванчику, и строго стоящего второму, это мне нужно для более полного погружения для квеста. Я понимаю, что это совсем необязательно, ведь мы не пытаемся создать ААА проект прямо на коленке как Юбисофт (это лично моё мнение), но всё же и создавать Г* мне не хочется, хоть это и попытка сделать всё при помощи интернета. Наконец пришло время для квеста!

Квест

Тут мне пришлось немного использовать крота, дабы прорыть интернет для правильного скрипта и построения квеста. Его выполнение, тоже должно было работать правильно и не вызывать ошибок, и я снова на коне! Давайте приступим.

Для начала создадим папку с названием Quest, а в ней соответственно создадим три скрипта с названиями: Sword, Quest, NPC (названия произвольны, Вы можете их назвать как Вам будет удобнее, но не забывайте тогда исправить class и обращения к скриптам). Первым же будет скрипт Quest:

Скрипт Quest

using UnityEngine;
using System.Collections;
public class Quest: MonoBehaviour
{
public bool quest; // отображает название квеста на экране;
public string MissionText; // название квеста;
public string ObjectTag; // тэг объекта;
public bool MissionObjects; //отображает собран предмет или нет;
public int Money; // количество денег;

void OnGUI()
{

if (quest)
{
GUI.Label(new Rect(20, 80, 300, 30), " " + MissionText); // значение названия квеста будет браться из скрипта NPC;
if (MissionObjects)
{ // если предмет собран;
GUI.Label(new Rect(150, 80, 200, 30), "[Выполнено]"); // выводит надпись;
}
}
}
}

 Его мы добавляем к нашему персонажу, и изменяем его ТЕГ на Player, тег Вы можете поставить в inspector нашего Player 

Далее создаём скрипт NPC

Скрипт NPC

using UnityEngine;
using System.Collections;

public class NPC: MonoBehaviour

{

public bool quest; //переменная, которая обозначает взят квест или нет;
public bool vis; // переменная, которая будет отображать диалог между персонажами;
public string missionText; // Текст который будет отображать наименование квеста;
public string missionTag; //Тэг объекта, который необходимо принести;
private Quest MP; // подключаем скрипт Quest;

void Start()

{
MP = GameObject.FindGameObjectWithTag(«Player»).GetComponent<Quest>(); // определяем что скрипт Quest будет находится на персонаже с тэгом player;
}

void Update()

{
GameObject MissionTagScanner = GameObject.FindGameObjectWithTag(«Player»); // персонаж у которого берем квест будет взаимодействовать только с тем объектом у которого тэг Player;
if (Input.GetKeyDown(KeyCode.E) & Vector3.Distance(transform.position, MissionTagScanner.transform.position) < 2) // При нажатии на клавишу Е и при дистанции между персонажами меньше чем 2;
{
vis = true; // переменная vis принимает значение true;
}
}
void OnGUI()
{
if (vis) // если переменная равна true;
{
if (!quest) // и если квест еще не взят;
{
GUI.Box(new Rect((Screen.width — 300) / 2, (Screen.height — 300) / 2, 300, 300), «Квест»); // то на экране отображается окно с названием Квест;
GUI.Label(new Rect((Screen.width — 300) / 2 + 5, (Screen.height — 300) / 2 + 15, 290, 250), «Куда ломишься, не видишь закрыто, вали отсюда пока не получил по щам.Еще и этот бездельник меч свой потерял вчера, всю ночь искал так и не нашел, теперь вот спит на посту.Сделаем так, принесешь мне потерянный меч моего напарника и я тебя пропущу, берешься? „); // и текстом который описывает квест;
if (GUI.Button(new Rect((Screen.width — 100) / 2, (Screen.height — 300) / 2 + 250, 100, 40), “Ок»)) // при нажатии на кнопку Ok;
{
quest = true; // квест взят;
MP.quest = true; // отображает название квеста на экране;
MP.MissionText = «Принести меч»; // текст квеста;
MP.ObjectTag = missionTag; // тэг объекта который необходимо принести;
vis = false; // все диалоговые окна закрываются;
}
}
else
{ // если же квест уже взят;
GUI.Box(new Rect((Screen.width — 300) / 2, (Screen.height — 300) / 2, 300, 300), «Квест»);
GUI.Label(new Rect((Screen.width — 300) / 2 + 5, (Screen.height — 300) / 2 + 15, 290, 250), «Принес?»); //то описание квеста меняется на другой текст;
if (MP.MissionObjects) // если вы уже подобрали объект;
{
if (GUI.Button(new Rect((Screen.width — 100) / 2, (Screen.height — 300) / 2 + 250, 100, 40), «Да»)) // то появится кнопка да, при нажатии на которую;
{
quest = false; // переменная квест принимает значение false, т.е. не взят ;
MP.quest = false; // название квеста не будет отображаться на экране ;
MP.MissionText = ""; // убирается название квеста;
MP.ObjectTag = ""; // обнуляется тэг объекта;
MP.MissionObjects = false; // объект считается не подобранным;
vis = false; // диалоговое окно закрывается;
}
}
else
{ // если вы еще не подобрали объект;
if (GUI.Button(new Rect((Screen.width — 100) / 2, (Screen.height — 300) / 2 + 250, 100, 40), «Нет»)) // то вместо кнопки да, будет кнопка нет;
{
vis = false; // при нажатии на которую, окно просто закроется;
}
}
}
}
}
}

Этот скрипт мы добавляем к NPC_01, так как я решил, что именно он будет давать нам квест!

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

Создаём скрипт Sword:

Скрипт Sword

using UnityEngine;
using System.Collections;

public class Sword: MonoBehaviour

{
private Quest MP; // опять подключаем скрипт Quest;

void Start()
{
MP = GameObject.FindGameObjectWithTag(«Player»).GetComponent<Quest>();
} // определяем что скрипт Quest будет находится на персонаже с тэгом player;
void OnMouseUp()
{
if (Input.GetMouseButtonUp(0)) // если при нажатии на правую кнопку мыши;
{
if (MP.ObjectTag == gameObject.tag) // и при том что тэг объекта равен тому значению которое написано в ObjectTag;
{
MP.MissionObjects = true; // то переменная принимает значение true, т.е. считается что предмет собран;
Destroy(gameObject); // и удаляем этот объект со сцены;
}
}
}
}

Добавляем скрипт к нашему мечу, и теперь необходимо создать для него тег Sword. В Inspector нажимаем на Tag выбираем Add Tag, жмём на плюсик и прописываем название Sword. Готово, тег Sword готов. Возвращаемся к NPC_01, смотрим Inspector, видим наш NPC(Script) и в строке Mission Tag прописываем sword. Если всё сделано правильно, то у нас появился наш первый квест! Давайте проверим как он работает.Запускаю игру, подхожу к НПЦ и нажимаю клавишу Е (именно она прописана в скрипте как клавиша вызова диалога).

НПЦ дал наш первый квест! Нажимаю ОК и отправляюсь на поиски меча. Как видим, у нас появилась надпись, оповещающая нас, какой именно квест мы сейчас проходим в левой части экрана.

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

Вернувшись к стражнику, он задаёт вопрос, я на него отвечаю, и вижу что квест выполнен, YoHOO!

Наш первый выполненный квест в этом мире, теперь мы настоящий герой! Но остался другой вопрос, ведь квест мы выполнили, а охранник обещал нас пропустить. Теперь необходимо сделать анимацию открывающейся решетки, чтобы она открывалась, как только мы выполняем квест. Для этого выбираем нашу решетку и заходим во вкладку Animation (если у Вас её нет, то зайдите в Window -> Animation -> Animation и у Вас появится эта вкладка либо нажмите Ctrl+6). Решетку я назвал Door_01 и теперь во вкладке Animation давайте сделаем анимацию поднятия решетки. Нажимаем Create и я ставлю название DoorOpen. Далее я выбираю кадр 0:55 нажимаю на красную кнопку, а после поднимаю решетку, снова нажимаю на красную кнопку, и вот у нас есть ключи анимации как поднимается решетка.

Создаю еще одну анимацию, но на этот раз решетка находится внизу, и сохраняю её как DoorClose. После захожу в Animator, и подключаю анимацию, как мы это делали уже множество раз. Проверяю и вижу, что анимация работает, решетка непрерывно открывается =).

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

Скрипт OpenDoor

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class OpenDoor: MonoBehaviour
{
private Quest MP; // подключаем скрипт Quest;

void Start()

{
MP = GameObject.FindGameObjectWithTag(«Player»).GetComponent<Quest>(); // определяем что скрипт Quest будет находится на персонаже с тэгом player;
}


void Update()
{
if (MP.Money == 100)
{
GetComponent<Animator>().SetBool(«ODoor», true);
}
}
}

Это единственный скрипт, что я нашел в интернете, который мне подошел. Я конечно его немного подправил под мои нужны в виде MP.Money. А для того, чтобы эта строчка работала, необходимо подключить скрипт Quest, что мы и сделали в самом начале. В скриптах, что я нашел ранее, есть параметр, который даёт вознаграждение в виде денег за выполнение квеста, поэтому мы добавим одну строчку, которая нам даст 100 монет, на которые и будет отвечать скрипт открывающий решетку.

Добавляем строчку в скрипт NPC
if (GUI.Button(new Rect((Screen.width — 100) / 2, (Screen.height — 300) / 2 + 250, 100, 40), «Да»)) // то появится кнопка да, при нажатии на которую;
{
quest = false; // переменная квест принимает значение false, т.е. не взят ;
MP.quest = false; // название квеста не будет отображаться на экране ;
MP.MissionText = ""; // убирается название квеста;
MP.ObjectTag = ""; // обнуляется тэг объекта;
MP.MissionObjects = false; // объект считается не подобранным;
MP.Money = MP.Money + 100;
vis = false; // диалоговое окно закрывается;

}

После всех манипуляций, добавляем наш скрипт OpenDoor на объект решетки, и вперед тестить!

После того как я сдал квест и получил свои 100 монет, решетка открылась =). На этом я думаю на сегодня хватит, продолжение будет скоро!

Заключение

Очередной этап создания игры закончен, абсолютно всё, что я тут проделал было взято из уроков или статей интернета.

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

ПС

Большинство роликов на ютубе были абсолютно бесполезны! Зря потраченное время =).

4 комментария

110097281221967604426@google
Вообще с тех. части это сцена)
Icy
Я же в буду использовать префабы, которые шли в комплекте с персонажем, а Terrain послужит мне границами уровня. (Для тех кто всё же хочет, чтобы я создал игровую область без префабов, пишите в комментариях, тогда будет понятно, нужна ли такая информация)

Это общая практика, что префабы дают вместе с моделью персонажа? Если вас не затруднит, какие-то базовые инструкции по созданию ландшафта с нуля были бы интересны.
Вообще, спасибо за серию статей, вы молодец.
182749768@vkontakte
Префабы не всегда бывают в паке. Надо читать что внутри ассет пака, перед покупкой, а то могут быть и без текстур, и без анимации или просто «статуи». У некоторых авторов ассетов есть видео на ютубе, где они показывают содержимое своих ассетов. Если вдруг, есть много свободного времени, то советую посмотреть обучающие ролики по 3D моделированию и анимации, вдруг вам будет достаточно начальных навыков и не придётся покупать ассеты.
n
Хорошо, как будет свободная минута напишу статью по Terrain

Добавить комментарий