martes, 27 de diciembre de 2011

Detectar pulsaciones dentro de un rectangulo en modo apaisado. libGDX

Si tenemos el dispositivo en modo apaisado, detectar donde se ha pulsado no es tan facil. Las coordenadas del rectangulo que queremos comprobar no nos sirven. Hay que tener en cuenta siempre que el eje Y va de abajo hacia arriba con las libGDX. Yo lo he "solucionado" cambiando la coordenada y despues de haber creado el rectangulo con las coordenadas sacadas del photoshop.
/** @Pasa de un rectangulo con la posicion y normal a  uno con el eje girado y modo landscape
  * 
  * @param rect el rectangulo a cambiar
  * @return
*/
 private Rectangle CambiarEjeYLandscape(Rectangle rect)
 {  
  return new Rectangle(rect.x, (Configuracion.ALTO_VIEWPORT - rect.y - rect.height), rect.width, rect.height);
 }

miércoles, 21 de diciembre de 2011

Comprobar que se ha pulsado dentro de un rectangulo libGDX

Sacado de el ejemplo SuperJumper que viene con libGDX
  import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;

public class ComprobadorSuperposicion {
 public static boolean SuperposicionRectangulos (Rectangle r1, Rectangle r2) {
  if (r1.x < r2.x + r2.width && r1.x + r1.width > r2.x && r1.y < r2.y + r2.height && r1.y + r1.height > r2.y)
   return true;
  else
   return false;
 }

 public static boolean puntoEnRectangulo (Rectangle r, Vector2 p) {
  return r.x <= p.x && r.x + r.width >= p.x && r.y <= p.y && r.y + r.height >= p.y;
 }

 public static boolean puntoEnRectangulo (Rectangle r, float x, float y) {
  return r.x <= x && r.x + r.width >= x && r.y <= y && r.y + r.height >= y;
 }
}
 

martes, 20 de diciembre de 2011

Meter archivos en la sd card

Pongamos que queremos, por ejemplo, meter un archivo de configuración.
¿Como se hace? ¿Como meto un archivo en la sdcard del emulador?
Lo suyo es abrir en Eclipse la perspectiva DDMS y  en mmnt->sdcard pulsar el icono que hay arriba a la derecha en el que aparece un flechita apuntando hacia un teléfono.
Pero te puede salir como a mi:
   Failed to push selection: Read-only file system
¿Que hacer?
Te vas a la linea de comandos y luego a : (en Windows XP)
   C:\Documents and Settings\TuUsuario\android-sdks\tools
allí pones:
    mksdcard -l mysdcard 128M sdcard.img
y creas la imagen de la tarjeta sd

Vuelves al Eclipse boton derecho en el proyecto android y “Run configurations…”
En el target , en additional Emulator Command line Options  hay que indicarle que use la imagen de la tarjeta
sd que previamente hemos creado, así:
   -sdcard "sdcard.img"

Volvemos a abrir en Eclipse la perspectiva DDMS y  en mmnt->sdcard pulsar el icono que hay arriba a la derecha en el que aparece un flechita apuntando hacia un telefono. Elegimos el archivo a subir a la sd
y listo.

[Image]

viernes, 16 de diciembre de 2011

TextureAtlas

Esto se usa para explotar las texturas que ha empaquetado el TexturePacker y poderlas pintar con el programa.
Ejemplo de uso:
TextureAtlas atlas;
atlas = new TextureAtlas(Gdx.files.internal("packedimages/pack"));

Lo que hace  TextureAtlas es leer el fichero de texto "pack" y cargar todas las paginas de imagenes que el "pack" referencia.

Y luego para explotarlo y pintar tenemos varias opciones, podemos usar TextureAtlas.AtlasRegions  que son TextureRegions que es un trozo de textura.
AtlasRegion region = atlas.findRegion("imagename");//findRegion ES MUY LENTO  es mejor guardar el valor devuelto.
The coordinate system used has its origin in the upper left corner with the x-axis pointing to the right and the y axis pointing downwards."

Otra opción es usar Sprites.
Sprite sprite = atlas.createSprite("otherimagename");//instancia un nuevo sprite
Si destruimos  el textureAtlas tambien nos cargamos todas las paginas de texturas.

http://www.badlogicgames.com/forum/viewtopic.php?f=11&t=2679


Como hacer cosas especificas de Android

Usando libgdx tenemos tres proyectos pero todo el codigo lo metemos en uno de ellos.
En ese proyecto podemos usar las librerias de Java y las de libgdx.
¿Pero y si queremos usar algo especifico de android?

En el proyecto principal: (donde esta la chicha)
Creas un interface . Aqui meteremos la declaración de los métodos que usaremos en Android.
En la clase que implemente ApplicationListener (en la "main" por decirlo así) deberá extender  el interface que hemos declarado.
En el proyecto android:
Creas una clase que implemente ese interface en el proyecto de Android. Aqui ya metes todo
lo especifico de Android.

Todo esto esta mejor explicado en inglés aqui:
http://code.google.com/p/libgdx-users/wiki/IntegratingAndroidNativeUiElements3TierProjectSetup#Steps_in_loose_order



