Вторник, 19 Марта 2024, 09:42

Приветствую Вас Гость

Меню сайта
Категории каталога
Создание игр [354]
Статьи об общих понятиях связанных с созданием игр.
Программирование [82]
Гайды по программированию на разных ЯП.
Движки и Гейммейкеры [144]
Статьи о программах для создания игр, уроки и описания.
Софт [39]
Различные программы, в том числе в помощь игроделам.
2D-графика [14]
Уроки по рисованию, растр, пиксель-арт, создание спрайтов и пр.
3D-графика [16]
Уроки по моделированию, ландшафт, модели, текстурирование и пр.
Моддинг игр [5]
Модификация компьютерных игр, создание дополнений, перевод, хакинг.
Игры [160]
Статьи об играх, в том числе и сделанных на гейммейкерах.
Разное [128]
Статьи, которые не вошли в определённые разделы.
Наш опрос
Какой вид используется в ваших играх?
Всего ответов: 10336
Главная » Статьи » Движки и Гейммейкеры

Создание интерфейса системы диалогов в Unity3D


Привет, это небольшой урок о реализации интерфейса системы диалогов в Unity3D. Отмечу, что в статье не будет описано построение базы данных диалогов. В статье речь идет только о интерфейсе.

Для удобства я создал проект с основными ассетами(2 спрайта + шрифт), для его открытия нужна версия Unity3D 4.3+. На основе этого проекта мы будем писать систему диалогов.


I. Откройте пустую сцену "Dev”.
Создайте GameObject с именем "DialogueSystem
В него добавьте два объекта типа "GUITexture
Назначьте им текстуры, и соответственно переименуйте их в "Background” и "Pointer
Теперь нужно задать Pixel Inset текстурам. Для текстуры задника это:


Pixel Inset для указателя:


Не забудьте изменить расположение текстур на 0,0,0, а с указателя уберите галочку активности.
Тексту дайте имя "Text”, поставьте размер 38 и шрифт из папки "Fonts”, по желанию измените надпись, ну и отрегулируйте позицию:


Теперь из окна "Game” можно наблюдать примерно такую картину:


Создайте пустой GameObject с именем "Answers”, и внутри добавьте три объекта типа "GUIText” (временно можно отключить объект Text, что бы не мешался)
Точно так же настройте размер, шрифт, обязательно дайте смешное значение в поле текст.
Отрегулируйте позицию всем трем текстам, что бы все было примерно как здесь:



Отключите Answers и включите Text. Сохраните сцену и проект(на всякий случай).
II. Теперь по коду. Скачаем для начала iTween, с ним даже плохие ассеты могут показывать хорошую картинку, благодаря красивым анимациям.

Зайдите в Asset Stote, в поиск введите "iTween”


Импортируйте его в проект.
В папке Scripts создайте скрипт DialogueEditor на языке C#.
Откройте его и тут же добавьте туда этот кусок кода, так мы будет управлять нашими объектами:
<div class="bbCodeBlock"><div class="bbCodeName" style="padding-left:5px;font-weight:bold;font-size:7pt">Код</div><div class="codeMessage" style="border:1px inset;max-height:200px;overflow:auto;height:expression(this.scrollHeight<5?this.style.height:scrollHeight>200?'200px':''+(this.scrollHeight+5)+'px');"> public GameObject pointer; 
public GameObject answers;
public GameObject textBackground;
public GameObject text;
</div></div>
Добавьте скрипт к объекту DialogueSystem. Поставьте каждому полю его соответствующее значение:


Дальше довольно много переменных:
<div class="bbCodeBlock"><div class="bbCodeName" style="padding-left:5px;font-weight:bold;font-size:7pt">Код</div><div class="codeMessage" style="border:1px inset;max-height:200px;overflow:auto;height:expression(this.scrollHeight<5?this.style.height:scrollHeight>200?'200px':''+(this.scrollHeight+5)+'px');"> public float letterDelay = 0.06f; //Задержка в написании одной буквы для красивого эффекта 
public float transitionTime = 0.5f; //Время всех твинов

