Как делается интерфейс в программах

В прошлой статье я рассказала о принципах разработки игрового интерфейса и о том, какие нюансы нужно учитывать при его проектировании. Теперь я хочу рассказать о порядке работы над задачами, связанными с концептированием, отрисовкой и внедрением интерфейса в игру. Давайте представим, что вы занимаетесь разработкой UI с нуля, на самом старте проекта. С чего же начинается эта работа?

1. Концепция геймдизайнера

После того, как была написана документация для базового функционала игры, можно начинать разработку игрового интерфейса. Как правило, она идет параллельно с созданием первого прототипа игры — ведь даже с прототипом нужно как-то взаимодействовать. Для того, чтобы дизайнер интерфейсов мог приступить к своей части, ему нужно получить подробное ТЗ на UI от геймдизайнера. Такое ТЗ, как правило, состоит из:

  • макета интерфейса (можно сделать через инструмент “рисунок” в обычном Google документе, или просто сфотографировать схему, нарисованную от руки на бумажке);
  • краткого описания основных игровых задач интерфейса, ключевых нюансов для игрока;
  • сносок с пояснением для каждого элемента и каждой кнопки на макете интерфейса;
  • детального описания функционала интерфейса, которое является описанием технических возможностей тех или иных элементов, а также их отклика на взаимодействие;
  • реакция, которой отвечает игра на нажатие на ту, или иную кнопку (автоматическое закрытие окна, переход в другое окно, сдвиг панелей, подсвечивание и прочее);
  • нередко — ссылки на документы с описанием механики, если окно представляет собой активно участвующую в геймплее структуру (например, интерфейс крафта или улучшения каких-либо предметов: по факту прямо в окне апгрейда происходит игровой процесс).

Такое ТЗ нужно написать на все базовые интерфейсы, чтобы дизайнер мог сразу начать работу над всеми макетами — опять же, напомню, ему нужно смотреть на всю картину в целом, а не на одно отдельно взятое окошко. Под базовыми интерфейсами я подразумеваю не описание всех игровых окон сразу, а только самых основных, позволяющих протестировать основную механику вашей игры. Главное, для чего это нужно — выработать общую структуру и список элементов на основе разных по содержанию окон.

Графический интерфейс. Как создать программу на C++

Пример задачи для дизайнера интерфейсов ищите в конце статьи.

2. Макет дизайнера интерфейсов

После передачи вашего макета и описания дизайнеру, нужно сесть и обговорить детали. Вероятнее всего, дизайнер предложит что-то сделать по-другому, перекомпоновать элементы, или укажет на то, что похожий элемент уже был в другом окне, и здесь нужно использовать такой же. Вместе вы обсуждаете изменения макета, вносите принятые вами изменения в документацию и в геймдизайнерский макет. Далее дизайнер интерфейсов делает свой макет с помощью заглушек и самых простых внешне элементов. Это нужно для того, чтобы проверить функциональность и удобность интерфейса, т.е. с целью собрать первичный прототип UI “на коленке” — ведь это гораздо быстрее, чем отрисовывать его в идеальном виде, а потом выяснить, что была допущена какая-то логическая ошибка.

Делаем программу с интерфейсом на Processing

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

Что же делать, если у вас маленькая команда и нет дизайнера интерфейсов?

Придется поднапрячься, вооружиться советами из вот этой статьи , и взять на себя эту роль самому геймдизайнеру. Лично я неоднократно занималась созданием макетов интерфейсов, которые потом вставлялись в игру для тестирования механик и юзабилити. Здесь мой совет будет довольно субъективным и дилетантским, я поделюсь способом, который мне всегда помогал, несмотря на то, что, возможно, есть тулзы получше и попроще. Я всегда пользовалась для создания макетов UI программой Adobe Illustrator : скачивала бесплатные векторные иконки и кнопки, и с их помощью собирала относительно приятный для глаза интерфейс. Мне нравится, что с Иллюстратором легко работать — он довольно простой, интуитивно понятный и его самых примитивных функций с головой хватает для того, чтобы сделать красивый заглушечный интерфейс с правильными размерами и пропорциями.

Сайты, где можно скачать векторы с бесплатной лицензией, легко гуглятся в интернете, но я докину пару ссылок:

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

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

3. Верстка интерфейса программистом

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