TexturePacker

Es una utilidad para crear SpriteSheets que tienen la gracia de que no tendremos que estar cargando distintas texturas. Cosa que enlentece el juego.
Usaremos esta utilidad  para recortar "trozos" de una textura grande donde estan mapeadas
varias imagenes mediante un fichero de texto.
Tiene una gui que te puedes bajar o bien lo puedes usar directamente en tu programa importando lo siguiente:
 import com.badlogic.gdx.tools. imagepacker.TexturePacker;
 import com.badlogic.gdx.tools. imagepacker.TexturePacker.Settings;


Como se usa:
En el main de el proyecto de escritorio, el Jogl o el Lwjgl metemos lo siguiente:

        Settings settings = new Settings();
        settings.padding = 0;
        settings.minHeight = 256;//estos tamaños a elegir
        settings.minWidth = 256;
        settings.maxWidth = 1024;
        settings.maxHeight = 1024;
        settings.incremental = true;
       
        TexturePacker.process(
                settings, 

 "C:/tuworkspace/Nombredelproyecto/assets/data/directorio_inputa_empaquetar/"                          "C:/tuworkspace/Nombredelproyecto/assets/data/directorio_output_empaquetado/");

      /*  Y aqui ya iría:
      new JoglApplication(...
      */

Con esto nos crea varios SpriteSheets y un fichero de texto llamado pack que contiene algo así:
    nombrespritesheet.png
    format: RGBA8888
    filter: Nearest,Nearest
    repeat: none
    nombreimagen
        rotate: false
        xy: 0, 0
        size: 76, 76
        orig: 76, 76
        offset: 0, 0
        index: -1
        ....

http://code.google.com/p/libgdx/source/browse/trunk/extensions/gdx-tools/src/com/badlogic/gdx/tools/imagepacker/TexturePacker.java

miércoles, 7 de diciembre de 2011

Como comunicarse con la red local usando UDP II Cola bloqueante en Java

La idea es cada vez que se reciba un mensaje meterlo en una cola de mensajes recibidos.
Y otro hilo irá sacandolos de allí y haciendo lo que tenga que hacer segun el mensaje que haya llegado. En esta web lo explican:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html

class Producer implements Runnable {
   private final BlockingQueue queue;
   Producer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
       while(true) { queue.put(produce()); }
     } catch (InterruptedException ex) { ... handle ...}
   }
   Object produce() { ... }
 }
 class Consumer implements Runnable {
   private final BlockingQueue queue;
   Consumer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
       while(true) { consume(queue.take()); }
     } catch (InterruptedException ex) { ... handle ...}
   }
   void consume(Object x) { ... }
 }
 class Setup {
   void main() {
     BlockingQueue q = new SomeQueueImplementation();
     Producer p = new Producer(q);
     Consumer c1 = new Consumer(q);
     Consumer c2 = new Consumer(q);
     new Thread(p).start();
     new Thread(c1).start();
     new Thread(c2).start();
   }
 }

Como comunicarse con la red local usando UDP I

Para poder hacerlo hay que usar hilos ya que si no estariamos bloqueando la ejecución del programa.
Por lo tanto no hay mas huevos que usar hilos. Como no tengo ni puta idea de como se usan los hilos en Java ni en Android porque vengo de .NET  C# me toca empollarmelo.
http://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html
Ejemplo:
public class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }

    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}

martes, 29 de noviembre de 2011

Java: Como documentar los programas

La documentación se genera del archivo fuente, por lo que es necesario utilizar los comentarios especiales para JavaDoc:
/**
* Esto significa documentacion para JavaDoc
*/
Palabra reservada     Versión     Descripción
@author     1.0     El autor del método, clase.
@deprecated 1.0     El método ha sido reemplazado por otro.
@exception  1.0     La excepción que puede generar.
@param      1.0     Después viene el parámetro, esto se hace para documentar todos los parámetros que requiere el método.
@return     1.0     El valor que regresa
@see        1.0     Una referencia a otra clase o método de utilidad
@since      1.1     La versión desde que se incluye.
@throws     1.2     Es un sinónimo para @exception.
@version    1.0     La versión del método, clase.

viernes, 25 de noviembre de 2011

Problema Arrancando la versión Android del juego

He tenido muchos problemas para poner en marcha el juego en emulador de Android.
Siguiendo las explicaciones de esta página web:
 http://code.google.com/p/libgdx/wiki/ProjectSetup
me he creado tres proyectos, uno donde se mete todo el código otro que simplemente ejecuta ese código en el escritorio y otro para ejecutarlo en Android.

Bueno pues en escritorio iba perfectamente y en Android no habia manera de que funcionase.
Mirando mil foros la gente recomendaba aumentar la memoria de la maquina virtual del emulador que estuvieramos usando.¿Como?
Boton derecho en el proyecto Android -> Run Configurations ->Android Application(en la parte izquierda)->Target
(en la parte derecha)
seleccionamos la maquina virtual que vayamos a usar y en la parte de abajo pone : Additional emulator command line options
ahi escribimos "-partition -size 1024" (sin comillas, claro)