private string currentText; //Текущий текст
private string testText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
  "Sed sit amet interdum dui. Morbi et turpis ac tellus ullamcorper placerat. " +
  "Vivamus rutrum neque non luctus dapibus. " +
  "Nam elementum, nibh in lacinia ullamcorper, magna tortor pretium lorem, nec feugiat velit magna eget nisl. " +
  "Interdum et malesuada fames ac ante ipsum primis in faucibus. " +
  "Sed fringilla magna augue, vel fermentum turpis mattis eu."; //Любой текст, который будет форматироваться и изменяться в процессе.
private List<string> testAnswers = new List<string> (); //Лист с тремя вариантами ответов
private string formattedText; //Отформатированный текст для нашего окна
private string nextText; //Отрезок оставшегося текста
private bool tweenCompleted; //Любое действие можно будет совершить только если все анимации и твины закончены
private bool answersMode; //Отвечам или читаем
private int selectedAnswer = 0; //Выбранный на данный момент ответ
private int maxLetters = 50; //Макс. кол-во букв
private int maxLines = 3; //Макс. кол-во строчек
</div></div>
В начале документа добавьте импорт: "using System.Collections.Generic;” - это для использования "List”
Код функции Reset (если уже не терпится все скопипастить, архив с проектом в конце статьи):
<div class="bbCodeBlock"><div class="bbCodeName" style="padding-left:5px;font-weight:bold;font-size:7pt">Код</div><div class="codeMessage" style="border:1px inset;max-height:200px;overflow:auto;height:expression(this.scrollHeight<5?this.style.height:scrollHeight>200?'200px':''+(this.scrollHeight+5)+'px');"> void Reset (bool next = false) { 
  text.SetActive (true); //Возвращаем все на свои места
  answersMode = false;
  tweenCompleted = false;
  text.guiText.text = "";
  formattedText = "";
  iTween.FadeFrom (textBackground, 0, next ? transitionTime/3 : transitionTime/2); //Небольшое ускорение анимации, если это не первое появление
  iTween.MoveFrom(textBackground,iTween.Hash("y",-1f,"time",next ? transitionTime/3 : transitionTime/2,
  "delay",0,"oncomplete","OnAppearingTweenComplete","onCompleteTarget", gameObject));  
  if (next) //Если есть продолжение текста, значит сейча выводим его
  {
  currentText = nextText;
  }
  else currentText = testText;
}
</div></div>
Функция Start:
<div class="bbCodeBlock"><div class="bbCodeName" style="padding-left:5px;font-weight:bold;font-size:7pt">Код</div><div class="codeMessage" style="border:1px inset;max-height:200px;overflow:auto;height:expression(this.scrollHeight<5?this.style.height:scrollHeight>200?'200px':''+(this.scrollHeight+5)+'px');"> void Start () { 
  answersMode = false;
  testAnswers.Add ("i'm going to say hello");
  testAnswers.Add ("i'm going to say shut up");
  testAnswers.Add ("i'm going to say goodbye");
  Reset ();
}
</div></div>
Функция форматирования текста под нашу форму:
<div class="bbCodeBlock"><div class="bbCodeName" style="padding-left:5px;font-weight:bold;font-size:7pt">Код</div><div class="codeMessage" style="border:1px inset;max-height:200px;overflow:auto;height:expression(this.scrollHeight<5?this.style.height:scrollHeight>200?'200px':''+(this.scrollHeight+5)+'px');"> public string FormatString ( string newText ) {   
  string[] words = newText.Split(" "[0]);
  string result = "";  
  int numberOfLines = 1;  
  int letterCounter = 0;
   
  for( int index = 0; index < words.Length; index++)
  {
  string word = words[index].Trim();
  if (index == 0) {
  result = words[0];
  letterCounter+=words[0].Length;
  }  
   
  if (index > 0 ) {  
  if (letterCounter + word.Length + 1 < maxLetters)
  {
  result += " " + word;  
  letterCounter+=word.Length + 1;
  }
  else if (numberOfLines < maxLines)
  {
  result += "\n" + word;  
  letterCounter = word.Length;
  numberOfLines += 1;
  nextText = "";
  }
  else if (numberOfLines == maxLines)
  {
  nextText = currentText;
  nextText = nextText.Remove(0, result.Length);
  break;
  }
  }  
  }  
  return result;
}
</div></div>
Тут же и функция "TypeText”, которая будет рисовать текст по одной букве:
<div class="bbCodeBlock"><div class="bbCodeName" style="padding-left:5px;font-weight:bold;font-size:7pt">Код</div><div class="codeMessage" style="border:1px inset;max-height:200px;overflow:auto;height:expression(this.scrollHeight<5?this.style.height:scrollHeight>200?'200px':''+(this.scrollHeight+5)+'px');"> IEnumerator TypeText () { 
  formattedText = FormatString (currentText);
  foreach (var letter in formattedText.ToCharArray()) {
  text.guiText.text += letter;
  yield return new WaitForSeconds(letterDelay);
  if (text.guiText.text == formattedText)  
  {
  break;
  }
  }
}
</div></div>
Функция Update:
<div class="bbCodeBlock"><div class="bbCodeName" style="padding-left:5px;font-weight:bold;font-size:7pt">Код</div><div class="codeMessage" style="border:1px inset;max-height:200px;overflow:auto;height:expression(this.scrollHeight<5?this.style.height:scrollHeight>200?'200px':''+(this.scrollHeight+5)+'px');"> void Update () { 
  if (tweenCompleted) {  
  if (answersMode == false) {
  if (Input.GetKeyDown (KeyCode.Space))
  {
  if (text.guiText.text != formattedText) {
  text.guiText.text = formattedText;
  }
  else if (text.guiText.text == formattedText && nextText != "") {
  Reset(true);
  }
  else if (text.guiText.text == formattedText && nextText == "")
  {
  ShowAnswers();
  }
  }
  }
  else {
  if (Input.GetKeyDown (KeyCode.DownArrow)) {
  if (selectedAnswer + 1 < testAnswers.Count) {
  selectedAnswer++;
  }
  else if (selectedAnswer + 1 >= testAnswers.Count) {
  selectedAnswer = 0;
  }
  iTween.Stop(pointer);
  ResetPointer();
  }
  if (Input.GetKeyDown (KeyCode.UpArrow)) {
  if (selectedAnswer + 1 > 1) {
  selectedAnswer--;
  }
  else if (selectedAnswer + 1 <= 1) {
  selectedAnswer = testAnswers.Count - 1;
  }
  iTween.Stop(pointer);
  ResetPointer();
  }
  if (Input.GetKeyDown (KeyCode.Space)) {
  SelectAnswer();
  }
  if (iTween.Count(pointer) == 0) StartPointerTween();
  }
  }
}
</div></div>
Мы почти готовы. Код связанный с ответами и анимацией указателя:
<div class="bbCodeBlock"><div class="bbCodeName" style="padding-left:5px;font-weight:bold;font-size:7pt">Код</div><div class="codeMessage" style="border:1px inset;max-height:200px;overflow:auto;height:expression(this.scrollHeight<5?this.style.height:scrollHeight>200?'200px':''+(this.scrollHeight+5)+'px');"> private void ResetPointer () {
pointer.transform.position = answers.GetComponentsInChildren<GUIText>() [selectedAnswer].transform.position;
pointer.guiTexture.pixelInset = new Rect(((answers.GetComponentsInChildren<GUIText>() [selectedAnswer].transform.position.x/Screen.width) +
answers.GetComponentsInChildren<GUIText>() [selectedAnswer].GetScreenRect().width) * 1.05f,
pointer.guiTexture.pixelInset.y,pointer.guiTexture.pixelInset.width,pointer.guiTexture.pixelInset.height);
}

private void StartPointerTween() {
iTween.MoveAdd(pointer,iTween.Hash("name","pointer","x",0.01f,"time",0.4f, "looptype", iTween.LoopType.pingPong, "easetype", iTween.EaseType.easeInOutCirc));
}

void SelectAnswer () {
tweenCompleted = false;
pointer.SetActive(false);
Reset();

answers.SetActive (false);
}

void ShowAnswers()
{
iTween.FadeFrom (textBackground, 0, transitionTime/2);
iTween.MoveFrom (textBackground,iTween.Hash("y",-1f,"time",transitionTime/2,"delay",0,"oncomplete","OnAnswersTweenComplete","onCompleteTarget", gameObject));

tweenCompleted = false;
answersMode = true;
text.SetActive (false);
} </div></div>
Ну и много, много коллбеков:
<div class="bbCodeBlock"><div class="bbCodeName" style="padding-left:5px;font-weight:bold;font-size:7pt">Код</div><div class="codeMessage" style="border:1px inset;max-height:200px;overflow:auto;height:expression(this.scrollHeight<5?this.style.height:scrollHeight>200?'200px':''+(this.scrollHeight+5)+'px');"> private void OnPointerAppearingTweenComplete () {
tweenCompleted = true;
StartPointerTween ();
}

private void OnAppearingTweenComplete () {
tweenCompleted = true;
StartCoroutine(TypeText());
}