Когда прототип готов, его можно посмотреть в игре, оценить удобство и то, насколько хорошо он справляется со своей работой. Если обнаруживаются недочеты, или какие-то проблемы, то пункты 2-3 выполняются повторно, с учетом корректировок. На самом деле, игра с прототипом позволит вам оценить не только интерфейс, но и саму игровую механику. Взаимодействуя с игрой через структурно финализированный интерфейс, вы можете вдруг понять, что самой механике чего-то не хватает, или она не выполняет своих функций и ей требуется какая-то доработка. В таком случае, после исправления механики, повторение пойдет с пункта 1.

Читайте также:
Png в какой программе

4. Разработка визуальной части и стиля

Если начинает более или менее вырисовываться логика интерфейса и базовые окна уже могут быть утверждены после тестирования, можно заняться отрисовкой интерфейса на чистовую. Для этого, опираясь на жанр и сеттинг, нужно определиться с целым рядом вещей.

Цвет

Нужно понять, в какой цветовой гамме будет ваш интерфейс, какие сочетания цветов будут на нем использоваться. Какого цвета будут бэки окон, какого цвета заголовки, какого цвета плашки и прогресс бары. Как будут дифференцироваться по цвету кнопки, отвечающие за разный функционал. Для примера, в Dishonored 2 основной цвет — это серо-черно-синие тона в сочетании с холодным бело-голубым.

Основные художественные элементы

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

В Dishonored 2 основные художественные элементы — это полупрозрачные текстуры на плашках, вензельки, треугольники-осколки и пятна “крови”. Классическая викторианская готика с острыми и мрачными вкраплениями.

Основные формы

Какие формы будут преобладать в вашем интерфейсе? Круглые прогресс-бары и иконки, или может быть прямоугольники со скругленными углами? Будут элементы полупрозрачными? Объемными, или плоскими? В Dishonored 2 наблюдается стройное единство форм.

Почти все они — это четкие прямоугольники и квадраты с острыми краями в сочетании с ровными кругами.

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

Затем потихоньку отрисовываются на чистовую все утвержденные и запрототипированные окна, и чем дальше, тем проще их создавать, потому что, напоминаю, во всех окнах используются одинаковые элементы. А как мы уже знаем, единообразие элементов — это одна из основных и непоколебимых догм разработки интерфейса. Для того, чтобы интерфейсы было удобнее собирать, а также для защиты от ошибок, все повторяющиеся элементы нужно сохранять в одном месте, делая своеобразную картотеку фирменного стиля вашего интерфейса. Такая картотека называется UI Kit , и она вмещает в себя все кнопки, стрелки, плашки, подложки, бары, таймеры, бэки — все, что используется от интерфейса к интерфейсу и составляет его визуальный стиль. Естественно, в каждом игровом окне может быть что-то уникальное, что будет выделять его из остальных и отражать его яркую индивидуальную цель, но базовые элементы стиля все равно будут одинаковыми.

UI Kit представляет из себя что-то такое, только без текста и гораздо более масштабное и детальное. Как видите, даже на этом примере есть множество переиспользуемых элементов: кнопки в нажатом и спокойном состоянии, бары, скроллы, ячейки и многое другое.

5. Внедрение финального интерфейса в игру

Как делается интерфейс в программах

Интерфейс представляет некое описание типа, набор компонентов, который должен иметь тип данных. И, собственно, мы не можем создавать объекты интерфейса напрямую с помощью конструктора, как например, в классах:

IMovable m = new IMovable(); // ! Ошибка, так сделать нельзя interface IMovable

В конечном счете интерфейс предназначен для реализации в классах и структурах. Например, реализуем выше определенный интерфейс IMovable:

// применение интерфейса в классе class Person : IMovable < public void Move() < Console.WriteLine(«Человек идет»); >> // применение интерфейса в структуре struct Car : IMovable < public void Move() < Console.WriteLine(«Машина едет»); >>

При применении интерфейса, как и при наследовании после имени класса или структуры указывается двоеточие и затем идут названия применяемых интерфейсов. При этом класс должен реализовать все методы и свойства применяемых интерфейсов, если эти методы и свойства не имеют реализации по умолчанию.

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

Применение интерфейса в программе:

Person person = new Person(); Car car = new Car(); DoAction(person); DoAction(car); void DoAction(IMovable movable) => movable.Move(); interface IMovable < void Move(); >class Person : IMovable < public void Move() =>Console.WriteLine(«Человек идет»); > struct Car : IMovable < public void Move() =>Console.WriteLine(«Машина едет»); >

В данной программе определен метод DoAction() , который в качестве параметра принимает объект интерфейса IMovable. На момент написания кода мы можем не знать, что это будет за объект — какой-то класс или структура. Единственное, в чем мы можем быть уверены, что этот объект обязательно реализует метод Move и мы можем вызвать этот метод.

Иными словами, интерфейс — это контракт, что какой-то определенный тип обязательно реализует некоторый функционал.

Консольный вывод данной программы:

Человек идет Машина едет

Реализация интерфейсов по умолчанию

Начиная с версии C# 8.0 интерфейсы поддерживают реализацию методов и свойств по умолчанию. Зачем это нужно? Допустим, у нас есть куча классов, которые реализуют некоторый интерфейс.

Если мы добавим в этот интерфейс новый метод, то мы будем обязаны реализовать этот метод во всех классах, применяющих данный интерфейс. Иначе подобные классы просто не будут компилироваться. Теперь вместо реализации метода во всех классах нам достаточно определить его реализацию по умолчанию в интерфейсе. Если класс не реализует метод, будет применяться реализация по умолчанию.

IMovable tom = new Person(); Car tesla = new Car(); tom.Move(); // Walking tesla.Move(); // Driving interface IMovable < void Move() =>Console.WriteLine(«Walking»); > class Person : IMovable < >class Car : IMovable < public void Move() =>Console.WriteLine(«Driving»); >

В данном случае интерфейс IMovable определяет реализацию по умолчанию для метода Move . Класс Person не реализует этот метод, поэтому он применяет реализацию по умолчанию в отличие от класса Car , который определяет свою реализацию для метода Move.

Читайте также:
Как перевести мангу с английского на русский программа на телефон

Стоит отметить, что хотя для объекта класса Person мы можем вызвать метод Move — ведь класс Person применяет интерфейс IMovable , тем не менее мы не можем написать так:

Person tom = new Person(); tom.Move(); // Ошибка — метод Move не определен в классе Person

Множественная реализация интерфейсов

Интерфейсы имеют еще одну важную функцию: в C# не поддерживается множественное наследование, то есть мы можем унаследовать класс только от одного класса, в отличие, скажем, от языка С++, где множественное наследование можно использовать. Интерфейсы позволяют частично обойти это ограничение, поскольку в C# классы и структуры могут реализовать сразу несколько интерфейсов. Все реализуемые интерфейсы указываются через запятую:

class myClass: myInterface1, myInterface2, myInterface3, .

Рассмотрим на примере:

Message hello = new Message(«Hello World»); hello.Print(); // Hello World interface IMessage < string Text < get; set; >> interface IPrintable < void Print(); >class Message : IMessage, IPrintable < public string Text < get; set; >public Message(string text) => Text = text; public void Print()=> Console.WriteLine(Text); >

В данном случае определены два интерфейса. Интерфейс IMessage определяет свойство Text, которое представляет текст сообщения. А интерфейс IPrintable определяет метод Print.

Класс Message реализует оба интерфейса и затем применяется в программе.

Интерфейсы в преобразованиях типов

Все сказанное в отношении преобразования типов характерно и для интерфейсов. Поскольку класс Message реализует интерфейс IMessage, то переменная типа IMessage может хранить ссылку на объект типа Message:

// Все объекты Message являются объектами IMessage IMessage hello = new Message(«Hello METANIT.COM»); Console.WriteLine(hello.Text); // Hello METANIT.COM // Не все объекты IMessage являются объектами Message, необходимо явное приведение // Message someMessage = hello; // ! Ошибка // Интерфейс IMessage не имеет свойства Print, необходимо явное приведение // hello.Print(); // ! Ошибка // если hello представляет класс Message, выполняем преобразование if (hello is Message someMessage) someMessage.Print();

Преобразование от класса к его интерфейсу, как и преобразование от производного типа к базовому, выполняется автоматически. Так как любой объект Message реализует интерфейс IMessage.

Обратное преобразование — от интерфейса к реализующему его классу будет аналогично преобразованию от базового класса к производному. Так как не каждый объект IMessage является объектом Message (ведь интерфейс IMessage могут реализовать и другие классы), то для подобного преобразования необходима операция приведения типов. И если мы хотим обратиться к методам класса Message, которые не определены в интерфейсе IMessage, но являются частью класса Message, то нам надо явным образом выполнить преобразование типов:

if (hello is Message someMessage) someMessage.Print();

Источник: metanit.com