Pero lo que ha hecho que me funcionara ha sido cambiar la version de la JRE System Library.
Yo tenia puesta la JavaSE1.7 y hay que cambiarla a  JavaSE1.6
Todo esto se cambia en el proyecto principal donde está todo el código.
Botón derecho ->Proiedades->Java BuildPath->Libraries-> Seleccionamos JavaSE1.7 y pinchamos Edit...
Luego en Execution Enviroment lo cambiamos en la combobox y recompilamos.

Y con esto  ya funciona en Android :P

lunes, 21 de noviembre de 2011

Resolución del dispositivo destino/ Aspect Ratio

¿Como cambio la resolución de mi juego usando una cámara ortográfica?
En el constructor:
 new JoglApplication(

   new MyLibgdxApplication(),
   "title", 
   480, 
   800, 
   useGL20)
y luego en la OrthoGraphicCamera  se hace:

 int ancho = Gdx.graphics.getWidth();
 int alto = Gdx.graphics.getHeight();

Como usar las Clases Screen y Game de libGDX

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Screen;

Para crear una  aplicación libgdx siempre hay que implementar un interfaz ApplicationListener. Para ello se pueden usar las clases Game y Screen.

La clase Game (Juego)
Creamos una clase que extienda Game que a su vez implementa ApplicationListener. Esta clase se podría decir que es la clase "Main". El punto de arranque del proyecto  libGDX. El método Create() esta ahí y después de llamar a  Create() el siguiente paso es moverse a una pantalla donde pintar. Para ello hay que hacer game.setScreen(screen);

La clase  Screen (Pantalla)
Nos creamos las clases que implementan Screen y las usamos como mini-ApllicationListeners. Cada una de ellas tiene su render(), pause(), resume(), and resize(), que serán llamados cuando se llamaría a los métodos de  ApplicationListener.Además tiene otros dos métodos hide()  y show().

¿Como funciona esto?

Cuando se llama a setScreen(screen) la pantalla que esté en uso llama a  hide(), la nueva pantalla se convierte en la pantalla actual y se llama a su método show(). Apartir de esto en cada frame se llama al método render de la nueva pantalla actual.
El método dispose() de las pantallas nunca es llamado automaticamente cuando se llama al método  dispose() del  ApplicationListener sino que se llama a  screen.hide()

Consejos:

Es mejor tener una sola instancia de cada pantalla para todo el ciclo de vida del juego. Así no se crean nuevos objetos Screen en cada cambio de estado y nos ahorramos llamadas al recolector de basura.

Cada pantalla debería tener una referencia a la instancia de  Game para poder cambiar de una pantalla a otra.


El interface ApplicationListener y crear la aplicación


Es el punto de entrada principal de cualquier proyecto libGDX. La Aplicacion determina la plataforma objetivo y el destino gráfico
donde se desplegará la aplicación. Escritorio lwjgl and jogl y Android.
Para crear una Aplicacion libGDX hay que implementar antes el Application Listener.

Una Implementación de  ApplicationListener:

public class MyGame implements ApplicationListener {
        public void create () {
                // STUB
        }

        public void render () {
                // STUB
        }

        public void resize (int width, int height) {
                // STUB
        }

        public void pause () {
                // STUB
        }

        public void resume () {
                // STUB
        }

        public void dispose () {
                // STUB
        }
}

Luego para crear una aplicacion de escritorio usando lwjgl (Lightweight Java Game Library )


Es el punto de entrada principal de cualquier proyecto libGDX. La Aplicacion determina la plataforma objetivo y el destino gráfico
donde se desplegará la aplicación. Escritorio lwjgl and jogl y Android.
Para crear una Aplicacion libGDX hay que implementar antes el Application Listener.

Una Implementación de  ApplicationListener:

public class MyGame implements ApplicationListener {
        public void create () {
                // STUB
        }

        public void render () {
                // STUB
        }

        public void resize (int width, int height) {
                // STUB
        }

        public void pause () {
                // STUB
        }

        public void resume () {
                // STUB
        }

        public void dispose () {
                // STUB
        }
}

Luego para crear una aplicacion de escritorio usando lwjgl (Lightweight Java Game Library )

import com.badlogic.gdx.backends.lwjgl.LwjglApplication;

public class MyDesktopGame {
        public static void main(String[] args) {
                new LwjglApplication(new MyGame(), "My Game", 480, 320, false);
        }
}

Ejemplo para crear  una aplicacion de escritorio usando jogl (Java Binding for the OpenGL API, and is designed to provide hardware-supported 3D graphics to applications written in Java. )

import com.badlogic.gdx.backends.jogl.JoglApplication;

public class MyDesktopGame {
        public static void main(String[] args) {
                new JoglApplication(new MyGame(), "My Game", 480, 320, false);
        }
}

En Android:
public class MyAndroidGame extends AndroidApplication {
    /** Called when the activity is first created. */
    @Override
    public void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initialize(new MyAndroidGame(), false);
    }
}
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;

public class MyDesktopGame {
        public static void main(String[] args) {
                new LwjglApplication(new MyGame(), "My Game", 480, 320, false);
        }
}

Ejemplo para crear  una aplicacion de escritorio usando jogl (Java Binding for the OpenGL API, and is designed to provide hardware-supported 3D graphics to applications written in Java. )

import com.badlogic.gdx.backends.jogl.JoglApplication;

public class MyDesktopGame {
        public static void main(String[] args) {
                new JoglApplication(new MyGame(), "My Game", 480, 320, false);
        }
}

En Android:
public class MyAndroidGame extends AndroidApplication {
    /** Called when the activity is first created. */
    @Override
    public void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initialize(new MyAndroidGame(), false);
    }
}

miércoles, 16 de noviembre de 2011

Aplicaciones libGDX II

El interfaz Aplicación provee de unos modulos para graphics, audio, input e i/o a ficheros.

Graphics: Métodos paara mostrar por pantalla. Esto se consigue a través de  OpenGL ES 1.0, 1.1 o 2.0 dependiendo de la plataforma destino.

 Audio:Atraves de la  Java Sound API en escritorio y de la Android media framework de Android si la plataforma destino es un dipositivo Android.

 Input: se pueden consultar las entradas del usuario del teclado, pantalla tactil, ratón y acelerométro.
Tambien se pude implementar  un InputProcessor y usarlo con setInputProcessor(InputProcessor) para recibir eventos de entrada.
   
Files: para accceder a ficheros externos e internos. Los internos son los que están próximos a la aplicación. En Android son los Assets
En el caso de aplicaciones de escritorio el classpath es donde primero se mira.
 Los ficheros externos en el caso de Android  son lo que estan en la tarjeta SD. En el caso de escritorio, las que estan en el directorio HOME del usuario. Es preferible no usar rutas absolutas de archivo.
 
Application tiene métodos para para consultar información específica acerca del sistema operativo donde se ejecuta la aplicación.
Application tiene un metodo para obtener logs en el caso de escritorio se imprime por la salida estandar y el caso de android por
el LogCat.


lunes, 14 de noviembre de 2011

Prestaciones Briconsejos

El Recolector de basura, Hay que evitarlo todo lo que se pueda.
¿Como?
  Evitar la creación de objetos
    No usar iteradores.
    No usar las colecciones Set ni Map usar en cambio SparseArray
    No concatenar strings con el +  usar un StringBuilder
    No usar Integer sino int, no Boolean sino boolean, no Long sino long
    Usar métodos estáticos
    Usar campos en vez de getters y setters
    Meter las variables que mas se usen dentro de métodos en vez de en    campos




Usando SurfaceView

Esto es otro tipo de vista que es mas directa que una Vista normal, esta por decirlo así mas cerca del hardware.
Su ventaja es que usandola no utilizamos para nada la UI del sistema operativo Android.
Para ello debemos pintar en pantalla en otro hilo y ahi es donde usar la Vista  Superficial "SurfaceView " tiene su utilidad.
¿Como se hace?
    SurfaceHolder surfaceholder = surfaceView.getHolder();
        // del
surfaceholder saldrá la SurfaceView,pero noinmediatamente
        // para saber si ya esta creado debemos hacer :

        boolean surfaceYaCreada;
        surfaceYaCreada = surfaceholder.getSurface().isValid();
Luego podremos asegurarlo:
    Canvas SurfaceHolder.lockCanvas();
    // aseguramos el canvas, ya que estamos tratando con hilos y devuelve un canvas que podemos usar
    // para pintar en un buffer auxiliar, no en pantalla
    SurfaceHolder.unlockAndPost(Canvas canvas);
    // se suelta el canvas y se manda a pantalla lo que habia en el buffer auxilar


Atención a:
Recordar que la SurfaceView no se crea instantaneamente con "surfaceView.getHolder()"
La vista superficial se destruye cuando la actividad es pausada "onPause" y se recrea cuando es continuada "onResume"

Nota:
Volatile en Java se usa para indicar que el valor de la variable va a ser modificado por varios procesos.
El valor de la variable no sera almacenada el la memoria asociada al proceso sino que es tara en la memoria
de acceso "general". El acceso a la variable será como si estuviera en un bloque sincronizado.
Cualquier declaracion en la que se haga refernecia a algo declarado volatile será ejecutado en orden, el compilador no podra cambiar el orden.




viernes, 11 de noviembre de 2011

Pintando Texto

La clase necesaria para cargar las fuentes se llama Typeface y tiene métodos estáticos para cargar fuentes
TrueType desde el directorio /assets.
    Typeface fuente = Typeface.createFromAsset(context.getAssets(), "fuente.ttf");
Si la fuente no existe no lanza execpcion asi que hay que terne en cuenta que nos puede fallar aquí el programa y no nos dariamos cuenta.
Ahora asignamos el TypeFace de una instancia de Paint. Vamos como si le asignáramos un pincel que fuera una fuente o algo así.
    paint.setTypeFace(font);
Asignamos el tamaño de la fuente.
    paint.setTextSize(30);
Y ya podemos pintar el texto por pantalla por medio del método draw de un Canvas.
    canvas.drawText("Hola Mundo", 100, 100, paint);




Ejemplo carga y pintado de imagenes


package com.pruebas.androidgames;

