Стандартные библиотеки Java

jMonkey Engine . Отличная производительность, кроссплатформенность, свой SDK+редакторы, дружелюбное сообщество (вот только англоязычное). Частые обновления и отличная поддержка со стороны разрабов самого движка не может не радовать. Есть модификация версии от 2009 года, её авторы гордо именуют свой мод отдельным движком - Ardor3D (но вот только проект загнулся, какая досада). Даже официальный сайт модификации уже не работает, а перенаравляет на личный блог разработчиков. "Под капотом" стоит LWJGL (Light-Weight JavaGL), поддержка OpenGL v2+ и шейдеров. Плюшки - поддержка всякой лабуды типа Oculus Rift; возможна разработка Android-приложений.

Мой вывод: если готовы приступить к более-чем-любительской разработке серьёзных проектов, то jME - ваш выбор.

Bonzai Engine . Великолепные утилиты для разработки, но нет как и документации, так и сообщества. Немного отойду от темы и проведу небольшое сравнение сообществ движков jME и Bonzai Engine: в одном только Твиттере у jMonkey Engine 1725 подписчиков, а у Bonzai Engine всего 12. Продолжу: кроссплатформенность (Windows/Linux/Android), OpenGL v2+. Плюшки: редакторы есть даже на Android. Также движок обещает поддержку большого количества форматов моделей.

Апдейт : документация внезапно появилась (просто я полтора года назад изучал этот движок, но документации не было вообще). Достойных (да и просто) проектов на этом движке я пока не встречал.

Мой вывод: обёртка классная, а начинка оставляет желать лучшего.

Приложения на Bonzai Engine: ???

jPCT . Врядли библиотеку размером в 300 кб можно назвать движком, но всё же это лёгкий инструмент для создания простейших приложений. Есть неофициальный редактор, куча подробной документации и довольно большое дружелюбное(!) сообщество (был случай, что на форуме мне помогал сам создатель движка). Также есть поддержка Android (версия jPCT-AE). За "плечами" движка имеется куча приложений, созданных пользователями (лично я сам залипаю в одну игрушку). Прошу учесть, что такой "движок" не даст такую великолепную картинку, как, например, jME и Bonzai Engine, но тут FPS держится выше и стабильнее. Плюшки: поддержка скелетной анимации.

Мой вывод: "дёшево и сердито".

2D Движки

