Простая 2D книга / разбивка текста

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


Для создания нам нужна какая нибудь текстура открытой книги и на развороте страниц добавить объект UI Text:


То есть нам нужно сделать своего рода окно, где будет выводиться текст, слева и справа. А под ними мы добавляем еще UI Text, который нужен для отображения текущего номера страницы. И плюс, нам понадобится еще две UI кнопки. Всё.

Теперь сам скрипт:

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

public class CalculatePages : MonoBehaviour {

	[SerializeField] private string loadBook = "MainBook"; // имя текстового файла
	[SerializeField] private string booksPath = "Books"; // имя папки с текстовым файлов в Resources
	[SerializeField] private Text leftPage; // левая страница
	[SerializeField] private Text rightPage; // правая страница
	[SerializeField] private Text LPN; // номер левой страницы
	[SerializeField] private Text RPN; // номер правой страницы
	[SerializeField] private Button nextButton; // листаем вперед
	[SerializeField] private Button prevButton; // листаем назад
	private List<string> pagesList = new List<string>();
	private int pageCount;

	void Start()
	{
		nextButton.onClick.AddListener(()=>{Next();});
		prevButton.onClick.AddListener(()=>{Prev();});
		leftPage.rectTransform.sizeDelta = rightPage.rectTransform.sizeDelta;

		Calculate(loadBook);
	}

	void SetPages()
	{
		leftPage.text = pagesList[pageCount];
		rightPage.text = (pageCount + 1 > pagesList.Count-1) ? string.Empty : pagesList[pageCount + 1];
		LPN.text = (pageCount + 1).ToString();
		RPN.text = (pageCount + 2).ToString();
	}

	void Next()
	{
		pageCount += 2;
		SetPages();
		prevButton.interactable = true;
		if(pageCount + 1 >= pagesList.Count-1) nextButton.interactable = false;
	}

	void Prev()
	{
		pageCount -= 2;

		if(pageCount < 0)
		{
			leftPage.text = string.Empty;
			rightPage.text = string.Empty;
			LPN.text = string.Empty;
			RPN.text = string.Empty;
			prevButton.interactable = false;
			return;
		}

		SetPages();
		nextButton.interactable = true;
	}

	void Calculate(string fileName)
	{
		TextAsset binary = Resources.Load<TextAsset>(booksPath + "/" + fileName);

		if(binary != null && !string.IsNullOrEmpty(binary.text))
		{
			pagesList.Clear();
			pagesList = Pages(binary.text, leftPage);
			leftPage.text = string.Empty;
			rightPage.text = string.Empty;
			LPN.text = string.Empty;
			RPN.text = string.Empty;
			nextButton.interactable = true;
			prevButton.interactable = false;
			pageCount = -2;
		}
	}

	List<string> Pages(string text, Text page) // определяем на сколько страниц нужно разбить текст
	{
		if(string.IsNullOrEmpty(text) || page == null) return new List<string>();

		TextGenerationSettings settings = page.GetGenerationSettings(page.rectTransform.rect.size);
		TextGenerator textGenerator = new TextGenerator();

		string current = text;
		int index = 0;
		List<string> pages = new List<string>();

		while(current.Length != 0)
		{  
			textGenerator.Populate(current, settings);
			index = textGenerator.characterCountVisible;
			pages.Add(current.Substring(0, index));
			current = current.Substring(index).Trim();
		}

		return pages;
	}
}

Скрипт совсем не сложный, а ключевая функция тут Pages, в ней происходит основное колдунство... Где берется образец страницы, то самое окно UI Text, затем копируются его настройки и далее делается проверка, сколько текста поместиться на страницу, этот текст вырезается и помещается в массив, затем повтор процедуры до тех пор, пока текст не кончится. На выходе, данная функция выдает текстовый массив, где каждый элемент содержит часть текста для страницы.

Скачать демо проект:

Внимание! Посетители, находящиеся в группе Гости, не могут скачивать файлы.
Тестировалось на: Unity 2017.3.1

Комментариев 6

Офлайн
ПРивет, сори что вопрос не по теме. Как создать Plane по размерам которые задаст пользователь ( НАпример в инпут напишет 5 на 5 ) и на сцене создает такую площадь
Офлайн
Light 4 марта 2018
Андрей Сандаков, ну нужно парсить значение инпута, через метод int.TryParse например.
Офлайн
Light,
спасибо
Офлайн
orkons 8 мая 2018
Как исправить, что книга начинается с пустой страницы?
Офлайн
Light 8 мая 2018
orkons, после строки Calculate(loadBook); добавить:

pageCount += 2;
SetPages();
Функцию void Prev() изменить на:

void Prev()
{
	pageCount -= 2;
	SetPages();

	if(pageCount == 0)
	{
		prevButton.interactable = false;
	}

	nextButton.interactable = true;
}
Офлайн
orkons 8 мая 2018
Пришлось добавить строчку в скрипт:

void Start()
{
nextButton.onclick.AddListener(()=>{Next();});
prevButton.onclick.AddListener(()=>{Prev();});
leftPage.rectTransform.sizeDelta = rightPage.rectTransform.sizeDelta;

Calculate(loadBook);
void Next()//чтобы изначально перелистнуть страницу
}
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Дешевый хостинг
  • Яндекс.Метрика