//estos dos imports son para cargar los ficheros de imagen
import java.io.IOException;
import java.io.InputStream;

import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.util.Log;

/**
 * @author Fran1
 * Ejemplo de cargar una imagen y mostrarla en pantalla
 *
*/
public class Prueba extends Activity
{           
    //creamos nuestra vista
    class RenderView extends View
    {
        //imagenes que usaremos
        Bitmap fotito;
                //rectangulo destino
        Rect dstRect = new Rect();
        //constructor
        public RenderView(Context context)
        {
            // llamamos al constructor del padre.
            super(context);
            // implementación de la parte personalizada.
            try
            {
                // intentaremos cargar un archivo de imagen y mostralo.
                // gestor para cargar recursos graficos, sonidos etc.
                AssetManager assetManager = context.getAssets();
                // stream con el fichero de imagen.
                InputStream inputStream = assetManager.open("fotito.png");
                // asignamos el bitmap por medio de la clase estatica BitmapFactory y el inputstream con el fichero.
                fotito = BitmapFactory.decodeStream(inputStream);
                // cerrar el stream, liberar recursos.
                inputStream.close();
                // mostramos la configuración.
                Log.d("bobargb8888.png", fotito.getConfig().toString());
            }
            catch(IOException ioe)
            {
               
            }
            finally
            {
                // habria que cerrar el filestream.
            }
        }
        @Override
        protected void onDraw(Canvas dstCanvas) {
            // TODO Auto-generated method stub
            super.onDraw(dstCanvas);
            //rectangulo destino
            dstRect.set(50,50,300,300);
            dstCanvas.drawBitmap(fotito, null, dstRect, null);
            invalidate();
        }       
    }
   
