viernes, 19 de octubre de 2012

Comandos de mercurial


HG INIT
Crea un repositorio.

HG ADD
Programa los ficheros que seran añadidos al repositorio. Estos no seran añadidos
hasta que se haga commit.

HG COMMIT
Guarda el estado actual de todos los ficheros al repositorio.

HG STATUS
Indica cuales son los ficheros de los que mercurial no sabe nada o ha
habido alguna modificacion depues del ultimo commit.


HG LOG
Muestra la historia de los cambios enviados al repositorio.

HG REVERT
Devuelve los ficheros al estado de la ultima version de commit.

HG UPDATE
Actualiza el directorio de trabajo a una revision en particular.

HG ROLLBACK
Deshace un commit si no se ha empujado("push") a nadie mas.

HG CLONE
Hace una copia de un repositorio completo.

HG PATHS
Da la lista de repositorios remotos conocidos.

HG PARENT
Muestra el change set padre del que estas trabajando.

HG BACKOUT
Sirve para borrar los cambios de un changeset.
Se asegura de que el directorio de trabajo esta limpio es decir que el output de
"HG status" esté limpio.
Va al changeset que hemos indicado en el parametro de backout y hace revert al
changeset anterior, luego hace commit.
   
HG HEADS
Muestra el ultimo changeset del respositorio actual.

HG INCOMING
Lista todos las diferenceia entre nuestra copia y el repositorio de que haremos pull.

HG OUTGOING
Lista los cambios del repositorio actual esperando a ser empujados.

HG PULL
Trae a nuestro repositorio los cambios desde otro repositorio.

HG PUSH
Empuja los nuevos cambios de este repositorio.

HG PATHS
Muestra una lista de los repositorios remotos conocidos.

jueves, 2 de agosto de 2012

Como pintar el fondo y los objetos. Cámaras.

Me ha pasado que tengo un fondo de 480 x 320 pixeles que muestro en los menus.
Sin embargo en la parte jugable, la cámara solo muestra 30x20. Y claro me salia
el fondo mal.
Despues de leer esto :
http://www.badlogicgames.com/wordpress/?p=1550
y esto (que está anticuado)
http://code.google.com/p/libgdx-users/wiki/Sprites
y esto:
http://androidnirvana.comule.com/wordpress/category/libgdx/

He llegado a la conclusion de  que usando dos cámaras la cosa funciona.
Al principio habia intentado cambiar los valores de una sola cámara y no me
funcionaba.

backgroundCamera = new OrthographicCamera(
ANCHOTOTAL,
ALTOTOTAL);
backgroundCamera.position.set(
CENTROANCHOTOTAL,
CENTROALTOTOTAL,
0f);

objectsCamera  = new OrthographicCamera(World.SCREEN_VIEW_WIDTH,World.SCREEN_VIEW_HEIGHT);
objectsCamera.position.set(
SCREEN_VIEW_WIDTH / 2f,
SCREEN_VIEW_HEIGHT / 2f,
0f);

Luego, a la hora de pintar cada vez que el spritebatch vaya a actuar se le aplica la
cámara.

batcher.begin()
backgroundCamera.update();
batcher.setProjectionMatrix(backgroundCamera.combined);
batcher.draw(
fondogeneral,
0f,
0f);
objectsCamera.position.x += 10f;
objectsCamera.update();
objetos,
batcher.setProjectionMatrix(objectsCamera.combined);
batcher.draw(
0f,
0f);
batcher.end()


martes, 31 de julio de 2012

Error generating final archive: Debug Certificate expired

Me ha salido esto hoy, mira tú, un error que todavia no habia visto.
La solución es cargarse el certificado que se usa para debug.
En mi caso (Windows 7) estaba en:
C:\Users\fran\.android\debug.keystore

lunes, 30 de julio de 2012

Acceder a una imagen pixel por pixel.


Para cargar la imagen y comprobar el color de cada pixel he usado un pixmap. Hay que tener cuidado 
con el formato de la imagen ya que si es RGB8888 tenemos tres bytes por pixel y si es RGBA8888 hay cuatro.


