Cada año hay muchos artículos dedicados al Día de San Valentín. También decidí involucrarme en este tema y crear algo original e inusual. La idea era crear una aplicación de Android simple con corazones que tendrían sus modelos físicos e interactuarían entre sí. Luego agregué texto, sonidos, partículas y algunos otros efectos. ¡La aplicación resultante funcionaba y era bastante original! En este artículo describiré el proceso de creación, así como las capacidades y las dificultades de la biblioteca libgdx .
.
Contenido
Para implementar esta idea, utilicé los siguientes programas y bibliotecas:
- IntelliJ IDEA : un IDE para aplicaciones multiplataforma. Alternativamente, puede usar Android Studio , Eclipse .
- libgdx : una biblioteca Java multiplataforma (PC, Mac, Linux, Android) para desarrollar juegos y otras aplicaciones gráficas. Esta biblioteca se distribuye bajo la licencia Apache 2.0. Algunos fragmentos de código se optimizaron utilizando JNI (por ejemplo, Box2d).
- box2d-editor : un editor para crear modelos físicos utilizados en el motor físico
box2d
, que está integrado en libgdx
. Aquí se usará para hacer coincidir la imagen del corazón con su modelo físico. - Generador de fuentes de mapa de bits Hiero : un programa para convertir fuentes vectoriales en ráster (ya que en
libgdx
solo se admiten fuentes ráster). - Particle Editor : un editor para crear sistemas de partículas, desarrollado por el creador de
libgdx
. Se utiliza para partículas en el efecto de "explosión" durante la destrucción del corazón. - Paint.NET : un editor de imágenes, se utilizó para editar la imagen del corazón y crear el fondo.
Todos estos programas y componentes se distribuyen libremente, y esta es una gran ventaja. libgdx
porque, en primer lugar, ya tengo algo de experiencia con él y, en segundo lugar, usando libgdx
no es necesario en un emulador lento de Android, ya que es multiplataforma y permite probar aplicaciones en un entorno nativo de Java y luego compilar ellos para Android.
Hola mundo
Primero, le diré en pocas palabras cómo crear proyectos libgdx. Usando gdx-setup.jar
, genere una plantilla de proyecto (basada en Gradle), que especifica las plataformas de destino. Actualmente, Desktop
, Android
, Ios
, Html
son compatibles. Para ser honesto, no pude probar los dos últimos, ya que no tengo un dispositivo iOS y hay algunas dificultades con HTML que aún no he resuelto.

También puede seleccionar las extensiones que usará. En nuestro caso, esta es la biblioteca de física Box2d.
Sin embargo, todo esto se describe en la wiki: Creación de un proyecto libgdx .
Después de la generación, se crean tres carpetas:
En los dos últimos, se colocan DesktopLauncher
y AndroidLauncher
respectivamente, que se ven así:
public class DesktopLauncher { public static void main (String[] arg) { LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); config.width = 800; config.height = 480; new LwjglApplication(new ValentinesDayHeartsApp(), config); } }
public class AndroidLauncher extends AndroidApplication { @Override protected void onCreate (Bundle savedInstanceState) { super.onCreate(savedInstanceState); AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(); initialize(new ValentinesDayHeartsApp(), config); } }
No habrá más código específicamente para la plataforma Android, que es una gran ventaja de la biblioteca elegida. Solo queda permitir la vibración y deshabilitar el modo de suspensión (para evitar que se restablezca el estado de la aplicación) en la configuración de AndroidManifest.xml
. Y también establezca la orientación horizontal para que el mundo no se ponga patas arriba:
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.WAKE_LOCK"/>
y
android:screenOrientation="landscape"
El código común se almacena en la carpeta core
. La clase principal llamada ValentinesDayHeartsApp
implementa la interfaz ApplicationListener
(para manejar eventos de inicialización, renderización, finalización y otros estados) y la interfaz InputProcessor
(para manejar la entrada del usuario).
Eso es todo, ¡el esqueleto está listo! Ahora nuestra aplicación se ejecutará tanto en PC como en Android.
General
El proyecto tiene una estructura simple: en la clase ValentinesDayHeatsApp
, se touchDown
métodos create
, render
, dispose
, touchDown
. El método create
inicializa todos los recursos (texturas, fuentes, partículas, sonidos) y crea el mundo físico. En el método de representación, se produce la representación de todos los objetos del mundo:
@Override public void render() { updatePhysics(); updateBackground(); updateSprites(); updateParticles(); refresh(); renderBackground(); renderHearts(); renderFonts(); renderParticles(); }
En el método dispose
, se liberan todos los recursos. Sí, sí, a pesar del hecho de que Java tiene recolección de basura automática, los recursos no administrados (objetos Box2d y algunos otros) aún deben liberarse manualmente. El método touchDown
se activa con un toque o un clic del mouse. Funciona así: si un punto de contacto se cruza con un corazón, el corazón se elimina. De lo contrario, se crea un nuevo corazón en el punto de contacto. El objeto Heart
tiene las siguientes propiedades:
Body
: un modelo físico.Sprite
: un modelo gráfico (sprite).String
: un texto que se muestra en el corazón.Font
: una fuente.ParticleEffect
partículas: partículas creadas al destruir el corazón.BreakSound
: un sonido de destrucción del corazón.
A continuación, describiré los componentes de la aplicación con más detalle.
Texturas
En primer lugar, necesitaba encontrar o dibujar el corazón. Afortunadamente, lo busqué en Google fácilmente y luego lo edité un poco: agregué un brillo y un fondo transparente. Para cargar texturas en libgdx
, utilicé la clase Texture
. Como la misma textura se puede usar varias veces, se usaron objetos Sprite
adicionales. Fueron dibujados usando el método de render
. La posición del sprite y el ángulo son los parámetros de representación y el modelo físico del corazón. Para variar, decidí dibujar los corazones en diferentes tonos. Utilicé la paleta HSL, que permite manipular el tono, la saturación y el aclarado, no componentes de color como RGB. La fórmula para la conversión RGB -> HSL y HSL -> RGB se puede encontrar fácilmente, y utilicé los métodos del artículo Manipulación de colores en .NET en Java. Todas las conversiones están en los prepareHeartsTextures
, prepareHslData
y generateHeartTexture
. Aquí está el ejemplo:
Pixmap pixmap = new Pixmap(fileHandle); float[][][] result = new float[pixmap.getWidth()][pixmap.getHeight()][4]; for (int i = 0; i < pixmap.getWidth(); i++) for (int j = 0; j < pixmap.getHeight(); j++) { int color = pixmap.getPixel(i, j); float r = (float)((color >> 24) & 0xFF) / 255.0f; float g = (float)((color >> 16) & 0xFF) / 255.0f; float b = (float)((color >> 8) & 0xFF) / 255.0f; float a = (float)(color & 0xFF) / 255.0f; result[i][j] = ColorUtils.RgbToHsl(r, g, b, a); } return result;
Desafortunadamente, la aplicación de Android comienza con algún retraso debido a la generación de texturas con diferentes tonos.
Fuentes
Como libgdx
solo puede funcionar con fuentes ráster, utilicé Hiero Bitmap Font Generator (versión 5), que crea imágenes de todos los caracteres en formato PNG, y el archivo FNT, que contiene información sobre las coordenadas de cada carácter en la imagen. Aquí está la captura de pantalla de este programa:

Después de que se generan los archivos necesarios, la fuente se puede usar en la aplicación libgdx de la siguiente manera:
font = new BitmapFont( Gdx.files.internal("data/Jura-Medium.fnt"), Gdx.files.internal("data/Jura-Medium.png"), false); font.setColor(Color.WHITE);
Y luego renderizarlo así:
font.draw(spriteBatch, heart.String, screenPosition.x, screenPosition.y);
Al renderizar, encontré algunas dificultades: por ejemplo, la fuente no se puede representar en ángulo, ya que se puede hacer con un sprite. Para resolver este problema, debe cambiar la matriz de proyección de SpriteBatch
y luego representar la fuente de la siguiente manera:
Matrix4 projection = spriteBatch.getProjectionMatrix(); projection.setToOrtho2D(0, 0, WorldWidth, WorldHeight); projection.translate(tmpVector1.x, tmpVector1.y, 0); projection.rotate(0, 0, 1, body.getAngle() / (float)Math.PI * 180); projection.translate(-tmpVector1.x, -tmpVector1.y, 0); Vector2 stringSize = heart.getStringSize(); tmpVector1.add(heart.Size.x / PhysWorldWidth * WorldWidth * CenterDisplacement.x - stringSize.x * 0.5f, heart.Size.y / PhysWorldHeight * WorldHeight * CenterDisplacement.y + stringSize.y); spriteBatch.begin(); BitmapFont.BitmapFontData fontData = font.getData(); fontData.setScale(heart.Size.x * FontSizeHeartSizeCoef.x, heart.Size.y * FontSizeHeartSizeCoef.y); font.draw(spriteBatch, heart.String, tmpVector1.x, tmpVector1.y); fontData.setScale(1, 1); spriteBatch.end();
Física
Como motor de física, se utilizó box2d .
Para hacer coincidir la imagen del corazón con su modelo físico, utilicé box2d-editor :
.
Usando este programa, creé un polígono del corazón, que se dividió automáticamente en polígonos convexos. El modelo físico es un conjunto de coordenadas de estos polígonos en formato JSON.
Además, este archivo se usa en nuestra aplicación (la carga se realiza en el método addHeart
). libgdx solo puede cargar archivos en formato binario. Afortunadamente, se encontró la clase BodyEditorLoader.java , que también se puede utilizar para cargar el modelo desde JSON (es decir, representación textual).
No olvide establecer la densidad, fricción y elasticidad del cuerpo:
FixtureDef fdef = new FixtureDef(); fdef.density = 0.75f; fdef.friction = 1.0f; fdef.restitution = 0.4f; bodyLoader.attachFixture(body, "Heart", fdef, newWidth); body.resetMassData();
¡Ahora nuestros corazones tienen un caparazón físico!
Para que los corazones no salgan volando de la pantalla, podemos agregar cuatro rectángulos estáticos a los lados de nuestro pequeño mundo. En dispositivos móviles, es recomendable establecer la gravedad en función de la orientación del dispositivo:
if (Gdx.app.getType() == ApplicationType.Android) { gravity.x = -Gdx.input.getPitch() / 90.0f; gravity.y = Gdx.input.getRoll() / 90.0f; gravity.mul(gravityCoef); world.setGravity(gravity); }
Sistema de partículas
En libgdx
, el sistema de partículas se especifica utilizando archivos especiales que se pueden generar en el editor:
.
Como puede ver, este editor tiene una gran cantidad de configuraciones: puede cargar diferentes texturas, cambiar la vida útil, la forma de propagación, la transparencia y otros parámetros. Hice partículas en forma de corazón, que aparecerán cuando toques la pantalla y destruyas un gran corazón físico. En la aplicación, el trabajo con partículas ocurre de la siguiente manera:
Inicialización
ParticleEffect effect = new ParticleEffect(); effect.load(Gdx.files.internal("data/destroy.p"), Gdx.files.internal("data"));
Comienzo del ciclo de vida.
Es importante no olvidarse del start
sin el cual las partículas no se mostrarán:
effect.setPosition(.., ..); effect.start();
Suena
Los sonidos se cargan de la siguiente manera:
sound = Gdx.audio.newSound(Gdx.files.internal("path/to/file"));
Y luego se juegan así:
sound.play(1);
¿Qué podría ser más fácil? Sin embargo, también hay dificultades. Por alguna razón, los archivos solo se pueden cargar en formato OGG y con una velocidad de bits de 96 kbit / s .
Conclusión
Espero que las técnicas descritas en este artículo sean útiles para muchos de ustedes para desarrollar juegos usando libgdx
. Puede usar el código fuente y los recursos. Enviar aplicaciones para el Día de San Valentín a sus novios :)
Vale la pena señalar que el texto que se muestra en los corazones se puede cambiar en el archivo data/words.txt
. Funciona incluso sin recompilación.
Código fuente y ejecutables