Slick2D . Хороший производительный движок с открытым исходным кодом (лицензия BSD). Кроссплатформенность (Windows/Linux/Mac), поддержка OpenGL v2+. Плюшки: модуль физики jBox2D; легко делается GUI.

  • Жанровая направленность: 2D/3D игры любого жанра;
  • Платформа: Windows, Linux, Mac, Solaris, Windows CE, FreeBSD, Android и т.д;
  • Лицензия: бесплатная;
  • Языки программирования: Java;
  • Открытый исходный код: предоставляется;
  • Мультиплеер: возможен;
  • Достоинства: кроссплатформенный, оптимизированный, бесплатный, открытый и свободный;
  • Недостатки: не передовые по нынешним меркам графические возможности;
  • Разработчики движка: Helge Foerster.

    jPCT - это свободный 3D-движок для Java, который позволяет использовать OpenGL и Software рендеры на выбор. Данный движок подходит для разработки мощных 3D-приложений для десктопа, Интернета и Android. А небольшие игры на нём пишутся весьма просто и удобно. Движок разрабатывается с 2002 года.

    Для разработки под мобильные устройства на базе операционной системы Android имеется специальный билд движка - PCT-AE (Android Edition). Данный вариант сборки движка заточен под Android, имеет всё те же элементы за исключением некоторых особенностей, которые были устранены или упрощены из-за специфики платформы.

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

    Как уже было упомянуто, jPCT поддерживает работу с Software рендером и с OpenGL, что позволяет создавать приложения на разные платформы. Используются аппаратное ускорение, различные режимы экрана и разрешения. Можно использовать Swing/AWT как AWTGLRenderer.

    У движка имеются уже готовые классы для обработки пользовательского ввода. Например, для ввода с клавиатуры используется класс KeyMapper. Вы просто создаете новый объект KeyMapper а потом можете в любое время получить состояние клавиш с помощью вызова poll(). Также jPCT предоставляет классы Object3D, Сamera, World, поддерживает несколько форматов 3D-моделей, удобный их импорт и т.д.

    Получаемые игры можно распространять под нужные вам платформы, например, для отображения в окне браузера можно использовать java-апплет через Java Webstart. Также с минимальными изменениями кода игр их можно портировать под мобильную систему Android. На jPCT разрабатываются игры любой сложности и любого типа. Например, разрабатывается MMORPG "Technopolies", произведён порт "Quake3". Игра работают через LWJGL или JOGL на Windows, MacOS X, Linux (x86) и Solaris. Запускаются и функционируют на Windows CE, FreeBSD, MacOS 9 и на многих других платформах, поддерживающих Java.

    Вместе с движком поставляются необходимые дополнительные материалы: документация и необходимые нативные библиотеки. Получаемые приложения совместимы с Java 1.1 и с прочими старыми виртуальными машинами, типа Microsoft VM и Netscape 4 VM.

    Официальный сайт: http://www.jpct.net




    JPCT is a powerful solution for bringing 3D into the Java world. You want to write a fullscreen game that makes use of hardware acceleration? No problem, jPCT can render into a native (optionally fullscreen) OpenGL window. You may even distribute your game as an OpenGL powered desktop application via Java Webstart and offer an applet version in addition.

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

    Многие разработчики ошибочно полагают, что создание даже простейшего 3D-приложения с нуля требует нечеловеческих знаний и усилий. К счастью, это не совсем так. Более того, при наличии компьютера и свободного времени, можно создать нечто подобное самостоятельно. Давайте взглянем на процесс разработки нашего собственного движка для 3D-рендеринга.

    Итак, для чего же это всё нужно? Во-первых, создание движка для 3D-рендеринга поможет понять, как же работают современные движки изнутри. Во-вторых, сам движок при желании можно использовать и в своём собственном приложении, не прибегая к вызову внешних зависимостей. В случае с Java это значит, что вы можете создать своё собственное приложение для просмотра 3D-изображений без зависимостей (далёких от API Java), которое будет работать практически везде и уместится в 50 КБ!

    Само собой, если вы хотите создать какое-нибудь большое 3D-приложение с плавной анимацией, вам лучше использовать OpenGL/WebGL. Однако, имея базовое представление о том, как устроены подобные движки, работа с более сложными движками будет казаться в разы проще.

    В этой статье я постараюсь объяснить базовый 3D-рендеринг с ортографической проекцией, простую треугольную растеризацию (процесс, обратный векторизации), Z-буферизацию и плоское затенение. Я не буду заострять своё внимание на таких вещах, как оптимизация, текстуры и разные настройки освещения - если вам это нужно, попробуйте использовать более подходящие для этого инструменты, вроде OpenGL (существует множество библиотек, позволяющих вам работать с OpenGL, даже используя Java).

    Примеры кода будут на Java, но сами идеи могут, разумеется, быть применены для любого другого языка по вашему выбору.

    Довольно болтать - давайте приступим к делу!

    GUI

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

    Import javax.swing.*; import java.awt.*; public class DemoViewer { public static void main(String args) { JFrame frame = new JFrame(); Container pane = frame.getContentPane(); pane.setLayout(new BorderLayout()); // slider to control horizontal rotation JSlider headingSlider = new JSlider(0, 360, 180); pane.add(headingSlider, BorderLayout.SOUTH); // slider to control vertical rotation JSlider pitchSlider = new JSlider(SwingConstants.VERTICAL, -90, 90, 0); pane.add(pitchSlider, BorderLayout.EAST); // panel to display render results JPanel renderPanel = new JPanel() { public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setColor(Color.BLACK); g2.fillRect(0, 0, getWidth(), getHeight()); // rendering magic will happen here } }; pane.add(renderPanel, BorderLayout.CENTER); frame.setSize(400, 400); frame.setVisible(true); } }

    Результат должен выглядеть вот так:

    Теперь давайте добавим некоторые модели - вершины и треугольники. Вершина - это просто структура для хранения наших трёх координат (X, Y и Z), а треугольник соединяет вместе три вершины и содержит их цвет.

    Class Vertex { double x; double y; double z; Vertex(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } } class Triangle { Vertex v1; Vertex v2; Vertex v3; Color color; Triangle(Vertex v1, Vertex v2, Vertex v3, Color color) { this.v1 = v1; this.v2 = v2; this.v3 = v3; this.color = color; } }

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

    Код также будет достаточно простым - мы просто создаём 4 треугольника и добавляем их в ArrayList:

    List tris = new ArrayList<>(); tris.add(new Triangle(new Vertex(100, 100, 100), new Vertex(-100, -100, 100), new Vertex(-100, 100, -100), Color.WHITE)); tris.add(new Triangle(new Vertex(100, 100, 100), new Vertex(-100, -100, 100), new Vertex(100, -100, -100), Color.RED)); tris.add(new Triangle(new Vertex(-100, 100, -100), new Vertex(100, -100, -100), new Vertex(100, 100, 100), Color.GREEN)); tris.add(new Triangle(new Vertex(-100, 100, -100), new Vertex(100, -100, -100), new Vertex(-100, -100, 100), Color.BLUE));

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

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

    G2.translate(getWidth() / 2, getHeight() / 2); g2.setColor(Color.WHITE); for (Triangle t: tris) { Path2D path = new Path2D.Double(); path.moveTo(t.v1.x, t.v1.y); path.lineTo(t.v2.x, t.v2.y); path.lineTo(t.v3.x, t.v3.y); path.closePath(); g2.draw(path); }

    Заметьте, что сейчас я совершил все преобразования до отрисовки треугольников. Это сделано, чтобы для того, что бы поместить наш центр (0, 0, 0) в центр экрана - по умолчанию начало координат находится в левом верхнем углу экрана. После компиляции вы должны получить:

    Вы можете не поверить, но это наш тетраэдр в ортогональной проекции, честно!

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

    Существует много путей манипулировать 3D-точками, но самый гибкий из них - это использование матричного умножения. Идея заключается в том, чтобы показать точки в виде вектора размера 3×1, а переход - это, собственно, домножение на матрицу размера 3×3.

    Возьмём наш входной вектор A:

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

    Например, вот как будет выглядеть трансформация, если мы умножим на 2:

    Вы не можете описать любую возможную трансформацию, используя матрицы размера 3×3 - например, если переход происходит за пределы пространства. Вы можете использовать матрицы размера 4×4, делая перекос в 4D-пространство, но об этом не в этой статье.

    Трансформации, которые нам пригодятся здесь - масштабирование и вращение.

    Любое вращение в 3D-пространстве может быть выражено в 3 примитивных вращениях: вращение в плоскости XY, вращение в плоскости YZ и вращение в плоскости XZ. Мы можем записать матрицы трансформации для каждого из данных вращений следующим путём:

    • Матрица вращения XY:
    • Матрица вращения YZ:
    • Матрица вращения XZ:

    И вот здесь начинается магия: если вам нужно сначала совершить вращение точки в плоскости XY, используя матрицу трансформации T1, и затем совершить вращение этой точки в плоскости YZ, используя матрицу трансформации T2, то вы можете просто умножить T1 на T2 и получить одну матрицу, которая опишет всё вращение:

    Это очень полезная оптимизация - вместо того, чтобы постоянно считать вращения на каждой точке, мы заранее считаем одну матрицу и затем используем её.

    Что ж, довольно страшной математики, давайте вернёмся к коду. Создадим служебный класс Matrix3, который будет обрабатывать перемножения типа «матрица-матрица» и «вектор-матрица»:

    Class Matrix3 { double values; Matrix3(double values) { this.values = values; } Matrix3 multiply(Matrix3 other) { double result = new double; for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { for (int i = 0; i < 3; i++) { result += this.values * other.values; } } } return new Matrix3(result); } Vertex transform(Vertex in) { return new Vertex(in.x * values + in.y * values + in.z * values, in.x * values + in.y * values + in.z * values, in.x * values + in.y * values + in.z * values); } }

    Теперь можно и оживить наши скроллеры вращения. Горизонтальный скроллер будет контролировать вращение влево-вправо (XZ), а вертикальный скроллер будет контролировать вращение вверх-вниз (YZ).

    Давайте создадим нашу матрицу вращения:

    Double heading = Math.toRadians(headingSlider.getValue()); Matrix3 transform = new Matrix3(new double {Math.cos(heading), 0, -Math.sin(heading), 0, 1, 0, Math.sin(heading), 0, Math.cos(heading)}); g2.translate(getWidth() / 2, getHeight() / 2); g2.setColor(Color.WHITE); for (Triangle t: tris) { Vertex v1 = transform.transform(t.v1); Vertex v2 = transform.transform(t.v2); Vertex v3 = transform.transform(t.v3); Path2D path = new Path2D.Double(); path.moveTo(v1.x, v1.y); path.lineTo(v2.x, v2.y); path.lineTo(v3.x, v3.y); path.closePath(); g2.draw(path); }

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

    HeadingSlider.addChangeListener(e -> renderPanel.repaint()); pitchSlider.addChangeListener(e -> renderPanel.repaint());

    Как вы, наверное, уже заметили, вращение вверх-вниз ещё не работает. Добавим эти строки в код:

    Matrix3 headingTransform = new Matrix3(new double {Math.cos(heading), 0, Math.sin(heading), 0, 1, 0, -Math.sin(heading), 0, Math.cos(heading)}); double pitch = Math.toRadians(pitchSlider.getValue()); Matrix3 pitchTransform = new Matrix3(new double {1, 0, 0, 0, Math.cos(pitch), Math.sin(pitch), 0, -Math.sin(pitch), Math.cos(pitch)}); Matrix3 transform = headingTransform.multiply(pitchTransform);

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

    Я буду использовать очень простой, но крайне неэффективный метод - растеризация через барицентрические координаты. Настоящие 3D-движки используют растеризацию, задействуя железо компьютера, что очень быстро и эффективно, но мы не можем использовать нашу видеокарту, так что будем делать всё вручную, через код.

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

    BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); for (Triangle t: tris) { Vertex v1 = transform.transform(t.v1); Vertex v2 = transform.transform(t.v2); Vertex v3 = transform.transform(t.v3); // since we are not using Graphics2D anymore, we have to do translation manually v1.x += getWidth() / 2; v1.y += getHeight() / 2; v2.x += getWidth() / 2; v2.y += getHeight() / 2; v3.x += getWidth() / 2; v3.y += getHeight() / 2; // compute rectangular bounds for triangle int minX = (int) Math.max(0, Math.ceil(Math.min(v1.x, Math.min(v2.x, v3.x)))); int maxX = (int) Math.min(img.getWidth() - 1, Math.floor(Math.max(v1.x, Math.max(v2.x, v3.x)))); int minY = (int) Math.max(0, Math.ceil(Math.min(v1.y, Math.min(v2.y, v3.y)))); int maxY = (int) Math.min(img.getHeight() - 1, Math.floor(Math.max(v1.y, Math.max(v2.y, v3.y)))); double triangleArea = (v1.y - v3.y) * (v2.x - v3.x) + (v2.y - v3.y) * (v3.x - v1.x); for (int y = minY; y <= maxY; y++) { for (int x = minX; x <= maxX; x++) { double b1 = ((y - v3.y) * (v2.x - v3.x) + (v2.y - v3.y) * (v3.x - x)) / triangleArea; double b2 = ((y - v1.y) * (v3.x - v1.x) + (v3.y - v1.y) * (v1.x - x)) / triangleArea; double b3 = ((y - v2.y) * (v1.x - v2.x) + (v1.y - v2.y) * (v2.x - x)) / triangleArea; if (b1 >= 0 && b1 <= 1 && b2 >= 0 && b2 <= 1 && b3 >= 0 && b3 <= 1) { img.setRGB(x, y, t.color.getRGB()); } } } } g2.drawImage(img, 0, 0, null);

    Довольно много кода, но теперь у нас есть цветной тетраэдр на экране.

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

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

    Double zBuffer = new double; // initialize array with extremely far away depths for (int q = 0; q < zBuffer.length; q++) { zBuffer[q] = Double.NEGATIVE_INFINITY; } for (Triangle t: tris) { // handle rasterization... // for each rasterized pixel: double depth = b1 * v1.z + b2 * v2.z + b3 * v3.z; int zIndex = y * img.getWidth() + x; if (zBuffer < depth) { img.setRGB(x, y, t.color.getRGB()); zBuffer = depth; } }

    Теперь видно, что у нашего тетраэдра есть одна белая сторона:

    Вот мы и получили работающий движок для 3D-рендеринга!

    Но и это ещё не конец. В реальном мире восприятие какого-либо цвета меняется в зависимости от положения источников света - если на поверхность падает лишь небольшое количество света, то она видится более темной.

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

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

    Для начала нам нужно посчитать вектор нормали для нашего треугольника. Если у нас есть треугольник ABC, мы можем посчитать его вектор нормали, рассчитав векторное произведение векторов AB и AC и поделив получившийся вектор на его длину.

    Векторное произведение - это бинарная операция на двух векторах, которые определены в 3D пространстве вот так:

    Вот так выглядит визуальное представление того, что делает наше векторное произведение:

    For (Triangle t: tris) { // transform vertices before calculating normal... Vertex norm = new Vertex(ab.y * ac.z - ab.z * ac.y, ab.z * ac.x - ab.x * ac.z, ab.x * ac.y - ab.y * ac.x); double normalLength = Math.sqrt(norm.x * norm.x + norm.y * norm.y + norm.z * norm.z); norm.x /= normalLength; norm.y /= normalLength; norm.z /= normalLength; }

    Теперь нам нужно посчитать косинус между нормалью треугольника и направлением света. Для упрощения будем считать, что наш источник света расположен прямо за камерой на каком-либо расстоянии (такая конфигурация называется «направленный свет») - таким образом, наш источник света будет находиться в точке (0, 0, 1).

    В коде это всё выглядит тривиально:

    Double angleCos = Math.abs(norm.z);

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

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

    Public static Color getShade(Color color, double shade) { int red = (int) (color.getRed() * shade); int green = (int) (color.getGreen() * shade); int blue = (int) (color.getBlue() * shade); return new Color(red, green, blue); }

    Код будет давать нам некоторые эффекты затенения, но спадать они будут куда быстрее, чем нам нужно. Так происходит, потому что в Java используется спектр цветов sRGB.

    Так что нам нужно конвертировать каждый цвет в линейный формат, применить затенение и затем конвертировать обратно. Реальный переход из sRGB к линейному RGB - довольно трудоёмкий процесс, так что я не буду выполнять полный перечень задач здесь. Вместо этого, я сделаю нечто приближенное к этому.

    Public static Color getShade(Color color, double shade) { double redLinear = Math.pow(color.getRed(), 2.4) * shade; double greenLinear = Math.pow(color.getGreen(), 2.4) * shade; double blueLinear = Math.pow(color.getBlue(), 2.4) * shade; int red = (int) Math.pow(redLinear, 1/2.4); int green = (int) Math.pow(greenLinear, 1/2.4); int blue = (int) Math.pow(blueLinear, 1/2.4); return new Color(red, green, blue); }

    И теперь мы видим, как наш тетраэдр оживляется. У нас есть работающий движок для 3D рендеринга с цветами, освещением, затенением, и заняло это около 200 строк кода - неплохо!

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

    Public static List inflate(List tris) { List result = new ArrayList<>(); for (Triangle t: tris) { Vertex m1 = new Vertex((t.v1.x + t.v2.x)/2, (t.v1.y + t.v2.y)/2, (t.v1.z + t.v2.z)/2); Vertex m2 = new Vertex((t.v2.x + t.v3.x)/2, (t.v2.y + t.v3.y)/2, (t.v2.z + t.v3.z)/2); Vertex m3 = new Vertex((t.v1.x + t.v3.x)/2, (t.v1.y + t.v3.y)/2, (t.v1.z + t.v3.z)/2); result.add(new Triangle(t.v1, m1, m3, t.color)); result.add(new Triangle(t.v2, m1, m2, t.color)); result.add(new Triangle(t.v3, m2, m3, t.color)); result.add(new Triangle(m1, m2, m3, t.color)); } for (Triangle t: result) { for (Vertex v: new Vertex { t.v1, t.v2, t.v3 }) { double l = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z) / Math.sqrt(30000); v.x /= l; v.y /= l; v.z /= l; } } return result; }

    Вот что должно у вас получиться:

    Я бы закончил эту статью, порекомендовав одну занимательную книгу: «Основы 3D-математики для графики и разработки игр» . В ней вы можете найти детальное объяснение процесса рендеринга и математики в этом процессе. Её стоит прочитать, если вам интересны движки для рендеринга.

    Вот скажите, где могут выполняются скрипты написанные на javascript: на сервере, на клиенте? На клиенте, говорите? Это устаревшая информация...

    С введением в Java версии 1.6 Scripting API стало очень просто и удобно писать extension поинты и динамические конфигурации для серверной логики.

    В этой статье я хочу коротко рассказать вам о ScriptEngine, ну и еще кое о чем.

    В частности хочу сделать следующее:

    • На небольшом примере показать, как просто использовать скриптовый движок, встроенный в Java
    • Провести небольшой бенчмаркинг и убедить всех, что скрипты - это не так уж и медленно
    • Неявно рассказать, что JavaScript - один из самых мощных (и недооцененных) языков программирования:)

    Работа со скриптовыми движками производится через интерфейс ScriptEngine. В JDK есть пока что только одна имплементация этого интерфейса - RhinoScriptEngine.

    Сразу небольшой пример кода:

    Public static void main(String args) throws ScriptException { ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); String helloWorld = (String) engine.eval(""Hello" + " World!""); System.out.println(helloWorld); }

    Мы создаем ScriptEngine через ScriptEngineManager для языка JavaScript. Далее мы выполняем скрипт, суть которого - сконкатенировать 2 строки.

    Как и во многих скриптовых языках, результатом вычисления некоторого куска кода является результат выполнения его последнего оператора. То есть результатом выполнения нашего кода будет строка - "Hello World !".

    В одном проекте перед нашей командой возникла задача - создать механизм для гибкой маршрутизации СМС сообщений в зависимости от разных свойств (дата создания, оператор, номер назначения и т.д.).

    Решено было попробовать движок, который встроен в JDK. Естественно, перед применением новой технологии необходимо проверить ее производительность. Ниже привожу код, который показывает, на что способен движок Rhino (код незначительно упрощен для улучшения понимания):

    Import javax.script.*; public class ScriptBenchmarks { static String script = "sms.serviceNumber == "777" && sms.mobileNumber.startsWith("8050")"; static Sms sms = new Sms(); static int loops = 10000; static void init () { sms.setMobileNumber("80500000000"); sms.setServiceNumber("777"); } // testInitAndEvalInsideLoop average: 1ms static void testInitAnEvalInsideLoop() throws ScriptException { long start = System.currentTimeMillis(); for (int i = 0; i

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

    Как вы видите, средняя скорость выполнения скрипта очень мала. Прекомпилированный скрипт не дает большого прироста производительности.

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

    На этом, пожалуй, и закончу свое повествование. Жду вопросов и замечаний. Всего вам хорошего.

    Решил посмотреть, а что собственно есть на эту тему - накопал страницу википедии - само-собой на аглицком языке. Итак начнем! Движки рассматриваются только бесплатные и открытые.

    Agar - написан на C и C++, есть связь с языком Ада, с другими - в разработке. Последнее обновление 30 октября 2008 года.
    - разработан Open Source сообществом на основе исходных кодов игры Marathon 2: Durandal, разработанной компанией Bungie Software в 1995 году. Поддержка основных операционных систем. Есть собственный язык Marathon Markup Language, поддержка Lua. Обновлялся последний раз 22 июля 2008 года.
    Allegro - библиотека для разработки игр. Написана на С/С++, кросплатформенная. Есть связь практически с большинством языков - Ada, C++, C#, D, LISP, Lua,Mercury, Pascal, Perl, Python, Scheme и др.
    Blender GE - ну думаю в представлении не нуждается.
    - движок на основе Doom
    Box2D - кросплатформенный игровой физический движок, написан Erin Catto на С++. Известен тем, что использовался при создании игры Crayon Physics Deluxe (пазлы). Взял премию в IGF (Independent Game Festival).
    CranLib - кросплатформенная объектно-ориентированная библиотека на C++. На форуме сайта видно движение - проект актуальный.
    Crystal Entity Layer - расширение движка Crystal Space
    Crystal Space - хорошая среда разработки. Работают совмество с разработчиками Blender.
    Cube - кросплатформенный движок одноименной игры для создания шутеров.
    DarkPlaces - сильно модифициоранный движок Quake с поддержкой современной графики.
    Delta3D - кросплатформенный, хорошо развивается, свежий релиз вышел совсем недавно.
    Doom - теперь уже открытый и бесплатный движок.
    DXFramework - движок по Win (использует DirectX) для скорее образовательных целей.
    EternityEngine - еще один модифицированный Doom движок.
    открытая реализация популярного движка Ultima IV.
    FIFE - дфижок для создания 2D изометрических игр.
    GZDoom - еще один модифицированный Doom.
    Genesis3D - 3D движок реального времени под Windows
    GenesisDevice - мощный движок, написанный на Object Pascal под Windows платформу.
    Horse3D - маленький и мощный движок.
    - кросплатформенный, написан на С++, поддерживает языки #NET,java, perl, ruby, basic, python, lua, и другие.
    jMonkeyEngine - Java - движок.
    - основанный на Java клиент-серверный движок для создания он-лайн игр типа шашки, шахматы и тд.
    KallistiOS - среда разработки для игровых консолей Dreamcast(tm), Gameboy Advance(tm), Playstation 2(tm), and x86-based компьютеров.
    Lightfeather - кросплатформенный, отличный движок!
    Nebula Device - 3D движок реального времени разработанный студией Radon Labs. Обновлялся в сентябре 2008. Расчитан на Windows, но есть порты на Mac и Linux.
    OGRE Engine - очень популярный обьектно-ориентированный графический движок. Также известен как OGRE3D. Написан на С++. Существует поддержка Windows, Linux и Mac OS.
    ORX - портативный легкий игровой 2D-ориентированный движок. Написан на С с архитектурой плагинов (на С++) - кросплатформенный.
    Panda3D - относительно легкий в использовании python-управляемый игровой движок созданный Carnegie Mellon University . Его использует Disney для производства своих игр.
    RealmForge - движок для.NET
    - движок для создания шутеров от первого лица (Windows).
    Sauerbraten модифицированный кросплатформенный Cube (aka Cube2) движок.
    SDL - библиотека SDL. В комментировании не нуждается.
    SFML простая и быстрая мультимедиа библиотека.
    Spring - мощный игровой движок реального времени.
    - хороший движок для создания 2D игр. В 2007 году разработчики перешли в проект Bos Wars
    Xilon II - непримечательный 2D движок под Visual Basic .NET

    На этом пока бесплатные и открытые движки заканчиваются, но и так видно, что инструментов для создания анимации - пруд пруди и маленькая тележка!

    В следующий раз рассмотрим просто бесплатные движки.

    Обзор бесплатных open-source игровых движков. дата: 08:12 Оценка: 5

    Статьи по теме: