Programación de videojuegos con libGDX



Comments



Description

Programación de videojuegos conIntroducción a libGDX Descargar la librería Crear un proyecto JAVA nuevo Portar el proyecto JAVA a un proyecto Android Ciclo de vida de una aplicación libGDX Gráficos Texturas e Interpolación TextureRegion TextuimagrePacker Empaquetar imágenes automaticamente Carga de imágenes empaquetadas Dibujar imágenes en pantalla Entrada Detectar pulsaciones en la pantalla táctil Audio Sounds Cargar sonidos Reproducir sonidos Descargar sonidos Music Cargar una música Descargar una música Navegando entre pantallas del juego Vibración Cámaras Animación Manual de buenas prácticas Separar la lógica de la presentación Páginas para Desarrollo de Juegos Solución de problemas OBJETIVO Este documento pretende ser una guía de uso del Framework LibGDX para el desarrollo de videojuegos multiplataforma. Para la redacción del mismo se va a recopilar la información de diversas fuentes como puede ser la propia documentación de la API del framework, foros, blogs y videoblogs. La idea es tener una documentación básica en castellano que esté viva, es decir, que se vaya actualizando con el paso del tiempo e incluyendo las nuevas funcionalidades de las nuevas versiones. pueden llegar a ser complicadas o largas y tediosas. existe bastante documentación. LibGDX permite generar una aplicación en su PC y utilizar el mismo código en Android. he decidido dar el paso por libGDX por varias razones: la comunidad es bastante activa. hace uso de herramientas contrastadas en el desarrollo de videojuegos como OpenGL. etc. libGDX. sonidos. utilizando las herramientas usuales de cada plataforma. hay una versión gratuita que se puede usar para proyectos comerciales con una intro mostrando el logo de Gideros). Box-2D. LibGDX es un framework multiplataforma de desarrollo de juegos para Windows. Linux y Android.. de esta manera el proceso de pruebas y depuración se realiza de forma más rápida y cómoda ya que el PC es mucho más rápido que el dispositivo Android. Entre estos Frameworks.. Componente de Audio (audio): nos facilitará el acceso a los sonidos y música de la aplicación. Componente de entrada (input): para leer y escribir los diferentes ficheros de datos como por ejemplo. pausa y resume de la misma.. Unity 3D.destrucción..INTRODUCCIÓN En el mundo del desarrollo de aplicaciones actualmente existen multitud de Frameworks que ayudan al desarrollador a realizar sus proyectos minimizando el tiempo de desarrollo y simplificando tareas que. Cocos 2D-X. siguen la filosofía del software libre y pueden ser usados para el desarrollo de software tanto comercial como privado sin el pago de licencia alguna como pueden ser Moai. texturas. Está escrito en Java con una mezcla de C/C++ para dar soporte y rendimiento a tareas relacionadas con el uso de la física y procesamiento de audio. En mi caso. Componente de Entrada/Salida (Files): gestionara la entrada a través del teclado. tenemos algunos que son propietarios en el que es preciso pagar una licencia para la creación de proyectos comerciales como pueden ser Corona SDK.. Como se puede observar hay una gran cantidad de opciones donde elegir. imágenes. pantalla tácil o acelerómetro. Componente de Gráficos (graphics): nos permitirá gestionar la representación de imágenes y objetos gráficos en la pantalla. ● ● ● ● . usa Java como lenguaje de programación que es el único que medio-domino. Otros.. Open AL. Gideros (aunque en este caso.. es decir. música.. etc. los eventos de creación.. Con LibGDX nos aseguramos de que la misma aplicación puede funcionar correctamente en diferentes dispositivos. LibGDX está compuesto por una serie de componentes que serán comunes a todas las aplicaciones: ● Marco de Aplicación (application): manejará el bucle principal y además estará encargado del clico de vida. archivos de configuración. por el contrario. newAudioDevice(44100. .Los módulos descritos anteriormente pueden ser accedidos vía campos estáticos de la clase Gdx. Physics: que básicamente es un wrapper de Box2D y permite controlar la gestión de colisiones.audio. Adicionalmente podríamos ampliar la gama de módulos con otros dos más. para acceder al módulo de audio. en esencia son un juego de variables globales que permiten el fácil acceso a cualquier módulo de libgdx. simplemente hay que escribir lo siguiente: // Crea un objeto de tipo AudioDevice en el que poder cargar fragmenos de audio de tipo PCM de 16 bits AudioDevice audioDevice = Gdx. Esto. false). Por ejemplo. ● ● Math: permite la gestión rápida de cálculos matemáticos orientados al desarrollo de videojuegos. estos módulos son sólo interfaces públicas que ofrece la librería. Desventaja: ● El soporte de alto nivel en 3d esta en construcción actualmente . Ventajas: ● Soporte 2d full (bajo y alto nivel) ● Mucha documentación. La propia aplicación será la encargada de la gestión de los diferentes módulos. eventos de entrada del usuario (Input).matemática. ● libGDX te da un acceso más fácil a Bajo nivel ● Posibilidad de tomar un juego hecho en java jar 2d o 3d y adaptarlo a libgdx para q funcione nativo en android. física.archivos ● Soporta 3d aunque no es su fuerte. tutoriales.eso hicieron con el juego Droid Invaders 3d.Este gráfico muestra en mayor detalle el sistema de módulos de LibGDX Realmente. ejemplos de código ● Releases en forma periódica ● Se puede probar en escritorio (antes de subir a dispositivo móvil) ● Maneja Audio. Links de referencia: ● Pagina Oficial ● Wiki del proyecto ● Blog ● Foro ● Juego en 3d ya realizado: Droid Invaders ● Listado de Ejemplos ● Video Tutoriales ● Video Tutoriales en castellano ● Documentación . Método 1: Manualmente Descargar la librería Para descargar la librería debemos ir a la web de la misma: http://libgdx.com/ .Uso de la librería Existen dos métodos para el uso de la librería: el primero. que consiste en descargar la misma e importarla en nuestro proyecto de forma manual y el segundo método que es el más rápido y el que yo recomiendo que es usando un GUI creado en Java que crea un proyecto con todo lo necesario de forma automática para únicamente importarlo desde Eclipse.badlogicgames. más manual. InteliJ IDEA.. Elegimos la ruta donde se creará en memoria y le damos a Finish. ). por lo tanto es el IDE que se usará en este manual. A continuación seleccionamos la distribución Nightly Builds que es la última versión que contiene las últimas actualizaciones (y algunos bugs. Para crear un proyecto JAVA en Eclipse simplemente en el menú vamos a File > New > Java Project.Una vez en la web. . por lo tanto simplemente hay que ejecutarlo haciendo doble click en el fichero . hay que descomprimir el fichero y nos encontraremos con un programa realizado en Java.com/blog/). etc. también) pinchando en el botón Latest Nightly Build.aurelienribon. Simplemente hay que descargarlo del blog de Aurelien Ribbon (http://www. Una vez descargado. lo más simple es usar una herramienta creada por Aurelien Ribbon llamada LibGDX Project Setup. En la última ventana ya sólo queda pinchar en la última versión que se llama libgdx-nightlylatest. Le damos un nombre al proyecto (en este caso Demo1). la mayoría de usuarios suele preferir usar Eclipse.zip Crear un proyecto nuevo Aunque se puede programar con cualquier IDE que permita programar en Java (como Netbeans.jar. pinchar en la opción Download & Source.. Para crear un nuevo proyecto usando LibGDX. Una vez creada esta carpeta. En nuestro ejemplo esta carpeta la llamaremos libs. Para añadir. Para ello click derecho sobre nuestro proyecto y New > Folder. nos vamos al directorio donde hemos guardado la librería descargada en el apartado anterior y podemos arrastrar o copiar los archivos que necesitamos (en la imagen). Para ello una buena práctica es crear un directorio dentro del proyecto donde incluir las librerías que usemos.Una vez creado el proyecto el siguiente paso será añadir la librería. simplemente tendremos que añadir a la misma lo que necesitamos para este proyecto. Nos quedaría el proyecto de esta forma: . aunque no necesaria es añadir la información contenida en el Javadoc de la librería. Pero aún no forman parte del mismo. Para ello seleccionamos los cuatro ficheros dentro de la carpeta libs. El proyecto queda de la siguiente forma: Otra buena práctica. hacemos click derecho y en el menú contextual seleccionamos Build Path > Add to Build Path . El objetivo de esto es que cuando se muestre la ayuda emergente de eclipse veamos la información contenida en el Javadoc de la librería. . el siguiente paso es añadirlas.Ya tenemos las librerías en el directorio que hemos creado dentro del proyecto. .. y buscamos la localización del Javadoc que se encuentra en libgdx-nightly > docs > api..Para ello hacemos click derecho sobre el proyecto y en el menú contextual Build Path > Configure Build Path... tras lo que se nos muestra lo siguiente: En esta ventana desplegamos gdx. Una vez seleccionado este directorio pulsamos sobre Ok para confirmar el cambio. Una vez hecho esto pulsamos sobre Edit. Una vez preparado Eclipse y nuestro proyecto JAVA ya podemos empezar a trabajar. Pulsamos en Browse. .jar y tal como se ve en la imagen seleccionamos Javadoc location.. Y ya tenemos esta característica habilitada. libgdx. Para ello click derecho sobre src > New > Class. Para ello creamos una clase que contenga el método main: . que será la encargada de manejar y controlar todo lo que ocurra en el juego.Lo primero será crear la clase principal del juego.Game).demo1 El nombre de la misma es Demo1Game Esta nueva clase heredará de Game ( com. Una vez creada la clase principal del proyecto. crearemos el punto de entrada para la ejecución de la aplicación JAVA.desarrolladoresandroid. Una clase que nos permitirá lanzar el juego.badlogic. ● ● ● Creamos la clase en el paquete com.gdx. ● ● ● Nombre de la clase: Demo1Desktop Mismo paquete que la clase principal Seleccionamos la opción public static void main(String[] args) . false. Ancho en píxeles. Por lo que se utilizará el 1. Los parámetros indican lo siguiente: ● ● ● ● ● new Demo1Game(). 480. 320. 320.java El resultado de la ejecución será una pantalla negra con la resolución indicada. Que es el título de la aplicación. 480. Instancia de la clase que implementa Game "Demo1". . Para lanzarlo tenemos que hacer click derecho en el proyecto y Run As > Java Application Una vez hecho esto nos saldrá una ventana para seleccionar el punto de entrada de la aplicación que en nuestro ejemplo es Demo1Desktop. Para indicar que no queremos utilizar OpenGL S 2. Alto en píxeles. false). "Demo1".0 en este caso.1 Una vez hecho esto ya tenemos un “juego” que no hace nada y que podemos lanzar como aplicación JAVA.Nos quedaría el proyecto de la siguiente forma: Para poder lanzar el juego añadimos en la clase Demo1Desktop tenemos que añadir lo siguiente: new LwjglApplication(new Demo1Game(). . Portar el proyecto JAVA a un proyecto Android Ahora crearemos el proyecto para compilarlo en Android. Para efectos practicos usare un ejemplo que yo ya tenía. Hecho en escritorio llamado HolaLibgdx. Crear carpeta libs dentro del proyecto y ponerle las siguientes librerías de las que descargamos incluyendo esas carpetas: Importante! "SE DEBEN INCLUIR LAS CARPETAS armeabi y armeabi-v7a como se ve en la imagen. Estas carpetas vienen en las librerías que descargamos" Modificar la Activity principal "HolaLibGdxActivity" para que no extienda de Activity sino de AndroidApplication.. Antes de cerrar esa pantalla anterior ir a la pestaña project y adjuntarle la referencia al proyecto de escritorio.. Click derecho al proyecto / build path / configure build path. .Referenciamos las librerías copiadas. (crt+shift+o) para resolver los imports necesarios. HolaLibgdx. */ @Override public void onCreate(Bundle savedInstanceState) { super.libgdx.os. import com. . //Aca inicializamos al app de escritorio.false).android. } } Debería quedarnos así. public class HolaLibGdxActivity extends AndroidApplication { /** Called when the activity is first created.AndroidApplication.onCreate(savedInstanceState). import android. Lo ejecutamos en el emulador.Bundle.libgdx. 13.badlogic. import com.backends.holalibgx.holalibgdx.package com. initialize(new HolaLibgdx().gdx. Desbloqueamos el dispositivo en el emulador. . también compiló la aplicación en un archivo . Lo que hicimos recién.apk se lleva al dispositivo fisico real y al ejecutarlo te instala la app creada. .y Se ejecuta exactamente lo mismo que en escritorio.apk dentro del directorio /bin del proyecto android. ese archivo . Descargar el libGDX Project Setup Se descarga de la web de Aurelien Ribon pinchando aquí. es necesario crear obligatoriamente el proyecto para Android. por lo que todos los recursos únicamente hay que almacenarlos en dicha carpeta del proyecto de Android para que estén disponibles en el resto de proyectos. sino que también lo podrás generar para android. Lo que hace el asistente es crear un “Core” y un proyecto “Android”.zip el fichero . Una vez descargado. simplemente se extrae del . Posteriormente el resto de proyectos hacen un soft-link a la carpeta Assests del proyecto Android. IOS y HTML5 de forma simultánea. la siguiente pantalla será la siguiente: .jar y se ejecuta. se pueden realizar dos acciones: crear un nuevo proyecto (pinchando en “Create”) o actualizar un proyecto existente (pinchando en “Update”). Si pinchamos en “Create”. El único requisito es que para crear cualquier proyecto.Método 2: usando el libGDX Project Setup Este segundo método es mucho más sencillo y seguro que nos quita dolores de cabeza innecesarios ya que simplemente ejecutando el GUI y rellenando unos pocos campos tendremos listo para importar a Eclipse no sólo un proyecto para escritorio. Aparecerá la siguiente pantalla: Como se puede observar. . así como las plataformas que queremos generar (como se puede comprobar. Para ello. También podremos descargar e incluir librerías de terceros. También nos permitirá configurar el SDK mínimo y el SDK objetivo de Android de nuestra aplicación. nos dará la opción de escribir los sufijos que queremos que tengan los diferentes proyectos. Generation: Esta parte nos informa de si podemos pasar al proceso de generación o no y nos ofrecerá un botón para ir a dicho proceso si todo está correcto. Overview: Esta parte simplemente nos mostrará el árbol de ficheros que va a generar el asistente para nuestra información 4. el de la clase del juego. si no la tenemos descargada. Configuration: en esta parte simplemente podremos poner el nombre del proyecto. el destino. “core” y “Android” no se pueden deseleccionar porque son obligatorias). 3.En esta pantalla tenemos cuatro partes diferenciadas por un número que sirven para lo siguiente: 1. Si pinchamos en “Show advanced settings> “. Library Selection: En esta parte está las diferentes librerías que queremos que tengan nuestros proyectos. nos permitirá descargarla pinchando en el icono de la derecha (nos descargará las “latest nightlies version”) o el penúltimo de la derecha (nos descargará la última versión estable). el del paquete que lo va a contener. 2. Como mínimo es obligatorio que tenga LibGDX instalado (¡Obvio!). ● La parte de la izquierda simplemente nos da la opción Launch! que generará nuestro proyecto y la opción Back por si queremos hacer algún cambio antes de la generación. .Una vez pinchamos en el botón “Open de generation screen”. se nos mostrará la siguiente pantalla: En esta pantalla. tenemos dos partes: ● La parte de la derecha es otra vez la pantalla Overview que nos muestra el árbol de ficheros a generar. Finalmente se nos mostrará la siguiente pantalla con la información de cómo ha ido el proceso.Una vez se pincha en el botón de Launch! nuestro proyecto será generado en la ruta que le indicamos en pasos previos. simplemente se cerrará para finalizar la ejecución del asistente. Si no ha ocurrido ningún error. . Una vez seleccionamos la carpeta. en la nueva ventana que aparece.. Para ello. . elegir la opción “Select root directory:” y pinchar el botón “Browse. sólamente queda importarlo desde Eclipse. seleccionar “Existing Projects into Workspace” y después al botón Next.Una vez hecho esto. se abre Eclipse y se pincha en File -> Import.” para que nos permita seleccionar la carpeta en la que se han creado todos nuestros proyectos desde el asistente de libGDX. marcar la opción “Copy projects into Workspace” para que nos copie los proyectos importados en nuestra carpeta de trabajo y a continuación pinchamos en “Finish”. en el cuadro “Projects:” nos aparecerán todos los proyectos que hay en el interior.. En la ventana que aparece a continuación. Seleccionamos los que queramos importar (recordad que los proyectos core y Android son obligatorios). . Con esto. tendremos los proyectos importados y con todas las librerías necesarias para comenzar a trabajar con libGDX. El arbol de ficheros que se crea en Eclipse debe ser similar al siguiente: . config). initialize(new MyGame(). archivos de entrada y módulos de E/S.Ciclo de vida de aplicación libGDX Este apartado describe cómo se estructura una aplicación libgdx. La interface también proporciona los métodos para acceder a gráficos. audio. La interface Application determina la plataforma y los graficos de fondo que serán utilizados por la aplicación. Una instancia de esta clase es pasada a los métodos de inicialización respectivos de cada implementación de Application de cada backend. También da acceso a un módulo de Logging el cual funciona en todas las plataformas.onCreate(bundle). new LwjglApplication(new MyGame(). una LA APLICACION Es el principal punto de entrada para cualquier aplicación libgdx. } } Para Android. Las clases de inicio El único código de plataforma específica que es necesario escribir. } } Estas dos clases viven en proyectos separados. config). La aplicación . AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(). la clase de inicio correspondiente quedaría así: public class AndroidStarter extends AndroidApplication { public void onCreate(Bundle bundle) { super. por ejemplo. usando el backend Lwjgl quedaría algo así: public class DesktopStarter { public static void main(String[] argv) { LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(). son las llamadas clases de inicio. El código actual de la aplicación está localizado en una clase que implementa el interface ApplicationListener (MyGame en el ejemplo anterior). Por cada plataforma. un pequeño trozo de código instanciará una implementación concreta de la interface Application. Para una aplicación de escritorio. se ha de implementar la interfaz ApplicationListener primero. RESUME y DISPOSE. la actualización del estado del juego (es decir. guardar el estado y la liberación de los recursos al salir de la aplicación. otra para HTML5 y otra para IOS. Es también el lugar donde los eventos del ciclo de vida son manejados. PAUSE. Por tanto. otra para Android. la lógica del juego). APPLICATION LISTENER ApplicationListener es el responsable de la inicialización de la aplicación. Application es responsable del circuito de juego y ApplicationListener es el lugar donde se implementa la lógica del juego. escucharán 6 notificaciones principales: CREATE. renderización de la imagen. La implementación de la interfaz ApplicationListener Las aplicaciones que usan libGDX. Para crear una aplicación libGDX. Cada aplicación / juego. LibGDX es compatible actualmente con dos back-ends de aplicaciones de escritorio (lwjgl y JOGL). sin importar el back-end y / o plataforma de destino tendrá que implementar la interfaz ApplicationListener. RESIZE. La implementación es exactamente la misma para todas las plataformas. pausado del juego. .llamará entonces a los métodos de ApplicationListener en el momento adecuado tal como se comenta en el punto “Ciclo de vida de una aplicación” más adelante. RENDER. En el escritorio este método no será llamado nunca. La actualización del juego también tiene lugar aquí antes de la representación real. Es un buen lugar para guardar el estado del juego en Android. ya que no se garantiza que sea reanudado. ● resize(int width. . Es precedido por una pausa ().● create (): Se llama una vez cuando se crea la aplicación. En Android se llama cuando el botón de inicio se presiona o haya una llamada entrante. int height): Se llama a este método cada vez que la pantalla del juego cambia su tamaño y el juego no está en el estado de pausa. Los parámetros son la nueva anchura y altura de la pantalla. ● resume(): Este método es llamado sólo en Android. En el escritorio se llama justo antes de dispose () al salir de la aplicación. También se le llama sólo una vez justo después del método create (). ● pause (): El método de pausa se llama justo antes que se destruya la aplicación. ● render (): Método llamado por el bucle del juego de la aplicación cada vez que se renderiza. cuando la aplicación recibe el foco. ● dispose (): Se le llama cuando la aplicación se destruye. El siguiente diagrama muestra las diferentes fases por las que pasa una aplicación libGDX: .Ciclo de vida de una aplicación Los métodos antes mencionados son provocados por la aplicación durante su ciclo de vida. newAudioDevice(44100. Gdx. Por ejemplo.Módulos de libGDX El núcleo de libGDX se basa en cinco interfaces que proveen formas de interactuar con el SO. El método devuelve una instancia que puede ser usada para dibujar en la pantalla. Estos son: ● Aplicación (Application) ● Gráficos (Graphics) ● Entrada/Salida (Files) ● Entrada (Input) ● Audio (Audio) Acceso a los módulos El acceso a los módulos anteriormente listados puede hacerse a través de campos estáticos de la clase Gdx. En el siguiente código podemos ver cómo obtener una instancia de la API OpenGL 1.audio. devuelve null. false). Dependiendo del hardware subyacente.0.graphics. El módulo de gráficos también proporciona métodos para generar mapas de pixels y texturas. los contenedores pueden ser o pueden no estar disponible. para acceder al módulo de audio simplemente se puede escribir lo siguiente: // creates a new AudioDevice to which 16-bit PCM samples can be written AudioDevice audioDevice = Gdx. En el caso que la configuración de hardware no sea compatible con OpenGL ES 1. Gráficos El módulo de gráficos es un resumen de la comunicación con el GPU y proporciona métodos de conveniencia para obtener las instancias de OpenGL ES. Se encarga de todo el código repetitivo necesarios para hacerse con el ejemplo de OpenGL y se ocupa de todas las implementaciones proporcionadas por el fabricante.audio es una referencia a la implementación backend que ha sido instanciada en el inicio de la instancia Application. Esencialmente es un juego de variables globales que permiten el fácil acceso a cualquier módulo de libGDX.0: GL10 gl = Gdx. Cada backend implementa estos interfaces. .getGL10 (). 480).glClearColor(0. Aunque en los ejemplos se definen la textura cuadrada.0f. no tiene por qué ser así. public void create(){ camera = new OrthographicCamera(640. 1024.1 el ancho y alto de una textura tiene que ser potencia de 2 (. Esto es debido al funcionamiento de OpenGL. Por ejemplo. 0. Intentar utilizar texturas más grandes en este dispositivo provocarán errores en el juego. Si usamos OpenGL v2. //configura un color y un alpha al //borrado gl. Para crear una cámara ortográfica: public class Game implements ApplicationListener { public OrthographicCamera camera. 0. 256.La recomendación es que no pases del valor 1024 para establecer el ancho o alto de tus texturas. 512. una textura de 1024x1024 (Aunque puedes tener más de una textura a la vez).GL_COLOR_BUFFER_BIT).. 128. . el HTC G1 soporta como mucho. . es realizar un borrado de pantalla en el método render incluyendo las siguientes sentencias al principio: gl. dejaremos esa explicación).glClear(GL10. 1).Consideraciones previas sobre OpenGL Previamente a dibujar nada con libGDX.. no se tiene esta limitación. 64. En OpenGL v1.0f. (Para no complicar las cosas. } … } Otra cosa a tener en cuenta antes de renderizar imágenes en libGDX. Un parámetro muy importante que hay que indicar a la hora de crear un objeto Texture es un valor TextureOptions que indicará qué método se utilizará para redimensionar las imágenes que tenemos dentro de la textura. etc. etc).32. lo primero es crear una cámara ortográfica. Lo único que hay que tener en cuenta es que al crear una cámara ortográfica tienes que tratar el eje z a 90 grados como si estuvieras mirando un cuadro para poder ver en 2D. //realiza el borrado con una máscara Texturas e Interpolación Texture es una "imagen" en la memoria del chip gráfico (las imágenes en disco se cargarán en esta zona de memoria). 32x256.1f. Puedes tener una textura de 128x32. pero no verás píxeles en la misma. Es mucho más rápido. pero la imagen tiene menor calidad. como sobras o halos resplandecientes que no deberían estar.Se pueden elegir los siguientes modos: ● NEAREST: La imagen aparecerá pixelada. Original: Ampliada con NEAREST: ● BILINEAR: La imagen aparece más difuminada.BILINEAR . Original: Ampliada con BILINEAR: ● REPEATING: Si la textura es de 32x32 y tiene que dibujarse sobre una superficie de 64x64. así que por ahora. Aquí es donde entra en juego la técnica " premultiplied alpha". vamos a ignorarlo. Cuando utilizas imágenes que contienen valores alpha (transparencia) puedes encontrarte con que te aparezcan "halos" que rodean los bordes de las mismas. estableces: TextureOptions. la cual corrige ese problema. Si quieres una interpolación bilineal. Este modo no funciona con los Sprites normales. veremos 4 imágenes rellenando ese hueco. Intenta evitar utilizar "premultiplied alpha" a menos que veas cosas raras en los bordes de tus imágenes. Como si pusiéramos la misma imagen una y otra vez repitiéndola. Es un poco más lento. int width. decir que: TextureOptions. int y. Para finalizar. Un ejemplo de selección de un área con TextureRegion es el siguiente: TextureRegion texture = new TextureRegion(new Texture( . TextureRegion(Texture texture. float u2.Se podran definir despues empleando los métodos de la clase.BILINEAR_PREMULTIPLYALPHA Lo mismo ocurre si quieres interpolación NEAREST con o sin "premultiplied alpha". int width.Si quieres una interpolación bilineal con " premultiplied alpha". Es cosa tuya explorar los valores que puedes elegir de TextureOptions.alto) TextureRegion(TextureRegion region) Construye una región con la misma textura y coordenadas que la región pasada como parámetro.DEFAULT = TextureOptions. son los siguientes: TextureRegion() Construye una region sin textuta ni coordenadas definidas. float v2) TextureRegion(Texture texture. int y. float u. int height) Construye una región con la misma textura y coordenadas que la región pasada como parámetro. int x. El sistema de coordenadas utilizado tiene su origen en la esquina superior izquierda con el eje x apuntando hacia la derecha y el eje y apuntando hacia abajo. float v.NEAREST_PREMULTIPLYALPHA TextureRegion Define un área rectangular de una textura. int x. Tiene varias opciones para construir un objeto de esta clase. TextureRegion(TextureRegion region. int height) Construye una región con con las coordenadas de la textura y el ancho y alto especificado. Las textureRegion son empleadas para crear nuevas imagenes( o también llamados actores de tipo imagen) asociadas a un área de una textura. int height) Define una tetura especificando el punto (x. TextureRegion(Texture texture) Construye una region de tamaño especificado en la textura.y) de origen y el tamaño del area (ancho. TextureRegion(Texture texture. int width. estableces: TextureOptions. process(settings. luego dibujar porciones de la misma muchas veces.jar El código para ejecutar el TexturePacker: Settings settings = new Settings(). Se deberá tener en el proyecto una carpeta images. settings.Gdx. Empaquetar imágenes automaticamente Se deberá importar la libreria: gdx-tools. También tiene una fuerza bruta. el embalaje de varias maneras y luego elegir el resultado más eficiente. settings.obligar a la textura más una vez.files. settings. . TexturePacker se basa en este algoritmo. Lo ideal es almacenar muchas imágenes más pequeñas en una imagen más grande. TexturePacker. 40.incremental=true.maxWidth=1024.png")). settings. 40). 0. 0. "data"). libgdx tiene una clase TexturePacker que es una aplicación de línea de comandos queempaqueta muchas imágenes más pequeñas en 1imágen más grande.maxHeight=1024. Carga de imágenes empaquetadas Asi se recuperan las texturas de un textureAtlas Generado por un packer. El proceso generará la carpeta data con el pack realizado.internal("data/jugador. TexturePacker Empaqueta imagenes en un Texture Atlas.padding=2. "images". con las imagenes a procesar. soundoff = atlas.findRegion("soundon").files.public static AtlasRegion background. */ public static void load(){ atlas = new TextureAtlas(Gdx. */ . background = atlas. soundon = atlas. /** Se utiliza para dibujar y optimizar las imagenes en el renderizado de la pantalla. soundon. */ OrthographicCamera guiCam.internal("data/pack")). */ public static TextureAtlas atlas. } } public static void dispose(){ atlas. atlas = new TextureAtlas(Gdx. } public class HolaLibgdxExample implements ApplicationListener { /** The gui cam.findRegion("background").findRegion("soundoff"). title = atlas. soundoff.files.dispose().findRegion("start"). start. title. /** * Load.findRegion("title").findRegion("background"). start = atlas. background = atlas.internal("data/pack")). /** Regiones dentro de la public static AtlasRegion public static AtlasRegion public static AtlasRegion public static AtlasRegion public static AtlasRegion imagen de textura empaquetada */ background. public class Assets { /** Contiene el paquete de texturas. Dibujar imágenes en pantalla Creamos la clase Asset para almacenar los recursos de imagenes. //Se elimina graficamente la transparencia ya que es un fondo batcher. 1). // Donde estara mirando la camara batcher = new SpriteBatch().start.SpriteBatch batcher. } @Override . 3.title. 6.draw(Assets.draw(Assets. //Dibujando el Background batcher.getGL10().combined).glClearColor(0.setProjectionMatrix(guiCam. 2. batcher. 15f / 2. 8. @Override public void create() { } @Override public void dispose() { batcher. batcher. batcher.GL_COLOR_BUFFER_BIT).enableBlending(). 6).position. 0. //Dibujando elementos en pantalla activamos el Blending batcher.set(10f / 2.draw(Assets.end().begin(). //definicion de nuestra propia medida del juego guiCam.end(). 10. guiCam = new OrthographicCamera(10. 2. batcher. batcher. batcher.background. 5. 15).soundon.dispose(). batcher.draw(Assets.1. 8. 6. 15). //referencia a OpenGL 1. 1). gl. batcher. //crear solamente un batcher por pantalla y eliminarlo cuando no se use guiCam.0 gl.0.graphics.disableBlending(). 1.glClear(GL10.1). 0.begin(). 0).update(). } @Override public void pause() { } @Override public void render() { GL10 gl = Gdx. public void resize(int arg0. int arg1) { } @Override public void resume() { } } . . Usamos tambien el objeto de OrthographicCamera. la pantalla táctil y el acelerómetro.isTouched ()) { System. En el escritorio la pantalla táctil se sustituye por el ratón.out. un area ficticia donde se captará el evento de pulsación del dedo. Y escribimos el código para manejar ese evento . y =" + y). Permite saber del estado de cada tecla.Entrada El módulo de entrada permite capturar los diversas formas de entrada de cada plataforma.input. En el fragmento de código siguiente se obtiene el touch actual de coordenadas si hay un touch del celular (o del ratón en el escritorio): if (Gdx. } De manera similar a todos los medios de entrada pueden ser consultados y manipulados. mientras que el acelerómetro no está disponible. Detectar pulsaciones en la pantalla táctil Se debe difinir un Vector. para convertir los pixeles en nuestra medida en metros.println ("de entrada se produjo en x =" + x + ". Luego preguntamos si el boton que creamos “BoundingBox” tiene un touch. Audio LibGDX cuenta con un módulo de audio que ofrece dos tipos de recursos: El sonido y la música. music. Lo normal es cargar el sonido desde un . music.mp3". FileType. Ambos tipos soportan el formato WAV. music.newMusic(Gdx. Sonidos Sound es una clase destinada a la reproducción de un efecto de sonido.setLooping(true).MP3 y OGG.5f).files. mientras que la música son streams de sonido que están almacenados en ficheros y a los que se accede cada vez que se quiere reproducir algo.Internal)).play().audio. El siguiente fragmento de código reproduce un fichero de música desde el disco con el volumen a la mitad: Music music = Gdx.setVolume(0. La diferencia entre el sonido y la música es que el sonido se almacena en memoria y se usa cada vez que se quiere reproducir alguno de ellos. También ofrece acceso al hardware de sonido.getFileHandle("data/myMusicFile. dispose() para liberar memoria en el dispositivo. Cuando ya no vayamos a usar más ese sonido será necesario llamar al método Sound. .play(). incidiendo directamente en el rendimiento. llegando a durar unos pocos segundos ya que al ser cargados en memoria pueden llegar a ocupar demasiado. Los sonidos son generalmente cortos.archivo a memoria y luego reproducirlo a través del método Sound. audio.newSound pasando como parámetro el fichero dentro del directorio data.internal("data/explosion.dispose().files.ogg")). Para descargar de memoria un sonido tan sólo será necesario llamar al método dispose del objeto. Sound explosion explosion = Gdx. Musica Music es la clase de libgdx para cargar archivos de sonido en nuestros juegos deriva de la clase Disposable consta de los siguientes métodos: ● play() →Comienza a la canción. explosion. haremos la llamada a newSound en nuestro método destinado a la carga de datos. explosion. Descargar sonidos Una vez que no queramos hacer uso del sonido será necesario descargarlo de memoria ya que en los dispositivos móviles.play(1). Puesto que el sonido será una cosa que sólo se cargará una vez durante toda la vida de la aplicación.Cargar sonidos Los Archivos para los efectos de sonido los pondremos dentro de una carpeta llamada data Para cargar en memoria un efecto de sonido tan sólo será necesario definirlo como tipo Sound y llamar al método Gdx. El siguiente fragmento de código carga un sonido en memoria.en el el caso de estar pausada la reanuda donde se quedo y en el . Esto podemos hacerlo en nuestro apartado destinado a la descarga de datos o bien en el método dispose de la aplicación.audio.newSound(Gdx. como ya hemos visto en el apartado de ciclo de vida de la aplicación. Reproducir sonidos Para reproducir un sonido previamente cargado en memoria tan sólo será necesario hacer una llamada al método play del sonido pasando como parámetro un valor entre 0 y 1 que representará el volumen. la memoria RAM sigue siendo un elemento muy precidado. 12. este método es ignorado al llamarlo.getFileHandle("data/8. ● setVolume() →Varía el volumen del sonido.mp3". . Estas clases permiten a la salida de las muestras de PCM para el dispositivo físico de audio.caso de que se hubiera parado la comienza desde el principio. ● pause() →Pausa la canción. así como muestras PCM registro de un micrófono conectado. OGG y WAV. Es conveniente usar Ogg en casi todos los casos. FileType. Es muy conveniente llamarlo cuando no sea necesaria la musica ya que consume memoria del disposivoLibgdx soporta los formatos MP3.audio. indicando el filesystem que lo contiene. FileType. si la canción no ha empezado aun o esta ya ha finalizado. esta función activa la repetición indefinida de la música. admite por parámetros (0 ó 1) . ● setLopping() →Admite como parámetro un booleano para indicar si se activa la función loop en la canción. ● isLopping() →Función que devuelve un booleano. ● Internal → Path relativo a la ruta de la aplicacion android o dicho de otro modo relativo al directorio raiz de la aplicación creada. Si necesita más control sobre el dispositivo de audio. ● getPosition() → Función que devuelve un float con la posición de la canción en milisegundos ● dispose() → Es el destructor de la clase.newMusic(Gdx.mp3 esta guardada dentro de la carpeta del proyecto data. indicando si es verdad o no que la canción esta sonando. de tal forma que si se llama al procedimiento indicando true. la canción se repite indefinidamente hasta que la paremos o hasta que desactivemos el loop. Cargar una música Las músicas se pueden almacenar de forma interna en el proyecto que estamos desarrollando o en una ruta fija(por ejemplo para poner como música un sonido standard del sistema) Para cargar una música en memoria debemos instanciar un objeto de la clase Music pasandole como parámetro un puntero al fichero del tipo FileHandle nativo de java.con un 0 se pone en silencio y con 1 se pone el volumen al máximo.FileType. por lo que el tipo de archivo le indicamos que es interno. ● stop() →Para la canción.Internal. puede utilizar el AudioDevice y clases Audiorecorder que también se obtiene de la interfaz de audio.files. En este ejemplo la canción 8.12. ● isPlaying() →Función que devuelve un booleano. de la siguiente forma: Music music = Gdx. indicando si es verdad o no que la canción esta sonando. estos son: ● External → Path relativo a la raiz del almacenamiento SD de android.La siguiente vez que se llame al método play() la canción comenzará desde el principio. ● Classpath → El path del fichero esta en una ruta relativa a la raiz del Clashpath ● Absolute → El path esta indicado de forma absoluta.Internal)). En el caso de no poder abrir el archivo se genera una excepción GdxRuntimeException Los tipos posibles de ficheros son los nativos de Javade tipo File. Esto podemos hacerlo en nuestro apartado destinado a la descarga de datos o bien en el método dispose de la aplicación.stop().newMusic(Gdx.Internal)). Para descargar de memoria un sonido tan sólo será necesario llamar al método dispose del objeto.mp3". .setLooping(true). music.files.play(). Vamos a verlo mas claramente con un pequeño ejemplo de como dejar una música reproduciéndose en un bucle infinito donde la música es un archivo mp3 almacenado en una carpeta que hemos llamado data Music music = Gdx.12. En el caso de que la música estuviera en un bucle lo lógico es pararla antes de eliminarla por seguir una secuencia lógica. Descargar una música Una vez que no queramos hacer uso del sonido será necesario descargarlo de memoria.dispose(). por tanto el orden seria : music.audio. music. como ya hemos visto en el apartado de ciclo de vida de la aplicación. estos se hace llamando al método stop.getFileHandle("data/8. music. FileType.Reproducir una música Para reproducir una música como hemos mencionado antes basta con llamar al metodo play() desde el objeto instanciado de tipo Music. y en parte por estética de la programación. System.position.println(e). return.set(10f / 2. } catch (Exception e) { System. Menu principal. creamos la screen. } Cámaras OrthographicCamera guiCam.out. 15). guiCam = new OrthographicCamera(10. nivel 1. Una Screen es una pantalla de un juego. // Donde estara mirando la camara . try { Gdx. //definicion de nuestra propia medida del juego 10x15 metros: Esto es porque dividmos los 320x480 pixeles en bloques de 32px. 15f / 2. creditos.out.input.vibrate(200). guiCam. Para cambiar entre pantallas haremos: Screen gameScreen = new GameScreen(game). etc. game. Vibración Para agregarle al juego del arkanoid (el del video tutorial) que vibre al chocar la barrita con la pared izquierda por modificamos el método render() de la clase GameScreen.println("vibra").setScreen(gameScreen). es decir. y se la seteamos a la instancia del juego. 0). nivel 2.Navegando entre pantallas del juego Game extiende de AplicationListener para implementar multiples pantallas. Opciones. Por último cuando se invoca al spriteBatch. Cuando se crea la animation. Aquí se ve el ejemplo de un hombre corriendo.Animación Crearemos un personaje de un personaje y haremos una animación. la posición de X y de Y en donde se quieren dibujar las mismas. que camine como si se estuviera moviendo. se le pasa por parametro la velocidad con la que se mueve el frame y el vector de imágenes. Usaremos la siguiente Imagen como secuencia: Copiaremos esta imagen. La imagen se puede ver como una matriz de imágenes las cuales se van a recorrer con dos ciclos y se van a pasar por imagen a un vector.draw(). es decir. se le indica el vector que contiene las imágenes. en la carpeta /imagen del proyecto Creamos una clase que implemente screen animación: . // #8 #3 // #5 #6 // #7 } Inicializamos en el constructor lo referente a la animación: public AnimationScreen(Game game) { this.glClear(GL10.position. static final float WORLD_HEIGHT = 3.files.getWidth() / FRAME_COLS. i < FRAME_ROWS.getHeight() / FRAME_ROWS). for (int i = 0. // #1 private static final int FRAME_ROWS = 5.split(walkSheet.game = game. walkFrames). // #10 walkFrames = new TextureRegion[FRAME_COLS * FRAME_ROWS]. SpriteBatch spriteBatch. // #11 spriteBatch = new SpriteBatch(). i++) { for (int j = 0.GL_COLOR_BUFFER_BIT | GL10.gl. WORLD_HEIGHT / 2.internal("images/man. guiCam.png")).025f.3f. j < FRAME_COLS. static final float WORLD_WIDTH = 5. // TextureRegion currentFrame. walkSheet. Animation walkAnimation. // #9 TextureRegion[][] tmp = TextureRegion.GL_DEPTH_BUFFER_BIT). 0).public class AnimationScreen implements Screen { Game game. // #12 stateTime = 0f. j++) { walkFrames[index++] = tmp[i][j]. SpriteBatch batcher. // #2 OrthographicCamera guiCam. walkSheet = new Texture(Gdx. float positionX=1. walkSheet. int index = 0. // #4 TextureRegion[] walkFrames. float stateTime. // #13 } Ahora en el render hacemos: Gdx. guiCam = new OrthographicCamera(WORLD_WIDTH. batcher = new SpriteBatch(). WORLD_HEIGHT). } } walkAnimation = new Animation(0. // #14 . // Texture walkSheet.set(WORLD_WIDTH / 2. private static final int FRAME_COLS = 6. getKeyFrame(stateTime.draw(currentFrame. #16: obtenemos el frame correspondiente en base al tiempo que lleva moviendose Metodo Update public void update(float delta){ positionX+=0.begin().1f. spriteBatch. true). positionX.stateTime += Gdx. // #17 spriteBatch. 2).com . update(delta).graphics. // #16 spriteBatch.getDeltaTime(). // #15 currentFrame = walkAnimation.end(). } Si necesitan el código fuente completo de este ejemplo: javi10823@gmail. Manual de buenas prácticas TO DO: Introducción a cosas para ser más eficientes y limpios escribiendo código.Las variables finales se escribirán integramente en mayúscula. . estos son solo algunos ejemplos. el nombre de estos suelen ser verbos. a diferencia de otros lenguajes de programación como puede ser python.Los nombres de las variables comienzan con letras minúsculas.El nombre de las clases comenzará con la primera letra en mayúscula y las siguientes en minúscula. . y en caso de contener varias palabras se le pondrá mayúscula a la primera letra de cada palabra a partir de la segunda palabra. no hacer condiciones muy largas o muchos bucles anidados.Respetar las reglas de nomenclatura de los lenguajes tales como los siguientes: . . . En ocasiones . ahora explicare un poco mas extenso algunos de los puntos mencionados anteriormente.Realizar un estudio que relacione el tiempo de procesamiento vs almacenamiento. pero de esta forma se hace el código más legible. .Los nombres de los métodos se escribirán en minúscula siguiendo la misma regla que el nombrado de las variables. . . En java. diferentes palabras por medio del carácter guión bajo “_” . Por lo general. de esta forma se tiene un acceso rápido a esa variable y sabemos de un simple vistazo que atributos tiene. En caso de contener varias palabras se las distingirá poniendo mayúscula la primera letra de cada palabra.Definir variables al principio de la clase/método. Para ser limpios y eficientes escribiendo código es importante tener en cuenta varias cosas como creaciones de métodos para simplificar el código.El nombre de los paquetes se realizará integramente en minúscula. aunque contenga varias palabras. separando.Tabular el código para una mayor compresión del mismo. no es necesario que las lineas de código estén tabuladas para pertenecer a un método/función/clase ya que para esto se utilizan las llaves. si fuera necesario. por eso cuando estemos programando hay que intentar dejar lineas simples. 1. cuando veas que estas creando dos variables para guardar información sobre un objeto dentro de una clase seguramente podrás . . o parecido. esto no suele aparecer mucho pero hay que tener cuidado a la hora de meter for while o do. j++) { batcher. Lo que también ayudara a la hora de la limpieza y de la claridad seran la clases. ya que si después alguien quiere usar nuestro o código o simplemente saber como funciona le sera imposible. creaciones de objeto que varían muy poco. lo mas probable es que puedas cambiarlo por una función o un método. i++) { for (int j = 1. teniendo en cuenta que un case solo comprueba integer y enumerados. pero un array tiene un acceso inmediato al dato contenido. esto implica dibujar o crear 100 casillas. cambiar un objeto. 1). En estos y en muchos mas la creación de una clase es lo mejor.Crear un casillero de 10 x 10. Y esto no es eficiente. uno dentro de otros ya que puede dar problemas Otra de las cosas que hay que tener en cuenta a la hora de programar es ser limpio y no escribir como se nos van ocurriendo las cosas y dejarlo así.una lista puede estar muy bien para almacenar datos.draw(casilla. 1). j < 11.Pelota en un espacio: Además de su nombre tendrá un x e y indicando su posición. Siempre que vallas a utilizar un objeto que vaya a tener mas de una propiedad se utilizan clases. siempre que al modificarlo no haya nada dependiendo de el. . . pero podrías dibujarlo con: for (int i = 1. Por ejemplo: . i < 11 .Usar varios for anidados hace que el programa se ralentice mucho. lo mas importante en el caso de la programación orientada a objetos. para que puedas modificarlo.draw(casilla. i. 1. . Algunos ejemplos: .Si ves que programando escribes varias veces lo mismo. un inventario guardado en un array. posX. ya que podemos encontrarnos con recorridos con muchos elementos y los recorre todos por lo que ralentiza mucho y no es eficiente. posY. o explicar con comentarios cuando veamos que algo puede que no se entienda. j. o cualquier cosa.Antes de crear un método comprobar que no existe ya. comprobación de un objeto.Personaje: Además de su nombre puede tener su posición indicada con x e y.Usar switch case si ves que comparas lo mismo dentro de muchos if. escribirías 100 veces: batcher. } } } . int y){ switch(matriz[x][y]){ case 0: return Assets. break. break. Separar la lógica de la presentación Con lógica nos referimos a todas las comprobaciones.x = ball. break.barco2.x = 1 + 0. pero teniendo en cuenta que el render lo debe llamar. case 1: return Assets.casillaB.25 < 1){ ball.casillaG. si hicieramos la parte logica en una clase llamada World deberia quedar algo parecido a esto: public class World { .position. Para hacer la parte lógica basta con crear un clase aparte del renderizado donde comprobemos lo que haga falta antes de pintar en pantalla. ya que el proceso de renderizado solo ya es lento si metes también toda la logica ara que el juego sea lento.0. En resumen todo lo que no sea dibujar en pantalla y deba ejecutarse siempre se ha de poner fuera del renderizado. break. modificaciones o creaciones que se hacen antes de renderizar.barco. break. case 2: return Assets.direction.VELOCITY. ball.x . case 3: return Assets.casillaR.25f.instanciar ese objeto desde otra clase y sera mas claro que poniendo tantos atributos. por esto es recomendable hacerlo en una clase aparte.position. Por ejemplo: -Cambiar la velocidad de una pelota al chocar con una pared: // Choque en pared izquierda if(ball. default: return Assets. } -Comprobar el valor de una casilla para pintarla de un color diferente: public AtlasRegion casilla(int x. } } -Actualizar valores de las variables. //esto llama al contructor. Para usar el World hay que llamarlo desde el render. que se el puede pasar los parámetros que se necesiten } } Puede haber distintos World. que sera creado en la clase de la pantalla. } //inicializar variables o limpiar public void initialize(){ } //actualizacion public void update(){ //aqui deberá ir todo lo que forma parte de la lógica para el renderizado de la pantalla. pero antes tiene que haber un objeto desde el que llamarlo. que a la vez llama al inizialite. . teniendo en cuenta que hay que llamarlo desde el render.//atributos internos //constructor public World(){ initialize(). aqui un ejemplo: public class GameScreen implements Screen{ World world. //Atributos public GameScreen(){ this. //inicializacion de atributos. abajo creado. no tiene porque ser solo de una. y puede usarse en las pantallas que se necesiten.//metodo interno.world = new World(). int height) { } @Override public void resume() { } @Override public void show() { } } .//aqui actualizamos la logica del juego.update().} @Override public void dispose() { } @Override public void hide() { } @Override public void pause() { } @Override public void render(float delta) {//delta es el tiempo transcurrido desde la ultima llamada por si la logica lo necesita. World. //Pintar imágenes. } @Override public void resize(int width. . blogspot.mysoundfx.Recursos para Desarrollo de Juegos Descargar Sonidos http://www.html Fondos http://2dgameartforprogrammers.net/tutorial.blogspot.com/es/ Tutorial creación Sprites Animadas desde cero http://ilovepixel.com/2011/11/creating-basic-face.com/ Crear un personaje para Animación http://2dgameartforprogrammers.com/2011/10/creating-game-character.html Caras http://2dgameartforprogrammers.blogspot.blogspot.com/ Musica para dar ambiente a tu juego http://pro.html .html 2d Game Art For Programmers http://2dgameartforprogrammers.com/2011/10/more-fun-with-gradients.jamendo.
Copyright © 2024 DOKUMEN.SITE Inc.