    // clase principal de nuevo, la que usa el renderview
    @Override
    public void onCreate(Bundle estadoGuardadoBundle)
    {
        super.onCreate(estadoGuardadoBundle);
        //quitar el titulo de la ventana.
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        //poner en modo pantalla completa.
        getWindow().setFlags(
                WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        //asignar la vista, es decir lo que saldrá por pantalla.
        setContentView(new RenderView(this));       
    }
}


Source not found

Hasta los huevos de ver esto:







Solución aquí:
http://android.opensourceror.org/2010/01/18/android-source/
Aqui para bajar otros sources en .zip (hasta la 2.2)
http://mobilebytes.wordpress.com/2010/06/30/classes-source-for-eclipse/

Pintar formas en un Canvas

 
import android.graphics.Paint;
import android.graphics.Paint.Style;

Paint pintar = new Paint();
protected void onDraw(Canvas canvas)
{
            super.onDraw(canvas);
            // pinta todo el fondo de un color (blanco en este caso)
            canvas.drawRGB(255,255,255);
                               
            //tamaño del canvas
            int altura = canvas.getHeight();
            int anchura = canvas.getWidth();
           
            // ancho del pincel
            pintar.setStrokeWidth(8);
           
            // pintar una linea
            canvas.drawLine(0, 0, anchura, altura,pintar);
           
            // pintar rectangulo
            canvas.drawRect(0, 0, anchura/4, altura,pintar);
           
            // pintar circulo
            canvas.drawCircle(anchura/2, altura/2, 100, pintar);
           
            // pintar punto
                canvas.drawPoint(1f, 1.0f, pintar);
           
            //ajustes rapidos del pincel   
            pintar.setColor(Color.RED);
            pintar.setStyle(Style.STROKE);
            pintar.setStyle(Style.FILL);
           
            invalidate();           
        }   


Atajos de teclado en Eclipse II

search/replace global entre ficheros
    Elije el texto
     "Search" menu, selecciona "File...". Esto saca el dialogo "Search"
    Bajo del  dialogo pulsa "Replace..."

CTRL + H     Carga la ventana de búsqueda
CTRL + E     Acceso a los ficheros que ya están abiertos
CTRL + O     Acceso a los atributos y métodos de esa clase
CTRL + O (2 veces)     Igual que el anterior pero añadiendo los atributos y métodos de las clases padre
CTRL + L     Acceso a la línea indicada
CTRL + K     Rastrea la variable seleccionada
CTRL + F     Buscar / Reemplazar una palabra
CTRL + D     Eliminar la fila
CTRL + SUPR     Eliminar la siguiente palabra
CTRL + RETRO     Eliminar la anterior palabra
CTRL + MAY + SUPR     Eliminar hasta el final
CTRL + Q     Volver a la anterior pestaña de edición
CTRL + 3     Cargador de vistas
CTRL + MAY + F     Formatea el texto según lo configurado
CTRL + MAY + S     Guarda todos los documentos abiertos
CTRL + MAY + O     Organizador de imports (añadiéndolos si faltan)
CTRL + MAY + T     Buscador de tipos en el workspace
CTRL + MAY + R     Acceso a la búsqueda de recursos
CTRL + 7     Comenta el texto seleccionado  







jueves, 10 de noviembre de 2011

Atajos de Teclado Eclipse

Auto Completado:
- Control + Space Bar

Auto Imports:
Pones el nombre del metodo y te lo marca en rojo como que no sabe a que clase pertenece.
- Control + Shift + O
Esto te organiza los imports, te incluye los necesarios y te quita los que no usas.

Generar Getters y Setters:
Botón derechoy ‘Source’ -> ‘Generate Getters and Setters’

Override / Implement methods:
Botón derecho y ‘Source’ -> ‘Override/Implement Methods.’


Referencias:
Para saber donde se usan métodos o variables o clases pinchar el nombre y
- Control + Shift + G
o bien Botón derecho y  ‘References -> workspace.’


Pintar en pantalla completa.

Para configurar la pantalla completa hacemos lo siguiente:
import android.view.Window;
import android.view.WindowManager;
public void onCreate(Bundle estadoGuardadoBundle)
{
   requestWindowFeature(Window.FEATURE_NO_TITLE);
   getWindow().setFlags(
         WindowManager.LayoutParams.FLAG_FULLSCREEN,
         WindowManager.LayoutParams.FLAG_FULLSCREEN);
   super.onCreate(estadoGuardadoBundle);
}
Para pintar en pantalla debemos derivar desde la clase Vista "View " y sobrecargar el método onDraw(). A este método lo llama el sistema operativo Android tantas veces como la vista necesite redibujarse .
Esto es cuando es creada, continuada o algo que la tapaba se ha hecho invisible.
Un ejemplo de implementación:
   class PintaView extends View 
     {
       public PintaView(Context context)
       {
          super(context);
       }
       protected void onDraw(Canvas canvas)
       {
         // aquí se metería el código para pintar lo que queramos
         invalidate();
         // con esto hacemos que android repinte mas o menos  "continuamente"realmente pinta cuando tiene tiempo para ello.
        }
   }

El constructor de Activity

Todas las actividades deben implementar el método abstracto Activity.onCreate()
que es llamado una vez por el sistema operativo Android cuando la aplicación es arrancada por primera vez. Hay que incluir una llamada al método onCreate de la clase padre.
Por ejemplo:
   @Override
   public void onCreate(Bundle estadoGuardado) {
   super.onCreate(estadoGuardado);


Programacion gráfica

Lo primero es usar un Wake Lock para que no se apague la pantalla cuando estemos un rato sin tocar nada.
Para ello hay que ir al AndroidManifest.xml y añadir android.permission.WAKE_LOCK en permissions.

Hay que importar:
   import android.os.PowerManager;
   import android.os.PowerManager.WakeLock;   

Luego, para instanciarlo, metemos lo siguiente en el método
  onCreate(Bundle savedInstanceState):
  PowerManager gestorEnergia = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
   WakeLock wakeLock = gestorEnergia.newWakeLock(PowerManager.FULL_WAKE_LOCK, "Mi wakeLock");
   
Una vez instanciado, para decirle al sistema que no apague la pantalla, cpu, ni teclado:
   wakeLock.acquire()
Esto se mete en el método onResume() ;
para liberar el wake lock y que la pantalla siga su comportamiento normal regido por el sistema hacemos
   wakelock.release();
Y lo metemos en el método onPause();


miércoles, 9 de noviembre de 2011

Como cambiar de pestaña en Eclipse

Con Alt+Tab no cambia, con Ctrl + Tab tampoco !Vaya mierda¡
Total que a buscar ... y el resultado es:
  Ctrl + Page Up, Ctrl + Page Dn

Gracias a este hombre, mujer o ente informe.
  http://blog.webandnow.com/blog/2008/02/21/eclipse-ide-alt-tab-functionality/


Música

Para mandar un tochazo de fichero de música hay que partirlo en cachitos, formar un flujo
y mandarselo al chip de audio. ¿Como? Con la clase MediaPlayer.
   MediaPlayer mediaPlayer = new MediaPlayer();
¿Que fichero tiene que reproducir?¿Como se lo digo?
Con un AssetFileDescriptor
   AssetFileDescriptor descriptor = assetManager.openFd("musiquita.ogg");
   mediaPlayer.setDataSource(

                   descriptor.getFileDescriptor(),
                   descriptor.getStartOffset(),
                   descriptor.getLength());
   mediaPlayer.prepare();

Una vez hecho todo esto ya se puede:
   reproducir el fichero =>   mediaPlayer.start();
   pausar =>                  mediaPlayer.pause();
   continuar =>               mediaPlayer.resume();
   parar =>                   mediaPlayer.stop();
   cambiar el volumen =>      mediaPlayer.setVolume(1, 1); de 1f a 0f
   
Para comprobar que se ha terminado de reproducir la canción no subscribimos así:
     mediaPlayer.setOnCompletionListener(listener);
Y si queremos comprobar como va la reproducción hacemos "polling" :D
(hacer polling tiene otras acepciones pero en este caso no tiene nada de porno)
   boolean isPlaying = mediaPlayer.isPlaying();
Finalmente para liberar recursos usaremos:
   mediaPlayer.release();
   
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.MediaPlayer;



Efectos de Sonido

Trocitos cortos de sonido, se usa la clase SoundPool.
    SoundPool soundPool = new SoundPool(
        20, //indica cuantos sonidos como MÁXIMO queremos reproducir al   mismo tiempo
        AudioManager.STREAM_MUSIC, //el canal de audio a usar
        0 //de momento esto no sirve para nada);
       
Para cargar el efecto de sonido a memoria se usa pasandole un AssetFileDescriptor al método SoundPool.load(). El AssetFileDescriptor sale del AssetManager ¿Como?
Ejemplo de carga de un .OGG
   AssetFileDescriptor descriptor = assetManager.openFd("sonidito.ogg");
   int soniditoId = soundPool.load(descriptor, 1);
     // el entero que devuelve es el manejador "handle" del efecto de sonido cargado
   
Una vez tenemos el numerito identificador del sonido para reproducirlo hay que hacer:
   soundPool.play(                                                                soniditoId, // identificador del sonido
        1.0f,  //volumen canal izdo de 0f a 1f
        1.0f, //volumen canal dcho de 0f a 1f
        0, //prioridad (no se usa)
        0,//cada cuanto se debe repetir en bucle (poner 0)
        1 //velocidad de reproduccion );
   
Para liberar memoria cuando no se use el efecto:
   soundPool.unload(soniditoId);
Para liberar memoria cuando no se vaya a usar ningun efecto:
   SoundPool.release()

Acceso a la tarjeta SD


File directorioSD = Environment.getExternalStorageDirectory();

public void onCreate(Bundle savedInstanceState)
{
 super.onCreate(savedInstanceState);
 // para mostar resultados
 TextView textView = new TextView(this);
 setContentView(textView);
 // para ver si la SD esta montada
 String state = Environment.getExternalStorageState();
 if (!state.equals(Environment.MEDIA_MOUNTED))
 {
    textView.setText("No external storage mounted");
 }
 else
 {
    // para ver el directorio de la SD que usaremos
    File externalDir = Environment.getExternalStorageDirectory();
        // creamos un fichero nuevo para probar
    File textFile = new File(externalDir.getAbsolutePath() + File.separator + "text.txt");
    try
      {
           //escribimos en el fichero de texto
      writeTextFile(textFile, "This is a test. Roger");
            //leemos del fichero de texto
      String text = readTextFile(textFile);
            //mostramos el texto en el view
      textView.setText(text);
      if (!textFile.delete())
          {
              //borramos el fichero
        textView.setText("Couldn't remove temporary file");
      }
    } 
    catch (IOException e)
    {
      textView.setText("something went wrong! " + e.getMessage());
  }
 }
}


martes, 8 de noviembre de 2011

Manejo de Ficheros

Los ficheros los meteremos en el directorio assets
Para tener acceso a los ficheros que hemos metido aquí usaremos la clase AssetManager.
  AssetManager assetManager = context.getAssets();
El interfaz Context esta implementado por la clase Activity asi que lo llamaremos desde ella.

InputStream inputStream = assetManager.open(
"dir1/dir2/nombrefichero.txt");
Este método devuelve un InputStream.
Ejemplo:
public class PruebaAssets extends Activity
{
    @Override public void onCreate(Bundle savedInstanceState)
    {
            super.onCreate(savedInstanceState);
            TextView textView = new TextView(this);
            setContentView(textView);
            AssetManager assetGestor = getAssets();
            InputStream inputStream = null;
            try
            {
                inputStream = assetGestor.open("textos/mifichero.txt");
                String text = loadTextFile(inputStream);
                textView.setText(text);
            }
            catch (IOException e)
            {
                textView.setText("Couldn't load file");
            }
            finally
            {
                if (inputStream != null)
                try
                {
                    inputStream.close();
                }
                catch (IOException e)
                {
                    textView.setText("Couldn't close file");
                }
            }
    }

}

Leyendo el acelerómetro

¿Como se hace?
Registrando un suscribindose a un Listener ¿a cual? a SensorEventListener

SensorEventListener tiene dos métodos:
   public void onSensorChanged(SensorEvent event);
   public void onAccuracyChanged(Sensor sensor, int accuracy);
El primero es llamado cuando llega el evento. El segundo cuando cambia  la precisión. Sólo nos interesa el primero.

Primero se comprueba que efectivamente el dispositvo tien acelerométro.
¿Como? Así:
SensorManager manager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
boolean hasAccel = manager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() > 0;

Para subscribirnos al SensorEventListener
  Sensor sensor = manager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0);
  boolean success = manager.registerListener(                                                listener,                                                                sensor,
                    SensorManager.SENSOR_DELAY_GAME);                                               
SensorManager.SENSOR_DELAY_GAME es una constante que especifica cada cuanto debe actualizarse el sensor con el ultimo estado del acelerómetro.


SensorManager.registerListener() devuelve un booleano que hay que consultar para saber si hemos tenido exito
o no. Una vez registrado el escuchador recibiremos SensorEvents en el método SensorEventListener.onSensorChanged().
Este método sólo es llamado cuando el estado del sensor ha cambiado.

¿Como procesarlo?
Con SensorEvent.values que es un array de floats público donde:
    SensorEvent.values[0] => Eje X
    SensorEvent.values[1] => Eje Y
    SensorEvent.values[2] => Eje Z



public class PruebaAcelerometro extends Activity implements SensorEventListener
{
        TextView textView;
        @Override    public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            textView = new TextView(this);
            setContentView(textView);
            SensorManager manager = (SensorManager)
            getSystemService(Context.SENSOR_SERVICE);
            if (manager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() == 0)
            {
                textView.setText("No accelerometer installed");
            }
            else
            {
                Sensor accelerometer = manager.getSensorList(
                Sensor.TYPE_ACCELEROMETER).get(0);
                if (!manager.registerListener(this, accelerometer,
                        SensorManager.SENSOR_DELAY_GAME))
                        {
                                textView.setText("No puedo registrar el escuchador del sensor");
                        }
            }
        }

    @Override public void onSensorChanged(SensorEvent event)
    {
        float x =event.values[0];
        float y =event.values[1];
        float z =event.values[2];
    }
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}


Usar el Acelerometro con el emulador de Android

Para poder usar el acelerometro hayq ue bajarse un par de programas.
Uno se ejecuta en el PC y otro se instala en el emulador. Ambos se comunican supongo que por TCP.

Connecting the SensorSimulator with the Android emulator
    http://code.google.com/p/openintents/wiki/SensorSimulator
    Download the latest sensorsimulator-x.x.x.zip from the download tab and unzip (if you didn't already).
    Start bin/sensorsimulator-x.x.x.jar (Java standalone application).
    Install bin/SensorSimulatorSettings-x.x.x.apk on your Android emulator.
  http://blog.freewarelovers.com/2010/08/how-to-install-apk-files-on-android.html
  Ok, now start the console ("Start -> Run... -> type 'cmd'" for Windows computers). Type-in the following command: adb install $APK where $APK is the name of the APK file. For example: adb install Snake.apk

Launch SensorSimulator on the emulator.
    Enter IP address and socket (port) number into the emulator as shown by the SensorSimulator (see below).
Go to Sensors Tab in the java simulator and choose the sensors you want to enable.
Press Connect on the emulator (second tab of the settings activity).
Now you should see the sensor data (see below). With a small delay, they are in sync with the SensorSimulator numbers.
Try moving the SensorSimulator phone around with the mouse: The numbers will change in the SensorSimulator and on the Android phone.

Procesando Eventos de un sólo Toque

Se hace con interfaces de escuchadores, que es como Android nos informa de que ha ocurrido un toque.
Los eventos de toque son pasados mediante la implementación de un interfaz OnTouchListener que debemos subscribir a un View.
  android.view.View.OnTouchListener
 Class Overview
 Interface definition for a callback to be invoked when a touch      event     is dispatched to this view. The callback will be invoked before the touch event is given to the view.
 Summary
 Public Methods
  abstract boolean onTouch(View v, MotionEvent event)
  Called when a touch event is dispatched to a view.
 Public Methods
  public abstract boolean onTouch (View v, MotionEvent event)
       
Called when a touch event is dispatched to a view. This allows listeners to get a chance to respond before the target view.
  Parameters
  v     The view the touch event has been dispatched to.
  event     The MotionEvent object containing full information about the event.
  Returns
   True if the listener has consumed the event, false otherwise.


El interfaz OnTouchListener  sólo tiene un método:
  public abstract boolean onTouch (View v, MotionEvent event)
El primer argumento es la Vista "View" a la cual se envian los eventos de toque.
El segundo, el MotionEvent es el que tiene la miga.

¿Como subscribimos la vista al OnTouchListener()?
Con el método View.setOnTouchListener
 public void setOnTouchListener (View.OnTouchListener l)
 Register a callback to be invoked when a touch event is sent to this view.
 Parameters
  the touch listener to attach to this view

El OnTouchListener será llamado antes de que sea mandado a la Vista en sí.  Lo que
haremos será procesarlo nosotros segun nos interese y luego avisar a la View de que hemos
recibido un onTouch. Devolviendo "true" al final del método para decirle que la hemos procesado
dentro del método o "false" para decirle al View que no la hemos procesado y debe hacerlo ella.

La instancia de MotionEvent tiene tres métodos que nos interesan:

MotionEvent.getX() y MotionEvent.getY(): las coordenadas x e y en las que se ha pulsado  relativas a la
view en la que estamos. Devuelve un float y la medida en es pixeles.
 These methods report
MotionEvent.getAction(): El tipo del evento toque
            MotionEvent.ACTION_DOWN
            MotionEvent.ACTION_MOVE
            MotionEvent.ACTION_CANCEL este no se da nunca
            MotionEvent.ACTION_UP

public class SingleTouchTest extends Activity implements OnTouchListener
{
    public void onCreate(Bundle savedInstanceState)
    {
    TextView textView = new TextView(this);
    textView.setOnTouchListener(this);
    setContentView(textView);
    }

    @Override public boolean onTouch(View v, MotionEvent event)
    {
        switch (event.getAction())
        {
                case MotionEvent.ACTION_DOWN:
                {};
                break;
                case MotionEvent.ACTION_MOVE:
                {};
                break;
                case MotionEvent.ACTION_CANCEL:
                {};
                break;
                case MotionEvent.ACTION_UP:
                {};
                break;
        }
        return true;
        }
}