Este es el codigo:

public static void loadTexture (String levelfile)
{
try
{
Pixmap pixmap = new Pixmap(Gdx.files.internal(levelfile));

altura = pixmap.getHeight();
anchura = pixmap.getWidth();
tilefactory = new TileFactory();
tiles = new Tile[anchura][altura];

java.nio.ByteBuffer bb =  ByteBuffer.allocateDirect(altura * anchura * 3);
Pixmap.Format format = pixmap.getFormat();
  bb = pixmap.getPixels();

for (int i = 0; i < altura * anchura; i++)
{
int  r = (bb.get() & 0xff) / 255;
int  g = (bb.get() & 0xff) / 255;
int  b = (bb.get() & 0xff) / 255;
//bb.get();
if (format == Pixmap.Format.RGBA8888)
{
int  a = (bb.get() & 0xff) / 255;
}
if ((r != 0 && g != 0 && b != 0)); // es negro puro
procesaSegunColor(r,  g,  b, i, anchura, altura);
}
pixmap.dispose();
}
catch(Exception ex)
{
Gdx.app.log("error", ex.toString());
}
}

Ejemplo de nivel:


jueves, 26 de julio de 2012

Tile Maps (mapas de mosaicos) y cargadores de niveles III


El método para crear los niveles del juego que estoy usando al final no es ninguno de los anteriores :P

La idea es crear una imagen en la que cada pixel de ella represente un mosaico en el juego.
Compruebo el color de cada pixel y con un switch creo el tile correspondiente a ese color.
La gracia de esto es que echando un vistazo al la imagen que representa el nivel sabes como esta
estructurado. Lo malo que tiene es que es mas laborioso crear los niveles con el programa de dibujo pixel a pixel.













domingo, 22 de julio de 2012

Tile Maps (mapas de mosaicos) y cargadores de niveles II



Se me ocurrío meter cada nivel entre dos caracteres '<' y '>' y dentro meter
las tiles especiales.
Ejemplo:
<10,1,0; 20,1,0; 30,2,1>
Esto sería en la posición (x=10, y =1) hay una tile de tipo 0
Esto sería en la posición (x=20, y =1) hay una tile de tipo 0
Esto sería en la posición (x=30, y =1) hay una tile de tipo 1
Meter en cada linea de un fichero de texto un nivel de estos y luego parsearlo.
¿Como? Algo así(el codigo esta mal y ya no lo uso):

// Devuelve un array de strings con los todos los niveles
  private void  ParseFichero(String nivel)
  {
  char[] canivel = nivel.toCharArray();
char[] ca_aux = new char[World.WORLD_WIDTH];
  int indexca_aux = 0;
  int estado = 1;
 
listaniveles = new ArrayList<String>();
 
for (int i = 0; i < World.WORLD_WIDTH; i)
  {
  char c = canivel[i];
switch (c)
  {
  case ST_BEGIN_LEVEL:
  {
  estado = ST_IN_LEVEL;
ca_aux = new char[World.WORLD_WIDTH];
  indexca_aux = 0;
  }
  break;
  case ST_END_LEVEL:
  {
  ca_aux[indexca_aux] = '\0';
listaniveles.add(new String(ca_aux));
  }
  break;
  case ST_IN_LEVEL:
  break;
  }
  }
}

  public void ParseLevel (int numnivel)
  {
String nivel = listaniveles.get(numnivel).toLowerCase().trim();
  String[] astrtiles = nivel.split("\\;");
obstaculos = new ObstaculoNormal[astrtiles.length];
 
  for (int i = 0; i < astrtiles.length ; i)
  {
int x = Integer.parseInt(tiledataseparado[0]);
  int y = Integer.parseInt(tiledataseparado[1]);
  int type = Integer.parseInt(tiledataseparado[2]);
 
ObstaculoNormal obstaculo = new ObstaculoNormal(x, y, type);
obstaculos[i] = obstaculo;
  }
}

sábado, 21 de julio de 2012

Tile Maps (mapas de mosaicos) y cargadores de niveles I