private void OnDisappearingTweenComplete () {
tweenCompleted = true;
gameObject.SetActive (false);
}

private void OnFirstAnswerTweenComplete () {
selectedAnswer = 0;
pointer.SetActive (true);
ResetPointer ();

iTween.MoveFrom (pointer, iTween.Hash("x",1f,"time",transitionTime/4,"delay",0,"oncomplete","OnPointerAppearingTweenComplete","onCompleteTarget", gameObject));
iTween.FadeFrom (pointer, 0, transitionTime/2);
}

private void OnAnswersTweenComplete () {
answers.SetActive (true);
pointer.guiTexture.color = new Color (pointer.guiTexture.color.r,pointer.guiTexture.color.g,pointer.guiTexture.color.b,1f);

foreach (Transform child in answers.transform)
{
child.gameObject.SetActive(true);
}

float modifier = 0.5f;
Component[] answersFields = answers.GetComponentsInChildren<GUIText>();

for (int i = 0; i < 3; i++) {
if (i < testAnswers.Count) {
modifier++;
answersFields[i].guiText.text = testAnswers[i];
if (i == 0) {
iTween.MoveFrom (answersFields[i].gameObject, iTween.Hash("y",-1f - modifier,"time",transitionTime/2,"delay",0,
"oncomplete","OnFirstAnswerTweenComplete","onCompleteTarget", gameObject));
}
else {
iTween.MoveFrom (answersFields[i].gameObject, iTween.Hash("y",-1f - modifier,"time",transitionTime/2,"delay",0));
}
iTween.FadeFrom (answersFields[i].gameObject, 0, transitionTime/2);
}
else {
answersFields[i].gameObject.SetActive(false);
}
}
tweenCompleted = false;
}</div></div>

С кодом таки все. Поставьте теперь Дилей в районе 0.06 и запускайте:

Осилили? Спасибо.
Ссылка на архив с проектом.
Категория: Движки и Гейммейкеры | Добавил: TideS (08 Декабря 2013)
Просмотров: 20586 | Комментарии: 6 | Рейтинг: 4.4/5 |
Теги: gui, itween, юнити уроки, система диалогов, визуальные новеллы, Уроки unity3d, RPG, Unity 4.3, Диалоги, Asset Store
Дополнительные опции:
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:

Игровые объявления и предложения:
Если вас заинтересовал материал «Создание интерфейса системы диалогов в Unity3D», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела. Предлагаются такие схожие материалы: Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.

Всего комментариев: 6
+0-
6 alexsilent   (06 Октября 2014 05:19) [Материал]
alexsilentОформление бы получше, а то непонятно где код, а где просто текст... cry

+1-
5 beril   (18 Января 2014 18:28) [Материал]
berilЧто это с оформлением??7

+1-
4 beril   (02 Января 2014 17:42) [Материал]
berilА чо скачать нельзя?

+2-
2 KamiRonin   (01 Января 2014 14:58) [Материал]
отличная работа TideS. респект!!!
ничем не отрицая ее ценности - просто дополнительная ссылка free система в ассет сторе
(честно скажу - я тоже взялся писать нечто подобное - просто для развития навыков)
удачи и реализации.

+1-
3 TideS   (01 Января 2014 16:22) [Материал]
TideSПриятно слышать. За ссылку также спасибо.

+1-
1 JHawk   (10 Декабря 2013 17:28) [Материал]
JHawkso good smile

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск по сайту
10 случ. движков
  • Xamarin
  • UPBGE
  • Rootex
  • Panda3D
  • Sonic Maker
  • Alice
  • 3D Rad Rus
  • Existence Engine
  • Orx
  • Superpowers
  • Друзья сайта
    Игровой форум GFAQ.ru Перевод консольных игр
    Все права сохранены. GcUp.ru © 2008-2024 Рейтинг