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;
        }
}


Una actividad para leer pulsaciones del teclado

Se empieza declarando que la Actividad implementa el interfaz  OnKeyListener.
  public class PruebaLectorPulsacionesTeclado extends Activity implements OnKeyListener
Sobreescribimos el metodo onCreate de la actividad
  @Override public void onCreate(Bundle savedInstanceState)
y en él declaramos un TextView para mostar el texto.
  TextView textView = new TextView(this);
y le diremos que se "subscriba" a  OnKeyListener.
  textView.setOnKeyListener(this);
Para que reciba los eventos de teclado el textView debe tener el foco por lo tanto haremos
  textView.setFocusableInTouchMode(true);
  textView.requestFocus();

Despues debemos sobreescribir el método onKey de android.view.View.OnKeyListener
public abstract boolean onKey (View v, int keyCode, KeyEvent event)
Interface definition for a callback to be invoked when a key event is dispatched to this view. The callback will be invoked before the key event is given to the view. Called when a key is dispatched to a view. This allows listeners to get a chance to respond before the target view. Parameters
  v     The view the key has been dispatched to.
  keyCode     The code for the physical key that was pressed
  event     The KeyEvent object containing full information about the    event.
Returns
  True if the listener has consumed the event, false otherwise.

La implementación:
 @Override public boolean onKey(View view, int keyCode, KeyEvent event)
en él procesaremos dos eventos el .ACTION_DOWN y .ACTION_UP es decir cuando se pulsa y cuando se suelta la tecla. ¿Como se hace esto?
Con event.getAction()
    switch (event.getAction())
    {
        case KeyEvent.ACTION_DOWN:
        {};
        break;
        case KeyEvent.ACTION_UP:
        {};
        break;
    }
Este método debe devolver un booleano por lo que al final del método  pondremos
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
            return false;
    else
            return true;
¿Esto para que? Esa es la tecla de ir para atrás, lo que haria que salieramos de la aplicación.Si no hicieramos esto esa tecla no haria nada y no podriamos salir de la actividad con ella.

lunes, 7 de noviembre de 2011

Corolario del Ciclo de vida de una Actividad.


Siempre es llamado el todo onResume()  antes de entrar al estado "Running" .Por tanto si se ha llamado a onResume() sabremos que la actividad esta en marcha.

No podemos asegurar que se llame a onStop() o onDestroy()  puesto que despues del onPause()el S.O podria matar la actividad. Por lo tanto interesa sobrecargar el onPause() que seguro que se ejecutará.
Aqui se guaradaran todos los estados que nos interese no perder.

onDestroy() puede que no sea llamado nunca así que debemos llamar al método  Activity.isFinishing() dentro de onPause() para ver si la actividad va a morir despues del onPause()

Para resumir: sólo sobrecargamos onCreate(), onResume(), and onPause()
En onCreate(), configuramos la ventana y el componente UI donde pintamos y desde el que recibimos el input.
En onResume(), (re)arracancamoswe el bucle principal
In onPause(), pausamos el bucle principal y si Activity.isFinishing() devuelve true, guardamos los datos que nos interese a disco.

Actividad Ciclo de Vida


En Marcha: en este estado la actividad esta encima de las demás y interactua directamente con el usuario.
Pausada: Cuando la aplicación está activada y visible pero tiene algo que la cubre parcialmente.
Cuando esta pausada el sistema operativo puede matarla.

Parada: Esto ocurre cuando la actividad esta completamente cubierta por otra actividad y no esta visible.Tambien cuando se presiona el botón de "Home". En este estado el sistema puede matarla.

Los métodos protegidos que hay que sobrecargar para estar informados del
estado de la actividad.

Activity.onCreate(): Se llama cuandose arranca la actividad por primera vez.
Aquí se configuran los componentes UI y se enlaza con el S.O. Sólo se llama a esto una vez en el ciclo de vida de la actividad.

Activity.onRestart(): Se llama a esto cuando la aplicacion se pone en marcha despues
del estado Parado.Precedido de onStop().
Activity.onStart(): Llamado despues de onCreate() o cuando la actividad es continuada desde el estdo parado precededida de onRestart().
Activity.onResume(): Llamado despues de onStart() o cuando la actividad se pone en marcha despues del estado Pausa.
Activity.onPause(): Se llama a esto cuando la actividad entra al estado PauseHay que guardar el estado porque el sistema puede matar la actividad en este estado.
Activity.onStop(): Se llama a esto cuando la actividad entra al estado Parado. Precedido del estado Pausa.
Hay que guardar el estado porque el sistema puede matar la actividad en este estado.