Mi primer intento de crear un cargador de niveles tipo tilemap has sido usando ficheros de texto
Como la estructura de los niveles sería siempre parecida y el "suelo" sería la
fila de mas abajo del nivel, pensé guardar sólo los obstaculos y tiles especiales.

Otra manera de hacerlo con ficheros de texto seria incluir todas las tiles en el fichero.
Por ejemplo:
. : Tile vacia
# : Tile especial
_ : Tile suelo

Y crear un fichero de texto algo así:
..........
...#......
__________

y esto sería un nivel de 10 x 3 tiles. Pero lo ví muy coñazo para definir los niveles, así que
volví a mi idea de definir los niveles de otra manera. 

martes, 29 de mayo de 2012

Firmando el .apk de nuestro juego

Para hacer esto se utliza un programa que se llama jarsigner.exe. Este programita está en el siguiente path:
    C:\Program Files\Java\jdk1.7.0_04\bin\jarsigner.exe
(Si tienes otro jdk la ruta cambia, claro)

Para firmar el jar antes hay que generar la llave privada que usaremos en la firma. Para ello se usa otro
programa, keytool.exe.
    C:\Program Files\Java\jdk1.7.0_04\bin\keytool.exe

Ahora para crear la llave con keytool.exe hay que crear un almacen de llaves y dentro de ese almacen se crea la llave. Dentro de ese almacen se mete la llave y se identifica con un alias.
Ejemplo:
    keytool -genkey -v -keystore llavero.keystore -alias fralurbealias -keyalg RSA -validity 10000
Para firmar una app android la duración de la validez de la llave debe ser superior a 25 años.

Una vez tenemos la llave vamos a firmar el apk de la aplicación con el jarsigner. Deberia ser tan simple como hacer:
Ejemplo:
    jarsigner -keystore llavero.keystore juegecito.apk fralurbealias
Te pide la clave que le has metido antes al crear la llave y ya está.











Mas información en la web de android developer.

sábado, 12 de mayo de 2012

Usando Subclipse

Me he creado un directorio
  C:\EclipseRepositorio
luego boton derecho en la carpeta y con el TortoiseSVN he hecho:
  create repository here
En el Eclipse en la SVN Repository Exploring Perspective a mano izquierda boton derecho y  new repository location te pide una url, que le den morcila, yo le meto un directorio. Le he puesto:
  file:////C://EclipseRepository
No ha fallado nada, parece que funciona bien.

usando subclipse
Ahora primero a meter el proyecto al SVN:
Cierro la vista SVN Repository y abro la de Java.
En Package Explorer botón derecho en la carpeta del proyecto que quiero controlar mediante el SVN.
Ahí elijo Team->ShareProject me sale un dialogo y elijo SVN, Next y Finish ,ya está.
En el package explorer me ha marcado el proyecto con un símbolo de asterisco.





Ahora a ver como se hacen los commit y los updates.En Package Explorer botón derecho->Team ahora el menú es diferente y salen
un monton de cosas, a mi me da igual de momento solo commit,
Elijo Commit y en la Consola del Eclipse empieza a salir

  mkdir --parents -m "Initial import." [file:////C://EclipseRepository/AccesoAlServidor]
  checkout file:////C://EclipseRepository/AccesoAlServidor -r HEAD --depth=immediates --force
      Checked out revision 2.
  add -N C:\Workspaces\AccesoAlServidor\assets
      A         C:/Workspaces/AccesoAlServidor/assets
      ....
Todo perfecto, el icono del package explorer ha cambiado de asterisco a otra cosa que supongo indica que el repo está actualizado.







Esta web lo explica mejor que yo y en el idioma de Shakespeare.
http://www.informit.com/articles/article.aspx?p=517206&seqNum=2






jueves, 10 de mayo de 2012

Control de versiones

Estoy intentando obligarme a usar un control de versiones. Aunque pienso que trabajando solo
no seria tan necesario, nunca viene mal y te da algo mas de seguridad a la hora de hacer algun cambio
que no sabes como saldrá.

Voy a intentar usar subversion porque en los proyectos .NET uso Tortoise SVN / AnkhSVN y ya me he acostumbrado. Aunque parece que esta mas de moda usar Git, Mercurial o BitBucket.

Buscando en google "SVN Eclipse" me he encontrado que la gente recomienda dos programas:
Subversive o Subclipse. Me ha parecido mas facil de instalar el Subclipse así que voy a probarlo.

En Eclipse: Help->Install new software
En el origen de descarga le meto la url.
http://subclipse.tigris.org/update_1.8.x

Instalando Subclipse






En esta web lo explican todo:
http://subclipse.tigris.org/servlets/ProjectProcess?pageID=p4wYuA


jueves, 8 de marzo de 2012

Error Failed to install *.apk on device 'emulator-*': timeout

Ultimamente me esta saliendo este error:
Failed to install Pruebawv.apk on device 'emulator-5554': timeout Launch canceled!
La solución que he encontrado ha sido cambiar el valor de "ADB connection time out".
Para cambiar este valor hay que pasar por los siguientes menus: Eclipse->Window->Preferences->Android->DDMS->ADB connection time out (ms) = 5000
Cambiarlo a 10000.
http://stackoverflow.com/questions/4775603/android-error-failed-to-install-apk-on-device-timeout

Si así tampoco va la cosa, otra opción es reiniciar el adb.
Cierro el emulador. Desde la linea de comandos y si adb.exe esta en el path se ejecuta lo siguiente:
adb kill-server
adb start-server
Es posible que mientras se hace esto en Eclipse aparezca:
DeviceMonitor]Connection attempts: 1
DeviceMonitor]Connection attempts:2
...
Supongo que será porque no consigue enlazar con el adb despues de haber matado el proceso.


miércoles, 7 de marzo de 2012

Notificaciones emergentes "Toast"

No se porque lo habran llamado "toast" los americanos estan locos supongo. Pero en fin esto se usa para sacar un ventana emergente que se pinta sobre todo lo demás durante un momento. Yo esto lo estoy usando cuando se produce algun proceso largo en el que no hay ningun cambio en pantalla. Como si una barra de progreso se tratara pero en simple. Me sirve para que el usuario sepa que el programa esta vivo haciendo algo. El ejemplete:
Toast tostada = Toast.makeText(

  context, " - Estoy tardando, comprate un movil mas rapido o espera a que acabe. - ",

    Toast.LENGTH_LONG);

tostada.setGravity(Gravity.CENTER|Gravity.CENTER,0,0);

tostada.show();

Enlaces referentes a esto:

viernes, 2 de marzo de 2012

¿Que ha pasado? “Hot Code Replace Failed”

Que has cambiado algo despues de empezar el "deploy" cuando ibas a debugear.
Sale un dialogo y te pregunta:
¿Continue, terminate o disconnect? ¿Que mierdas hace cada opción?
Continue: Aceptas que los cambios que acabas de hacer no seran tenidos en cuenta en la sesion de debugeo y continuas.
Terminate: Matas la aplicación.
Disconnect: No matas la aplicación, que continua ejecutandose en el emulador. Pero no continuas con la sesión de debugeo.

jueves, 1 de marzo de 2012

Mezclar una actividad "normal" con otra libGDX

Esto todavia no lo he probado. Debería funcionar a base de intentos. Parece que llamar a la actividad libGDX desde la actividad "normal" se hace así:

 intent = new Intent(view.getContext(), GdxView.class);

No tengo tan claro como pasar de la actividad libGDX a la actividad "normal". Ni que pasa cuando el juego se queda en el estado pause. Supongo que el sistema operativo se lo podria cargar si le faltara memoria.

Abrir una actividad desde otra actividad de la misma aplicación.

Hay que crearse dos actividades en una aplicación. En el AndroidManifest.xml hay que añadir una actividad. Debe quedar algo asi:


    

    
    
        
            
                
                
            
        
        
    

En la primera actividad metemos un botón el cual hará que al pulsarlo se pase a la segunda actividad. Algo así:
@Override
 public void onCreate(Bundle savedInstanceState)
 {
  try
  {
   super.onCreate(savedInstanceState);
   requestWindowFeature(Window.FEATURE_NO_TITLE);
   setContentView(R.layout.main);
   botoncambiActividad = (Button) findViewById(R.id.button1);
   webView = (WebView) findViewById(R.id.webView);
   botoncambiActividad.setOnClickListener(new View.OnClickListener()
   {
    public void onClick(View view)
    {     
     Intent myIntent = new Intent(view.getContext(),
       PruebawvActivity2.class);
     startActivityForResult(myIntent, 0);
    }
   });   
  } catch (Exception ex)
  {
   Log.d("Excepcion", ex.toString());
  }
 }
 

martes, 7 de febrero de 2012

Lanzar una aplicacion cuando el dispositvo arranca.

¿Como se puede hacer? Metiendo en la aplicación un receptor de banda ancha que espere la llegada de un intento que indique que el dispositivo ha arrancado. ¿Como se mete el receptor de banda ancha? Podemos hacerlo de manera dinámica:
package es.jodio.elandroid.este
import android.content.*;
public class ReceptorBandaAncha extends  android.content.BroadcastReceiver
{ 
 @Override
 public void onReceive(Context arg0, Intent arg1)
 { 
  ...
 }
}
Y habrá que saber a que intento queremos hacer caso. Los intentos son como mensajes a broadcast con un id. Así que habrá que indicar a que id atenderemos. En este caso sería algo así: "android.intent.action.BOOT_COMPLETED" IntentFilter filter = new IntentFilter ("android.intent.action.BOOT_COMPLETED" ); ReceptorBandaAncha miRBA = new ReceptorBandaAncha(); registrarReceiver(miRBA, filter); Luego para dejar de estar registrados al intento podriamos hacerlo así: unregisterReceiver (ReceptorBandaAncha); Tambien se puede hacer de manera estática. De esta manera en cuanto se lanze el intento asociado esta se recibirá esté o no la aplicación en marcha.En el manifest metemos:

    
        
    

Enlaces: Android developers - BroadcastReceiver: Android developers - Intent and Intent Filters:

miércoles, 1 de febrero de 2012

Tres puntos en los argumentos de un método (varargs)

Viendo este método :
 public Animation (float frameDuration, TextureRegion... keyFrames) {
  this.frameDuration = frameDuration;
  this.keyFrames = keyFrames;
 }
Me he quedado picueto. No habia visto nunca lo de los tres puntos en el paso de parametros a un método. Resulta que es para indicar que no sabemos cuántos elementos de un tipo en concreto se pasarán al método. Osea un array del tipo indicado sin tamaño fijo. En esta web lo explican mejor.
<a href="http://www.codexion.com/tutorialesjava/java/javaOO/arguments.html"></a>

Comunicaciones UDP III. El Receptor

package es.vaprel.qkandroid.Communications;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.concurrent.BlockingQueue;

import com.badlogic.gdx.Gdx;

public class ComunicacionesReceptor extends Thread
{ 
 byte [] datosArrayByte;
 InetAddress direccionIp = null; 
 DatagramSocket recepcionSocket;
 DatagramPacket dato;
 private final BlockingQueue colamensajes;
 boolean socetOK = true;
 
 public ComunicacionesReceptor(BlockingQueue colamensajes,InetAddress direccionIp) 
   throws SocketException
 {
  this.direccionIp = direccionIp;
  this.colamensajes = colamensajes;     
  datosArrayByte = new byte[Comunicaciones.PAQUETE_SIZE]; 
  try
  {
   recepcionSocket = new DatagramSocket(Comunicaciones.PUERTO_DONDE_RECIBO);
  }
  catch (IOException ioe)
  {   
   Gdx.app.log("ERROR: ", ioe.getLocalizedMessage(), ioe);
  }      
 } 
 
 @Override
 public void run() {  
  dato = new DatagramPacket(new byte[Comunicaciones.PAQUETE_SIZE], Comunicaciones.PAQUETE_SIZE);
  while (socetOK)
  {
   try
   {
    // BLOQUEANTE
    recepcionSocket.receive(dato);
    // BLOQUEANTE
    ProcesarPaquete(dato);
    if (Thread.interrupted()) {
        try {
      throw new InterruptedException();
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
/*
 * By convention, any method that exits by throwing an InterruptedException clears
 *  interrupt status when it does so.
 *  However, it's always possible that interrupt status will immediately be set again,
 *  by another thread invoking interrupt.
 * */
      e.printStackTrace();
      Gdx.app.log("ERROR: ", e.getLocalizedMessage(), e);
      CloseSocket();
     }
    }
   }
   catch(IOException ioe)
   {
    socetOK = false;    
    Gdx.app.log("ERROR: ", ioe.getLocalizedMessage(), ioe);
   }
  }    
 }
 
 //Cuando llega un datagrama lo encola en la cola de mensajes recibidos
 private void ProcesarPaquete(DatagramPacket dato)
 {    
  try
  {
   datosArrayByte = dato.getData();
   Mensaje auxmensaje = new Mensaje(datosArrayByte.toString());
   colamensajes.add(auxmensaje);
  }
  catch (Exception ex)
  {
   Gdx.app.log("ERROR: ", ex.getLocalizedMessage(), ex); 
  }
 }
 
 public void CloseSocket() {
  socetOK = false;
  recepcionSocket.close();    
 }
}

jueves, 26 de enero de 2012

Error cargando un TextureAtlas

Nuevos dolores de cabeza, ahora me falla el programa en su version android al cargar los assets.
En la versión de escritorio funciona bien.
Cuando llega aquí no entra ni al catch, me dice que VM aborting y adios muy buenas.Ni entra al catch el muy cabrón

atlasaux = new TextureAtlas(Gdx.files.internal("data/packeaux/pack"));

No hay manera de encontrar por qué pasa esto. Algunos links que he mirado:
http://stackoverflow.com/questions/7950965/libgdx-android-application-cannot-find-the-main-game-class
http://stackoverflow.com/questions/6945881/libgdx-android-app-can-find-any-files-but-my-xml-level-files
http://code.google.com/p/libgdx/wiki/ProjectSetup

viernes, 20 de enero de 2012

Eliminar una aplicación del emulador


El emulador de Android debe estar ejecutándose.
Para eliminar una aplicación que haz instalado en el emulador, lo que debes hacer es:
Abre una consola en tu sistema operativo.
Navega hasta el directorio "Android Tools" (Por ejemplo: C:\android_sdk_windows_m3-rc22a\tools).
Ejecuta el comando "adb shell". Si el emulador no se está ejecutando vas a ver el siguiente mensaje:

-Navega al directorio "data/app", para ello ejecuta el comando
"cd data/app".
-(Opcional) Lista los archivos de este directorio con el comando
"ls".
-Finalmente elimina el archivo de tu aplicación con el comando
"rm tuaplicacion.apk"
-Ya está:
"exit"
Sacado del blog de este señor
http://celutron.blogspot.com/2007/12/cmo-hacer-eliminar-una-aplicacin-del.html

jueves, 19 de enero de 2012

The project was not built since the path is incomplete. Cannot find the class file for java.lang.Object. Fix the build path then try building this project.

Jodido con errores en el Eclipse  

The project was not built since the path is incomplete. Cannot find the class file for java.lang.Object. Fix the build path then try building this project.

No se porqué sale pero es muy frustrante el errorcito de los cojones.
Para solucionarlo:
- Botón derecho en el proyecto->Propiedades->Java Build Path->Libraries
Yo aqui tenia JRE System Library [JavaSE-1.7]
- Add Library->JRE System Library->Next->Execution Eviroment->
- Elegimos JavaSE-1.6 en la izquierda y jre6 en la derecha.
- Volvemos atras y marcamos Execution Enviroment
- Finish
- marcamos JRE System Library [JavaSE-1.7] y le damos a Remove a mano derecha
Y así el error no vuelve a salir, la tensión arterial baja a niveles normales.
Parece que toda esta mierda sale al actualizar la maquina virtual java.