Программирование JavaFX: разработка элементов интерфейса

Иногда даже программистам на Java необходимо создавать интерфейсы, и для этого им приходится изучать дополнительные инструменты. В этом случае им на помощь приходит инструментарий создания GUI, который избавляет от необходимости подключения дополнительных технологий — JavaFX.

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

То есть в случае веб-подхода вы бы использовали, например, HTML, CSS, JavaScript; в случае же с JavaFX эта связка будет выглядеть как FXML, CSS, Java. Это означает, что на выходе мы получим десктопное приложение.

Что нужно для работы

Для работы с JavaFX вам понадобится установить две вещи: JDK Java и SDK JavaFX. Почему раздельно? Раньше всё это было несколько проще, и JavaFX шла в комплекте с основным JDK Java, сейчас же этот фреймворк распространяется в виде отдельного модуля, и вам надо будет скачать его отдельно.

Сказанное выше касается только тех ситуаций, когда вы не используете ранние версии Java вплоть до 10, так как в них JavaFX уже содержится в комплекте JDK.

Если же вы используете версию 11+, то у вас есть два варианта: либо качать SDK JavaFx и устанавливать зависимости вручную, либо воспользоваться любой системой сборки, например, Maven. Кстати говоря, если вы будете использовать именно Maven, то вам даже не придётся качать JavaFX, так как он загрузит необходимые модули самостоятельно.

Вкратце пару слов про системы сборки и для чего это надо: в настоящее время, как правило, те компьютеры, на которых происходит разработка приложения, и те компьютеры, которые будут запускать приложения, — это разные машины.

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

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

По ссылке выше (где описана установка с применением Maven) как раз говорится о настроенных архетипах для ускорения процесса создания проектов, которые предлагает разработчик JavaFX.

Например, простой проект:

mvn archetype:generate -DarchetypeGroupId=org.openjfx -DarchetypeArtifactId=javafx-archetype-simple -DarchetypeVersion=0.0.3 -DgroupId=org.openjfx -DartifactId=sample -Dversion=1.0.0 -Djavafx-version=17.0.1

Читайте также:
Программа чтобы поставить музыку на звонок

Структура приложений

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

Если говорить о структуре типичного приложения, то оно представляет собой своеобразную матрёшку, представленную тремя уровнями: Stage, Scene, Node:

image

Источник картинки: Education wiki

То есть Stage — это то, что вмещает всё содержимое, внутри него находится как минимум один элемент Scene.

Все элементы Scene хранятся в виде так называемого Scene Graph, то есть в виде иерархии элементов.

На рисунке выше Node — это управляющие элементы, в качестве которых могут выступать как отдельные кнопки, так и макеты. Кроме того, может присутствовать вложенность одних элементов в другие.

Говоря об узле, можно увидеть, что на картинке он обозначен тремя идентификаторами: ROOT, BRANCH, LEAF.

  • ROOT — самый первый узел, который называется также первым графом сцены.
  • BRANCH — узел, у которого имеются производные дочерние узлы.
  • LEAF — конечный узел, у которого нет никаких дочерних. В качестве подобного примера можно назвать такие, как, например, box, rectangle.

image

Источник картинки: Vojtechruzicka

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

Чтобы проиллюстрировать всё вышесказанное, обратимся к документации, несмотря на то, что она относится к 8 версии, многое ещё применимо и в новых версиях. Например, нам необходимо создать простое приложение, которое выводит на экран какую-то фразу:

image

Источник картинки: Oracle

Если мы попробуем представить структуру этого приложения в виде схемы (Scene Graph, о котором мы уже говорили выше), то выглядеть это будет вот так:

image

Источник картинки: Oracle

Соответственно, код этого примера будет выглядеть следующим образом:

Как вы видите, код создаёт кнопку, при нажатии на которую в консоль выводится надпись.

А допустим, нам необходимо некоторым образом организовать управляющие элементы, для этого служат, например, такие классы, как TilePane, GridPane, StackPane, BorderPane, AnchorPane, FlowPane, VBox, HBox:

image

Источник картинки: Metanit

Все эти панели компоновки входят в пакет javafx.scene.layout, описание классов которого находится по этому адресу:

  • TilePane — элементы в сетке из «плиток» одинакового размера.
  • GridPane — элементы в гибкой сетке строк и столбцов.
  • StackPane — элементы в стеке в обратном порядке.
  • BorderPane — элементы сверху, слева, справа, снизу и по центру.
  • AnchorPane — позволяет привязывать края дочерних узлов к смещению от краёв области привязки.
  • FlowPane — элементы в потоке, который обтекает границу области потока.
  • VBox — элементы в одном вертикальном столбце.
  • HBox — элементы в один горизонтальный ряд.

