Как я создал собственный 3D движок и игру на нём за 20 месяцев
Эту статью я написал для своего блога в октябре 2017 года.
Речь идёт об игре Speebot, которая сейчас выпущена в Steam. Бесплатная demo версия прилагается.
Я разрабатывал эту игру с января 2016 года в своё свободное время в одиночку. Мною выполнено всё программирование, дизайн игрового процесса, создание графики и музыки. Кроме того, я написал собственный игровой движок с нуля.
Люди часто спрашивают меня, почему я решил создать свой движок, когда на рынке доступно множество бесплатных универсальных движков. Есть много причин, и о них я попытаюсь рассказать в этой статье.
Одним из самых больших преимуществ собственного движка является абсолютный контроль кода. Есть возможность настроить его именно так, как это нужно для конкретной задачи. Такой узкоспециализированный движок получается оптимизированным для конкретного типа игр и работает быстрее и надёжнее, чем универсальный движок.
Универсальные игровые движки называются так, потому что они предназначены для общего использования, и в них заложены функции, которые не всем нужны. Это неизбежно приводит к «раздуванию» кода, и к замедлению производительности игр.
Второе преимущество — это контроль самого процесса разработки. Я считаю, что инструментарий должен быть по-максимуму удобным для разработчика. Что является удобным — зависит от самого типа данной игры. Например, для Speebot — это встроенный редактор уровней, который позволяет быстро создавать новые уровни и незамедлительно их тестировать.
Решение использовать собственный движок позволяет мне интегрировать мои собственные инструменты таким образом, чтобы мне было проще и быстрее создавать контент.
Ещё один большой плюс: не нужно соглашаться с условиями лицензии стороннего движка, подписывать договора и платить проценты от прибыли.
Ну и наконец: написание собственного движка — это очень интересно.
Разработка движка началась в январе 2016 года. Я назвал его YUME («мечта» по-японски). Он написан на Haxe, C++ и OpenGL. Я использую модифицированную версию библиотеки Lime, которая включает в себя несколько полезных функций, например, позволяет загружать ресурсы и открывает доступ к OpenGL.
До начала создания движка я почти ничего не знал о разработке 3D игр. Нужно было разбираться в OpenGL читая документацию, форумы и уроки, предназначенные для других языков (Java и C++). Через пару месяцев у меня получился довольно стабильный 3D-визуализатор.
Кроме самого 3D-визуализатора, нужно было с нуля создать множество разных систем: 2D-визуализатор, машину состояний, систему временных шагов (об этом позже), систему интерфейсов, систему управления мышью, клавиатурой и джойстиками, динамические тени, 3D звуковую систему (используя OpenAL), загрузку моделей (в собственном формате, основанном на IQM), «скелетные» анимации, иерархию объектов, эффект зеркального отражения в реальном времени, отображения текста и так далее.
В конце концов, получилась 3D библиотека, которую можно использовать для чего-то конкретного. Многое из того, что я перечислил, присутствует и в других движках, но в YUME есть несколько отличий. Одно из них — система временных шагов.
Система временных шагов гарантирует, что движок обрабатывает и показывает кадры игры с определённым интервалом. В YUME нет ограничения по количеству кадров в секунду, т.е. нет привязанности к 30 или 60 кадрам в секунду. Частота кадров может быть любая, а игра всё равно будет работать с одной и той же скоростью, потому что частота обновления логики не связана с частотой обновления экрана. На компьютерах разных мощностей может быть разная производительность, и время для показа одного кадра может быть любым. А логика всегда привязана к частоте 62.5 циклов в секунду (16 миллисекунд на каждый цикл). В этом основной принцип системы временных шагов, хотя есть некоторые крайние случаи.
В результате: на более слабых компьютерах уменьшается частота кадров в секунду, но на игровой процесс это не влияет.
У меня была готовая библиотека, но пока ещё не движок. Пришла пора начать разрабатывать игру, и принимать решения о нужных функциях. К тому времени у меня уже было несколько идей, и я знал, что хотел попробовать поэкспериментировать с 3D «плитками».
Я начал создавать систему игровых уровней, которая использовала что-то похожее на 2D плитки (tilemaps), но с одним дополнительным измерением. Получается, что уровень можно сложить из «кубиков», как конструктор. Я создал редактор карт, чтобы ускорить процесс создания уровней. В итоге этот редактор попал в финальную версию игры и доступен каждому игроку.
Движок автоматически определяет, какую 3D модель использовать для отображения каждой плитки, в зависимости от соседних плиток. Придумал способ, как объединить все плитки в одну общую 3D модель, чтобы видеокарте не нужно было рисовать каждую плитку индивидуально. Вся карта рисуется за один раз, что очень сильно улучшает производительность.
Уровни можно редактировать и тестировать сразу. Для продуктивности — то что нужно.
Я написал простую систему игровой физики и начал экспериментировать с игровым процессом. Через несколько недель был готов первый прототип игры, в котором игрок мог перемещать цилиндр по 3D уровню.
YUME продолжал развиваться параллельно с разработкой Speebot (примерно в это время я выбрал такое название для игры). Было найдено и устранено несколько проблем с архитектурой движка, добавилось несколько новых функций: физика, частицы, отражения на поверхности воды, инструменты для анимации камеры, интерактивные объекты. Постепенно библиотека эволюционировала в игровой движок.
Я продолжал добавлять новые элементы игрового процесса, оставляя элементы, которые казались мне интересными, и избавляясь от лишнего. После некоторых экспериментов с художественным направлением графики игры я создал персонажа в Blender — маленького робота с одним колесом. Персонаж нарисован и анимирован в мультяшном стиле.
В это время я уже работал в основном над самой игрой, а не над движком. Я продолжал создавать новые уровни, декорации, персонажи и элементы игры.
В конце 2016 года я сделал паузу от разработки игры, и посвятил несколько месяцев изучению и практике написания музыки. У меня нет музыкального образования, но это — моё хобби. У меня уже был небольшой опыт в композиции музыки для моей предыдущей игры Hypnorain, но я хотел улучшить свои навыки, поэтому снова погрузился в изучение музыкальной теории. Для композиции музыки я использовал программу SunVox, которая является виртуальным модульным синтезатором. В финальной версии игры Speebot всего 23 трека, которые вместе составляют более часа оригинальной музыки. Я удовлетворён результатом, и продолжу улучшать свои навыки для следующей игры.
После этого я концентрировался на создании новых уровней, добавлении новых игровых элементов, написании музыки и устранении ошибок. Такой подход к разработке игр мне по душе. Если мне становится скучно заниматься одним и тем же делом, я переключаюсь на другой вид деятельности, и поэтому не теряю интереса к разработке игры.
После выпуска нескольких демо версий, обработки отзывов от игроков и улучшения игры, Speebot был выпущен в октябре 2017 года. В финальной версии игры 200 уровней, 4 мира, редактор пользовательских уровней, несколько дополнительных режимов игры, и много другого дополнительного контента.
Самое сложное при разработке игры было сохранять мотивацию и интерес на протяжении всех 20 месяцев. Работать над игрой мне удавалось только по вечерам после университета и работы, и по выходным дням. Но всё равно, это было очень интересно.
Я продолжу использовать и развивать свой движок YUME в своих будущих играх, и уже начал работать над своим следующим проектом.
После написания этой статьи я разработал и выпустил ещё две игры на этом движке: сюжетная приключенческая игра Phantom Path, и игра-головоломка Pilie Pals.
Java — как делать 3D игры?
Как сделать 3D игру на языке программирования Java, можете написать сами, либо скинуть ссылку на статью или видео-урок по этой теме.
Лучший ответ
Для создания 3D игр на языке Java вам необходимо использовать специальные библиотеки, которые позволяют работать с графикой и 3D-моделями. Вот некоторые из наиболее популярных библиотек для создания 3D игр на Java:
jMonkeyEngine: Это одна из наиболее популярных библиотек для создания 3D игр на Java. jMonkeyEngine предоставляет обширный набор инструментов для создания игр, включая инструменты для работы с физикой, анимацией, звуком и сценами.
LWJGL: Эта библиотека предоставляет низкоуровневый доступ к OpenGL и другим графическим API. Она также включает в себя инструменты для работы с звуком и вводом пользовательских действий.
Java 3D: Эта библиотека предназначена специально для создания 3D-графики и предоставляет набор инструментов для работы с графикой, анимацией и моделированием.
JOGL: Эта библиотека предоставляет доступ к OpenGL на языке Java. JOGL позволяет создавать игры с высокой производительностью и высоким качеством графики.
Выбор конкретной библиотеки зависит от ваших индивидуальных потребностей и уровня опыта. Однако, с использованием любой из этих библиотек, вам понадобится изучить основы 3D-графики и математики, такие как векторы, матрицы и преобразования. Кроме того, вам может потребоваться изучить язык шейдеров для создания эффектов и текстур.
Простейшая 3D игра на libGDX под Android в 200 строк кода
Я преподаю в IT школе Samsung программирование под Android для школьников. Программа обучения охватывает множество разнообразных тем. В числе прочих предусмотрен один урок, знакомящий учеников с основами 3D-графики под Android. Стандартный учебный материал этого урока показался мне очень бесполезным по нескольким причинам:
- Используется голый OpenGL, а поскольку на практике в программировании игр чаще всего используются готовые движки, то это мало полезно для школьников в контексте их собственных проектов. Кто-то может возразить, что увидеть в деле чистый OpenGL полезно для понимания основ, но здесь вступает в дело 2-й недостаток.
- Урок очень непонятный. У типичного школьника, пусть и разбирающегося в программировании, нет достаточной базы, чтобы понимать многое из того, что описано в уроке (например матрицы многие пройдут только уже в ВУЗе).
- В конце урока мы приходим к результату — отрисовка 3-х треугольников средствами OpenGL. Это настолько далеко от реальной 3D-игры, что легко может отбить интерес у школьника.
Поэтому я решил подготовить свой урок, описывающий основы использования libGDX под Android, а раз я все равно готовлю этот материал, заодно разместить его здесь — на хабре. В этом уроке мы сделаем наипростейшую 3D игру под Android, скриншот которой вы можете видеть во вступлении к статье. Итак, интересующиеся, добро пожаловать под кат.
Почему именно libGDX? Во-первых код должен быть на Java, потому-что мы обучаем студентов именно Java-программированию. Это сужает выбор. Во-вторых libGDX оказался очень прост в освоении. В моих условиях это большое достоинство, перевешивающее прочие недостатки.
Идея игры очень проста: вы второй пилот истребителя, отвечающий за системы вооружения. Вам нужно успеть вовремя выстрелить лазерным оружием когда двигатель вражеского корабля находится в перекрестье прицела, пока ваш первый пилот старается не дать сбросить себя с хвоста. То есть по сути геймплей описывается фразой «кликни вовремя».
В ходе этого урока нам понадобится только Android Studio 1.5 (версия может отличаться, здесь я привел ту, с которой у меня все точно получилось).
Для начала нам нужно скачать мастер создания проекта от libGDX, который значительно облегчает задачу первоначальной настройки проекта (скачать можно по ссылке в инструкции на wiki проекта libGDX). Вот, что за настройки я туда вбил:
Импортируем получившийся проект в Android Studio и начинаем собственно работу с кодом. Основной код игры находится в файле MyGdxGame.java (если вы назвали этот класс так же, как и я). Удалим шаблонный код и начнем писать свое:
public class MyGdxGame extends ApplicationAdapter < public PerspectiveCamera cam; final float[] startPos = ; @Override public void create() < cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); cam.position.set(startPos[0], startPos[1], startPos[2]); cam.lookAt(0, 0, 0); cam.near = 1f; cam.far = 300f; cam.update(); >>
Здесь мы создаем новую камеру с углом обзора в 67 градусов (что является довольно часто используемым значением) и задаем соотношением сторон ширину и высоту экрана. Затем мы устанавливаем позицию камеры в точку (150, -9, 0) и указываем, что она будет смотреть на центр координат (поскольку именно там мы планируем разместить пирамидку, вокруг которой будет строиться геймплей). И наконец мы вызываем служебный метод update(), чтобы все наши изменения применились к камере.
Теперь можно изобразить что-то, на что мы будем смотреть. Мы, конечно, могли бы использовать какую-то 3D модель, но сейчас, в целях упрощения урока, мы будем рисовать только простую пирамиду:
public class MyGdxGame extends ApplicationAdapter < . public Model model; public ModelInstance instance; @Override public void create() < . ModelBuilder modelBuilder = new ModelBuilder(); model = modelBuilder.createCone(20f, 120f, 20f, 3, new Material(ColorAttribute.createDiffuse(Color.GREEN)), VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal); instance = new ModelInstance(model); instance.transform.setToRotation(Vector3.Z, 120); >@Override public void dispose() < model.dispose(); >>
Тут мы создаем экземпляр ModelBuilder, который предназначен для создания моделей в коде. Затем мы создаем простую модель конуса с размерами 20x120x20 и количество граней 3 (что в итоге и дает пирамиду) и задаем ему материал зеленого цвета. Когда мы создаем модель, необходимо задать как минимум Usage.Position. Usage.Normal добавляет к модели нормали, так что освещение сможет работать правильно.
Модель содержит все необходимое для отрисовки и управления собственными ресурсами. Однако она не содержит информации, где именно отрисовываться. Так что нам нужно создать ModelInstance. Он содержит данные о расположении, параметрах вращения и масштаба для отрисовки модели. По умолчанию рисуется в (0, 0, 0) так что мы просто создаем ModelInstance, который отрисуется в (0, 0, 0). Но кроме того, мы еще вызовом метода transform.setToRotation() поворачиваем нашу пирамидку на 120 градусов по оси Z (так ее лучше видно с позиции камеры).
Модель необходимо освобождать после использования, так что мы добавляем немного кода в наш метод Dispose().
Теперь давайте отрисуем наш экземпляр модели:
public class MyGdxGame extends ApplicationAdapter < . public ModelBatch modelBatch; @Override public void create() < modelBatch = new ModelBatch(); . >@Override public void render() < Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); modelBatch.begin(cam); modelBatch.render(instance); modelBatch.end(); >@Override public void dispose() < model.dispose(); modelBatch.dispose(); >>
Здесь мы добавляем в метод create ModelBatch, который отвечает за отрисовку и инициализацию модели. В методе render мы очищаем экран, вызываем modelBatch.begin(cam), рисуем наш ModelInstance и затем вызываем modelBatch.end() чтобы завершить процесс отрисовки. Наконец, нам нужно освободить modelBatch чтобы удостовериться, что все ресурсы (например шейдеры, которые он использует) корректно освобождены.
Выглядит довольно неплохо, но немного освещения могло бы улучшить ситуацию, так что давайте его добавим:
public class MyGdxGame extends ApplicationAdapter < . public Environment environment; @Override public void create() < environment = new Environment(); environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f)); environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, 10f, 10f, 20f)); . >@Override public void render() < . modelBatch.begin(cam); modelBatch.render(instance, environment); modelBatch.end(); >>
Здесь мы добавляем экземпляр Environment. Мы создаем его и задаем окружающий (рассеянный) свет (0.4, 0.4, 0.4) (обратите внимание, что значение прозрачности игнорируется). Затем мы создаем DirectionalLight (направленный свет) с цветом (0.8, 0.8, 0.8) и направлением (10, 10, 20). Я предполагаю, что вы уже знакомы с источниками освещения в общем хотя здесь все итак довольно очевидно. Наконец, во время отрисовки мы передаем созданный environment (окружение) в обработчик моделей.
Поскольку мы все-таки пишем игру, не мешало бы добавить немного динамики в статичную картинку. Сделаем, чтобы камера немножко сдвигалась при каждой прорисовке. Здесь уместно сказать о жизненном цикле libGDX-приложения. При старте вызывается метод create(), в котором уместно размещать всю инициализацию. Затем N раз в секунду вызывается метод render(), где N — ваш FPS. Этот метод отрисовывает текущий кадр. Поэтому чтобы добавить в приложение динамичности, нам просто нужно в render() как-то менять параметры наших игровых объектов.
public class MyGdxGame extends ApplicationAdapter < . final float bound = 45f; float[] pos = ; float[] Vpos = new float[3]; final float speed = 2f; private float getSpeed() < return speed * Math.signum((float) Math.random() - 0.5f) * Math.max((float) Math.random(), 0.5f); >@Override public void create () < . // initialize speed for (int i = 0; i < 3; i++)< Vpos[i] = getSpeed(); >> @Override public void render() < . for (int i = 0; i < 3; i++) < pos[i] += Vpos[i]; if (pos[i] if (pos[i] >= startPos[i] + bound) < pos[i] = startPos[i] + bound; Vpos[i] = getSpeed(); >> cam.position.set(pos[0], pos[1], pos[2]); cam.update(); modelBatch.begin(cam); modelBatch.render(instance, environment); modelBatch.end(); > >
Здесь мы создаем иллюзию того, что наша пирамидка двигается, хотя на самом деле движется камера, посредством которой мы смотрим на нее. В начале игры в методе create() случайным образом выбирается значение приращения Vpos[i] для каждой координаты (скорость). На каждой перерисовке сцены в методе render() к координатам прибавляется значение шага изменения. Если мы вышли за установленные границы изменения координат, то возвращаем координаты в эти границы и генерируем новые скорости, чтобы камера начала двигаться в другую сторону. cam.position.set() собственно и устанавливает камеру в новые координаты, рассчитанные по описанному выше закону, а cam.update() завершает процесс изменения параметров камеры.
Можно отметить, что на разных устройствах скорость движения пирамидки будет разной из-за разницы в FPS и, соответственно, количестве вызовов render() в секунду. По хорошему здесь бы добавить зависимость приращения координат от времени между кадрами, тогда скорости были бы везде одинаковыми. Но мы этим заниматься не будем, чтобы не усложнять проект.
А теперь сделаем игровой HUD:
public class MyGdxGame extends ApplicationAdapter < . protected Label label; protected Label crosshair; protected BitmapFont font; protected Stage stage; protected long startTime; protected long hits; @Override public void create() < . instance.transform.setToRotation(Vector3.Z, 90).translate(-5,0,0); font = new BitmapFont(); label = new Label(" ", new Label.LabelStyle(font, Color.WHITE)); crosshair = new Label("+", new Label.LabelStyle(font, Color.RED)); crosshair.setPosition(Gdx.graphics.getWidth() / 2 - 3, Gdx.graphics.getHeight() / 2 - 9); stage = new Stage(); stage.addActor(label); stage.addActor(crosshair); startTime = System.currentTimeMillis(); >@Override public void render() < . StringBuilder builder = new StringBuilder(); builder.append(" FPS: ").append(Gdx.graphics.getFramesPerSecond()); long time = System.currentTimeMillis() - startTime; builder.append("| Game time: ").append(time); builder.append("| Hits: ").append(hits); builder.append("| Rating: ").append((float) hits/(float) time); label.setText(builder); stage.draw(); >@Override public void resize(int width, int height) < stage.getViewport().update(width, height, true); >>
Обратите внимание, что параметры вращения и сдвига (метод translate(x, y, z))пирамидки изменены так, чтобы она находилась в центре экрана и направлена туда же, куда смотрит наша камера. То есть на старте игры мы находимся с противником на одном курсе и смотрим ему прямо в двигатели.
Здесь мы создаем 2 текстовых метки. Метка label предназначена для отображения внутриигровой информации (FPS, время игры и статистика попаданий). Метка crosshair рисуется красным цветом и содержит в себе только один символ — «+». Это показывает игроку середину экрана — его прицел. Для каждой из них в конструкторе new Label(, new Label.LabelStyle(font, )) задается стиль, включающий в себя шрифт и цвет надписи. Метки передаются в объект Stage методом addActor(), и, соответственно, отрисовываются автоматически когда отрисовывается Stage.
Кроме того для метки crosshair методом setPosition() задается позиция — середина экрана. Здесь мы используем размеры экрана (Gdx.graphics.getWidth(), . getHeight()) чтобы рассчитать, куда нужно поместить наш плюсик, чтобы он оказался в середине. Еще имеет место небольшой грязный хак: setPosition() задает координаты левого нижнего угла надписи. Чтобы в центре экрана оказался именно центр плюсика, я вычитаю из полученного значения эмпирически (то есть наугад) полученные константы 3 и 9. Не используйте такой подход в полноценных играх. Просто плюсик в середине экрана — это несерьезно. Если вам нужно перекрестье прицела, вы можете использовать спрайты.
При каждой отрисовке мы создаем текст через StringBuilder, куда кладем все то, что хотим вывести внизу экрана: FPS, время в игре, количество попаданий и рейтинг. Метод setText() позволяет задать метке текст, что мы и делаем в render() раз за разом.
Правда стрелять то мы пока не можем. Самое время исправить этот недостаток.
public class MyGdxGame extends InputAdapter implements ApplicationListener < . final float zone = 12f; boolean isUnder = false; long underFire; @Override public void create() < . Gdx.input.setInputProcessor(new InputMultiplexer(this)); >@Override public void render() < if (Math.abs(pos[1] - startPos[1]) < zone && Math.abs(pos[2] - startPos[2]) < zone) < isUnder = true; crosshair.setColor(Color.RED); >else < isUnder = false; crosshair.setColor(Color.LIME); underFire = 0; >. > @Override public void pause() <> @Override public void resume() <> @Override public boolean touchDown(int screenX, int screenY, int pointer, int button) < if (isUnder) < underFire = System.currentTimeMillis(); >else < hits /= 2; >return true; > @Override public boolean touchUp(int screenX, int screenY, int pointer, int button) < if (isUnder && underFire != 0) < hits += System.currentTimeMillis() - underFire; underFire = 0; >else < hits /= 2; >return false; > >
Обратите внимание, что описание класса MyGdxGame теперь изменилось. Здесь мы наследуемся от InputAdapter и реализуем интерфейс ApplicationListener. Такая структура позволит нам сохранить наш код в неизменном виде, но дополнить его возможностью обработки пользовательского ввода. В методе create() добавляется строка, регистрирующая наш класс как обработчик ввода. Методы pause() и resume() мы просто обязаны реализовать, поскольку у InputAdapter он абстрактные.
Вся математика расчета попадания находится в render(). Мы проверяем, находятся ли координаты камеры в той зоне, чтобы наш противник был в центре экрана на одном с нами курсе (находятся ли координаты Y и Z в пределах start ± zone). Если мы на одном курсе, значит стрелять можно: устанавливаем isUnder = true и делаем прицел более яркого красного цвета. Опять-таки эта простота определения попадания — это хитрость, основанная на тупости простоте, некоторой условности игрового процесса. Вообще же в libGDX есть средства для определения, какие 3D-модели попали в область касания в общем случае.
Методы обработки касаний называются touchDown (палец коснулся экрана) и touchUp (палец убрали с экрана). Эти методы принимают координаты касания, но мы их здесь использовать не будем. На самом деле нам достаточно определить, находится ли камера сейчас в той позиции, чтобы смотреть на пирамидку прямо. Если это так (пользователь нажал вовремя), то в touchDown мы начинаем подсчет времени, сколько лазер жарил враждебную пирамидку. Если нет, то сокращаем очки пользователя делением надвое (штраф за промах). Когда пользователь отпускает палец, проверяем не отпустил ли он его слишком поздно. Если отпустил поздно, то штрафуем, если вовремя (лазер еще жарил цель), то добавляем очки.
Дополнение: модель истребителя вместо пирамидки
Вобщем-то игра готова, но хочется чтобы выглядела она как-то поприличнее, а пирамидка — это довольно скучно. Так что в качестве опционального дополнения к уроку можно еще реализовать нормальную 3D-модель летательного аппарата вместо пирамидки. Возьмем эту модель и попробуем вставить ее в нашу игру.
Модель поставляется в 4-х форматах разных 3D-редакторов. Однако libGDX использует свой бинарный формат моделей, в который их нужно конвертировать, чтобы использовать в игре. Для этого предусмотрена специальная утилита — fbx-conv. Скачиваем собранные бинарники и распаковываем в какую-нибудь папку. Там есть версия под Windows, Linux и MacOS. Windows-версия запустится без лишних телодвижений, а для Linux и MacOS нужно предварительно выполнить команду
export LD_LIBRARY_PATH=/folder/where/fbx-conv/extracted/
Тем самым мы указываем утилите, где искать свою разделяемую библиотеку libfbxsdk.so, которую она требует для работы. Запускаем утилиту:
./fbx-conv-lin64 -f space_frigate_6/space_frigate_6.3DS
Конечно, вам надо указать свой путь до модели и использовать бинарник для вашей ОС. В итоге у вас получится файл space_frigate_6.g3db , который надо положить в папку проект android/assets (папка с ресурсами приложения для платформы Android).
О сложностях конвертирования моделей для libGDX для тех, кто захочет использовать другие модели
Вообще связка libGDX+fbx-conv очень проблемная. Я перепробовал около десятка бесплатных моделей космических кораблей с http://tf3dm.com/ и http://www.turbosquid.com/ прежде чем у меня получилось найти эту, которая заработала. Сложности самые разные. Иногда модель в игре получается без текстур, иногда она загружается нормально, но просто не отображается, а иногда (это чаще всего) при загрузке модели игра выпадает с OutOfMemoryError. Я, конечно, понимаю, что это мобильная платформа. Но игры в Play Market показывают и намного более сложную графику и памяти им для этого хватает. Даже та модель, которую я в конечном счете использовал, доставила проблем. Из obj нормально не конвертировалась, а вот из 3ds получилось. В свете этого можно сказать, что пока еще у libGDX с поддержкой моделей туговато. Можно использовать этот движок для простеньких игр, если старательно подбирать модели или же делать их самостоятельно с оглядкой на совместимость с libGDX. Или же использовать более продвинутые движки типа jMonkeyEngine.
Ну а теперь подключим это в игре:
public class MyGdxGame extends InputAdapter implements ApplicationListener < . public AssetManager assets; public boolean loading; @Override public void create() < . assets = new AssetManager(); assets.load("space_frigate_6.g3db", Model.class); loading = true; >@Override public void render() < if (loading) if (assets.update()) < model = assets.get("space_frigate_6.g3db", Model.class); instance = new ModelInstance(model); loading = false; >else < return; >. > @Override public void dispose() < model.dispose(); modelBatch.dispose(); >>
Здесь мы создаем экземпляр класса AssetManager, который отвечает за загрузку игровых ресурсов и указываем ему загрузить нашу модельку. На каждой отрисовке мы проверяем, не загрузил ли еще AssetManager модель (метод update(), возвращающий boolean). Если загрузил, то пихаем в instance вместо набившей оскомину пирамидки наш няшный самолетик и устанавливаем loading = false, чтобы это создание inctance не повторялось на каждом кадре, а то ведь assets.update() будет возвращать true дальше на протяжении всего времени работы приложения.
При запуске получим исключение java.io.FileNotFoundException: SPACE_FR.PNG . Значит файл модели не включает текстуры, их нужно засовывать отдельно. Берем из 4-х представленных понравившуюся текстуру, переименовываем в SPACE_FR.PNG , кладем в assets , запускаем. В итоге получаем то, что во вступительной картинке. Ну а на закуску — гифка с игровым процессом:
Итог: мы написали очень простую, но почти полноценную с точки зрения использованных средств (освещение, движение, HUD, касания, модели) игру, уложившись всего в 200 строк кода. Конечно, тут есть многое, что можно улучшить: нормальный прицел, skybox (небо или космос вокруг), звуки выстрелов и полета, игровое меню, нормальное определение попадания и т. п. Тем не менее игра уже содержит самую базу игрового процесса и наглядно показывает самые основные моменты разработки игр на libGDX. Надеюсь этот урок будет способствовать появлению многих новых интересных игр на Android как от моих студентов, так и от аудитории хабра.
Источники:
- https://libgdx.badlogicgames.com/nightlies/docs/api/overview-summary.html
- http://www.todroid.com/android-gdx-game-creation-part-i-setting-up-up-android-studio-for-creating-games/
- https://xoppa.github.io/blog/basic-3d-using-libgdx/
- http://stackoverflow.com/questions/19699801/dewitters-game-loop-in-libgdx
- http://stackoverflow.com/questions/21286055/run-libgdx-application-on-android-with-unlimited-fps
- https://xoppa.github.io/blog/interacting-with-3d-objects/
- https://xoppa.github.io/blog/loading-models-using-libgdx/
Java и создание игр: о движках от А до Я
Создание развлекательных приложений и игр – перспективные направления в программировании. Пользователи готовы не только скачивать соответствующий контент бесплатно, но и платить за него. Особенно тогда, когда софт получается действительно качественным.
Во время создания игр можно использовать разнообразные языки программирования. Некоторые разработчики предпочитают Си-семейство. Оно универсально, но новичкам «с нуля» приступить к коддингу будет трудно. Поэтому тем, кто только начинает изучать процесс разработки игр и программирования, стоит обратить внимание на Java. Это – весьма простой язык, посредством которого можно создавать уникальные перспективные проекты с минимальными трудностями. Основной принцип Джавы – меньше писать, больше делать.
Движок – это…
Перед тем, как приступать к работе с кодом и задумываться над созданием игр, нужно уяснить – справиться с поставленной задачей удастся только при помощи так называемого движка. Термин слышали многие, но не все понимают, что это такое.
Игровой движок – совокупность неких модулей программного типа, которые включают в себя различные элементы, задействованных при создании игр и развлекательных приложений. Готовый «сборник» утилит. Выступает в качестве базового программного обеспечения при разработке игрового софта.
При помощи движка можно обеспечить:
- музыкальное и звуковое сопровождение;
- сетевую игру;
- графическую визуализацию;
- перемещение внутриигровых персонажей (а также их взаимодействие согласно имеющимся скриптам);
- соблюдение физических эффектов и закономерностей;
- встроенные графические сцены.
Грамотно подобранный движок дает разработчику больше возможностей при коддинге. С ним создавать игры для Андроид, Windows/Mac и iOS просто и интересно. Навыки программирования могут быть минимальными.
Движки для программистов и библиотеки на Джаве
Ява – язык программирования, который пользуется у программистов очень большим спросом. Освоить его способен даже новичок без существенных затруднений. Большинство современных платформ для создания игр поддерживают Java-семейство. Это позволяет программерам и разрабам выбрать оптимальный для себя «пакет» готовых утилит при создания развлекательного контента. Далее будут перечислены лучшие движки JavaScript и библиотеки.
GDevelop
Универсальная утилита – подходит и новичкам, и продвинутым программистам. С ее помощью можно сделать:
- платформеры;
- шутеры;
- элементарные игры 8-bit.
Создана для того, чтобы дать возможность разработчикам (особенно новичкам) освоить работу с 2d-играми. Трехмерную графику не поддерживает.
GDevelop предлагает экспорт на различные платформы: Android, iOS, FaceBook (ныне Meta) Instant Games и не только. Подойдет тем, кто заинтересован в экспортировании игр, но не хочет углубляться в непосредственную разработку софта и долго изучать низкоуровневую архитектуру игровых движков.
MelonJS
Еще один вариант, если хотите научиться делать собственные 2D-игры. Подключив соответствующую библиотеку к коду, можно получить доступ к качественной поддержке:
- физики;
- столкновений;
- спрайтов;
- деформаций.
В успешных проектах все это играет огромную роль. Из минусов – не самая лучшая документация. Зато пользовательского контента у MelonJS полно. А еще имеется отличное комьюнити.
Идеальный вариант для новичков. Является весьма мощным инструментом в умелых руках. Но продвинутым программерам предлагаемых возможностей будет маловато.
ImpactJS
Имеет ориентацию преимущественно на двухмерную графику. В отличие от предыдущих вариантов обладает плагинами, которые при добавлении в Impact позволяют имитировать 3D-среду.
Дополнительно к Impact «идут» следующие инструменты:
- редактор уровней;
- дебаггер;
- фреймворк для публикации в Ejecta.
Через Impact удается без проблем размещать утилиты в AppStore.
Babylon
Мощный инструмент, предусматривающий веб-рендеринг. Игровым движком его назвать нельзя, но на основе BabylonJS удастся создать game. Движок рендеринга предусматривает доступ к низкоуровневому функционалу.
Babylon – утилита, которая подойдет продвинутым программистам. Новичкам с ней работать затруднительно, особенно если учесть, что это – не совсем игровой движок.
PhaserJS
Среди популярных вариантов, поддерживающих Java, выделяют PhaserJS. Он позволяет программировать не только для компьютеров, но и для мобильных устройств. Обладает поддержкой WebGL. Годится для написания 2D-софта.
Это – бесплатный движок. За дополнительную плату можно подключить особые плагины, значительно увеличивающие мощь «пакета».
Pixi
Библиотека, задействованная при программировании в двухмерном пространстве. Работает с WebGL, задействуется для воплощения потрясающих интерфейсов. И не обязательно они будут размещаться в играх.
Включает в себя:
Идеальный вариант для тех, кого больше беспокоит визуализация. Для сложных и весьма крупных проектов лучше воспользоваться каким-нибудь другим вариантом.
PlayCanvas
Среда программирования для развлекательных приложений, включающая в себя все необходимое разработчику. Здесь удается не только писать коды, но и проводить тестирование, настройку сцен, экспорт контента в одно нажатие.
PlayCanvas – условно-бесплатный «набор программиста». Годится для небольших публичных проектов. За «тайные» коммерческие идеи предстоит платить ежемесячно.
A-Frame
Инновационное решение в программировании. A-Frame может предоставить пользователям больше возможностей, нежели предыдущие библиотеки. И все это за счет того, что ориентирован движок на VR и AR.
Синтаксис напоминает HTML-верстку. Подойдет для 3d-программирования с «полным погружением». В основном утилитой пользуются опытные программеры.
PhysicsJS
Основан на физическом взаимодействии имеющихся объектов. Используется при разработке всех видов игрушек. Для Андроид в том числе.
Отличное решение для тех, кому важна сложная физика в реализуемом софте. То же самое касается применения при создании собственных движков на основе уже имеющихся библиотек.
Универсальные решения для программистов
Перечислять программы, при помощи которых можно создавать любые игрушки для мобильных и компьютерных устройств, удается бесконечно долго. Но в мире сложилась тенденция, согласно которой несколько вариантов вышли на передовую. Они используются программистами на разных языках чаще остальных. К концу статьи каждый потенциальный разработчик сможет выбрать платформу, с которой он будет работать, зная Java.
Unreal Engine 4
Настоящая легенда в сфере gaming programming. Разрабатывался «пакет» с 1998 года. С тех пор все время совершенствуется и дорабатывается. Современная версия UE 4 является универсальной. При помощи нее создаются развлекательные приложения для:
- игровых консолей;
- мобильных платформ;
- компьютеров.
Является частично бесплатным. Платить за использование оного не нужно, если прибыль с созданного приложения в месяц не переваливает за 3 000 долларов США. В противном случае предстоит переводить создателям движка проценты с получаемых доходов.
Unity
Юнити – популярный вариант среди разработчиков. Обошел иные платформы для создания игр, благодаря простоте осваивания. Развивается с 2005 года.
Подойдет для 3D-игрушек. Как и предыдущий вариант, является кроссплатформенным. На Юнити пишут не только простые игры (головоломки, аркады), но и шутеры от первого лица с тщательно проработанным игровым миром.
Недостаток один – графика в созданных утилитах далека от 100% реалистичности. Если разработчику важна графическая составляющая, лучше пользоваться UE 4. Несмотря на это, более половины утилит для Android написаны именно на Unity. Подходит как новичкам, так и продвинутым программистам.
Corona
Программы для создания игрушек можно перечислять бесконечно долго. И выбрать что-то одно бывает непросто. Добавить к списку наиболее успешных и популярных «пакетов» можно утилиту под названием Corona SDK.
Он выступает в качестве платформы для двухмерных игр. Предусматривает:
- поддержку API;
- сложные функции в 2D-играх;
- в основе API используется Luna;
- монетизацию через Corona Ads.
Данный вариант является кроссплатформенным. Подходит и для Андроид, и для iOS. Осваивается без существенных затруднений, поэтому идеальна для новичков. Имеется тестирование в режиме реального времени.
Обладает разнообразными полезными фитчами:
- Sublime Text;
- Corona Editor;
- Composer GUI.
Через Corona’s Physycs Engine можно отслеживать взаимодействие игровых объектов между собой. Этот прием позволяет довести физику в развлекательном софте до идеального состояния с минимальными временными потерями.
Как создать собственную игру – советы
Для того, чтобы писать программы и игровой контент на Java, рекомендуется изучить основы программирования. Существуют следующие варианты развития событий:
- Самообразование. Результат виден лишь у целеустремленных будущих программистов. В интернете полно полезной информации по рассмотренной тематике. И не всегда за нее нужно платить.
- Обучение в ВУЗе. Подойдет направление «Программирование». В некоторых университетах есть вариант «геймдев». Долгий и дорогостоящий вариант, но в результате на руках окажется диплом. Выпускник сможет писать сложные программы.
- Прохождение курсов.
Последний вариант больше всего подходит тем, кто не готов сидеть 5 и более лет в университете. Специализированные образовательные центры предлагают как очные/заочные курсы, так и дистанционные.
Преимуществом такого подхода является то, что человек может выбрать узкую направленность. Пример – изучение только процесса создания игр на Android или iOS. В конце обучения (длится до года) выдается сертификат установленного образца. При желании можно изучать движки для игр iOS, Windows, Android более подробно. Для самых популярных «утилит» существуют отдельные курсы. Делятся они по уровню навыков. Подходящие уроки подберет себе и новичок, и продвинутый программер.