Activity.onDestroy(): Esta se llama al final del ciclo de vida de la actividad. Es el último sitio en
el que podemos guardar el estado. Puede ser que no se llegue nunca aquí porque el sistema haya  matado la actividad
en el estado despues de una llamada a onPause() o onStop()

Aplicaciones con Varias Actividades


Una aplicación con varias actividades tien algo llamado una pila de actividades. Cada vez
que arrancamos una nueva actividad, esta se mete en la pila. Y cuando se cierra se saca
de la pila.
Al principio, todas las actividades de la aplicación, es decir todas las que estan pausadas en
la pila de actividades y la que está activa comparten la misma Máquina Virtual así como
el mismo mismo monticulo de memoria.
Si se usan variables estáticas, estas usaran memoria del monticulo tan pronto como sean
activadas. Como son campos estáticos estas sobreviviran a destrucción de la actividad
y tambien la recolección de basura. Esto puede llevar a fugas de memoria y por tanto es mejor
usar sólo una actividad para juegos simples.

viernes, 4 de noviembre de 2011

AccelerometerHandler must override a superclass method

Los ejemplos del libro no me iban, me he vuelto loco para encontrar la solución.
Haciendo esto no se arreglaba.
http://www.badlogicgames.com/wordpress/?p=1782

Window–>Preferences –> Android –> Busca el directorio del SDK Java
Botón derecho en cada proyecto Properties–>Elige Java Build Path a mano izquierda–>En la derecha Libraries –> Add Library –>JRE System Library–>Next , OK. Esto para cada proyecto

Al final encontré la solución en esta web:
http://blog.donnfelker.com/2010/07/06/android-must-override-a-superclass-method-errors/#respond
El problema era que por defecto se usaba el compilador 1.5 de Java.
Y en la 1.5 el parámetro @override solo se puede usar para superponer el metodo de una clase padre.
En Java 1.6 también se pueden superponer métodos de interfaces.

Por lo tanto hay que cambiar:
Window –> Preferences –> Java –> Compiler
Seleccionar 1.6 en Compiler Compliance Level
Darle a “Configure Project Specific Settings …" y  en project specific settings elige  1.6 en Compiler Compliance level.

Y con esto desaparecen los errores.

jueves, 3 de noviembre de 2011

Corolario del AndroidManifest.xml, pasos rapidos para crear el proyecto.

1. Crear un nuevo proyecto Android en el Eclipse.
2. Ponle nombre al proyectoy elige como objetivo de despliegue la SDK que quieras.
3. En el mismo diálogo pon el nombre del juego el package tendrá ese nombre y tambien lo sera de la actividad principal.
Poner el minimo de SDK  a la version 3, apretar "finish".
4. Abre AndroidManifest.xml.
5. InstallLocation = preferExternal para que instale en la SD.
6. debuggable= true para poder debugear
7. screenOrientation = portrait o = landscape
    configChanges= keyboard|keyboardHidden|orientation
8. <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
En el Eclipse te vas al permission editor le das a la U mayuscula verde de User Permissions luego a Add..
        luego en el combobox de la derecha se eligen WAKE_LOCK y WRITE_EXTERNAL_STORAGE
        y se le da a Guardar para que los añada.

9. <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="elmismoque pusimos en el segundo paso" />

En El AndroidManifest.xml V

Elemento <uses-sdk>
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="9"/>
Especifica el SDK mínimo que necesita la aplicación.

En El AndroidManifest.xml IV

Elemento <uses-feature>
En el Android Market se comparan las características del dispositivo que esta accediendo con lo que pone en los atributos de este elemento.
android.hardware.touchscreen.multitouch: para saber si el dispositivo tiene pantalla multitouch.
android.hardware.touchscreen.multitouch.distinct: todas las capacidades multitouch que tiene el dispositivo.
<uses-feature android:glEsVersion="0x00020000" required="true"/> hace que sólo dispositivos que soporten OpenGL ES 2.0 vean la aplicación.