С применением такой компоновки можно создать достаточно красивые и сложные формы, например, регистрационную форму, подробный процесс создания которой рассмотрен здесь:

image

Источник картинки: Callicoder

Создание и настройка GridPane происходит вот таким образом:

// Создание новой панели сетки GridPane gridPane = new GridPane(); // Положение панели в центре экрана как по вертикали, так и по горизонтали gridPane.setAlignment(Pos.CENTER); // Установка отступа по 20 пикселей с каждой стороны gridPane.setPadding(new Insets(40, 40, 40, 40)); // Установка горизонтального зазора между столбцами gridPane.setHgap(10); // Установка вертикального зазора между строками gridPane.setVgap(10); // columnOneConstraints будет применяться ко всем узлам, размещённым в первом столбце ColumnConstraints columnOneConstraints = new ColumnConstraints(100, 100, Double.MAX_VALUE); columnOneConstraints.setHalignment(HPos.RIGHT); // columnTwoConstraints будет применяться ко всем узлам, размещённым во втором столбце ColumnConstraints columnTwoConstrains = new ColumnConstraints(200,200, Double.MAX_VALUE); columnTwoConstrains.setHgrow(Priority.ALWAYS); gridPane.getColumnConstraints().addAll(columnOneConstraints, columnTwoConstrains);
Полный код примера выше

Говоря об управляющих элементах (которые, как вы видели, использовались выше), например, о таких, как кнопки, мы фактически говорим об узле (Node). Примерный вид иерархии классов, которые наследуются от Node, можно увидеть на картинке ниже:

image

Источник картинки: Metanit

Полный же список элементов, где так или иначе используется Node, можно посмотреть здесь.

Говоря о тексте, который используется в различных элементах сцены, можно сказать, что к текстовым элементам возможно применять различные эффекты, так как они наследуются от Node.

Причём, учитывая, что сам этот класс наследуется от Shape, текстовые элементы могут содержать обводку или любую заливку, так же как и обычная фигура. Примеры подобной работы с текстом имеются здесь:

image

Источник картинки: Oracle

Код текста выше:

String family = «Helvetica»; double size = 50; TextFlow textFlow = new TextFlow(); textFlow.setLayoutX(40); textFlow.setLayoutY(40); Text text1 = new Text(«Hello «); text1.setFont(Font.font(family, size)); text1.setFill(Color.RED); Text text2 = new Text(«Bold»); text2.setFill(Color.ORANGE); text2.setFont(Font.font(family, FontWeight.BOLD, size)); Text text3 = new Text(» World»); text3.setFill(Color.GREEN); text3.setFont(Font.font(family, FontPosture.ITALIC, size)); textFlow.getChildren().addAll(text1, text2, text3); Group group = new Group(textFlow); Scene scene = new Scene(group, 500, 150, Color.WHITE); stage.setTitle(«Hello Rich Text»); stage.setScene(scene); stage.show();

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

image

Источник картинки: Oracle

Говоря о графическом наполнении, нельзя не отметить, что в развитие фреймворка серьёзный вклад привносит сообщество энтузиастов, сложившееся вокруг этой технологии. Если взять те же самые диаграммы, одна из команд разработчиков предложила библиотеку, которая позволяет создавать диаграммы достаточно впечатляющего вида:

image

Источник картинки: Github HanSolo

image

Источник картинки: Github HanSolo

image

Источник картинки: Github HanSolo

Или, например, библиотека по генерации разнообразных часов и индикаторов:

image

Источник картинки: Github HanSolo

Другие интересные и впечатляющие примеры использования библиотек для создания полезных приложений вы можете найти в разделе Community.

Завершая этот рассказ, следует отметить, что мы рассмотрели ключевые моменты этого фреймворка лишь обзорно и «глубоко не углубляясь». Поэтому в рамках этого рассказа не был рассмотрен графический способ создания интерфейсов с помощью Scene Builder, а также мы не затронули использование специфической реализации XML для JavaFX — FXML.

Обо всём этом мы поговорим в следующий раз.

НЛО прилетело и оставило здесь промокод для читателей нашего блога:

— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS .

Источник: temofeev.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru