Beruflich Dokumente
Kultur Dokumente
Home
Blog
Sguenos
Concenos
Contacto
Categoras
Android
Curso introduccin
Android
Programacin
Seguridad
Sistemas Operativos
Entradas recientes
Colorshapes, el juego de
velocidad mental y figuras
de colores para Android
eyeOS: Trabajando en la
nube
Integrando Google
Analytics en aplicaciones
Android
Integrando Twitter en
aplicaciones Android con
SignPost y Twitter4J
Entrenando con
Metasploitable (IV). Desde
postgres a ssh, pasando
por openSSL
Etiquetas
activity
algoritmo android
aplicacion android
arbol backtrack bash BD
acelerometro
BEeF
eclipse
expresiones regulares
graficos android
metasploit
metasploitable mitm
mysql oauth owasp
Sitios de inters
Android Developers
Android.es
Backtrack
Command Line Kung Fu
DragonJAR
El Androide Libre
EDITADO:
Exploits Database
Flu Project
El equipo de Android Market ha decidido a fecha 20-09-2011 retirar dicha aplicacin por violacin
de las polticas de contenido, a pesar de que nunca cobramos por dicha aplicacin ni obtuvimos
ganancias por publicidad ni negamos que Atari fuera la depositaria de los derechos de autor.
Gran Angular
Hispasec
Microsiervos
Por este motivo hemos decidido alojar la aplicacin en nuestro propio servidor para que pueda
seguir descargndose pulsando aqu (MD5: 039bf32bfaa8c64a6112bc364d456aa0).
OpenLibra
Pentester.es
Poesa Binaria
Security By Default
Twittear
19
Share
Esta entrada fue publicada en Android, Curso introduccin Android, Programacin y etiquetada
como aplicacion android.
LuiS! dijo:
22 julio, 2011 at 0:07
Hmmm me gusta lo del pong !! Yo tenia uno por algun lado programado en Visual basic y la
verdad esque me enganche a programar con el pong hasta el punto de ir de empalmada a
clase xD. Tengo un par de ideas para juegos / programas de utilidad para android xD ya
hablaremos. Kisses!LuiS!
Responder
2. Pingback: Poesa binaria C.I. XII: La evolucin de la web, 20 aniversario de Linux, DateTime
para php, instalar Arch Linux, Creando una aplicacin en Android y un pedal con Arduino
4.
Deja un comentario
Tu direccin de correo electrnico no ser publicada. Los campos necesarios estn marcados *
Nombre *
Un informtico en el lado
del mal
World Wide Web
Consistorium
Home
Blog
Sguenos
Concenos
Contacto
Paso 0: preparacin
Ubuntu no trae instalado por defecto el Java SDK, por lo que lo primero que debemos hacer es
instalarlo. Para ello, abrimos una Terminal y escribimos:
sudoaptgetinstallsunjava6bin
Introducimos la contrasea del usuario y esperamos a que descargue los ~106MB de los paquetes
necesarios.
Nota: si el Ubuntu sobre el que estis trabajando es de 64 bits, necesitis ejecutar el siguiente
comando en una terminal:
Categoras
Android
Curso introduccin
Android
Programacin
Seguridad
Sistemas Operativos
Entradas recientes
Automatizando la
creacin de entornos de
desarrollo con Vagrant
Colorshapes, el juego de
velocidad mental y figuras
de colores para Android
eyeOS: Trabajando en la
nube
Integrando Google
Analytics en aplicaciones
Android
Integrando Twitter en
aplicaciones Android con
SignPost y Twitter4J
Etiquetas
activity
algoritmo android
aplicacion android
arbol backtrack bash BD
acelerometro
BEeF
sudoaptgetinstallia32libs
eclipse
expresiones regulares
graficos android
Recomendamos crearnos nuestro directorio de desarrollo, para tenerlo todo organizado. Por
ejemplo en /home/[user_name]/AndroidDev o /media/[data_disk]/AndroidDev.
Una vez completado esto, vamos al siguiente paso.
metasploit
metasploitable mitm
mysql oauth owasp
primera opcin (o al menos la que era primera opcin cuando se cre esta entrada), la cual es
Eclipse IDE for Java EE Developers, 210 MB. La web debera detectar que estamos en un Linux, y
sin haber hecho click en el link tendremos a la derecha las opciones Linux 32 bit y Linux 64 bit. En
mi caso, 32 bit. Elegimos el mirror y comenzamos la descarga. Eclipse no se instala, es portable,
por lo que el lugar donde lo descomprimimos es el lugar de la instalacin. Lo dejamos
descargando en la ubicacin que queramos y avanzamos al siguiente paso.
Donde [path_development] ser la ubicacin donde hayamos descomprimido el SDK (en el cual
tendremos el directorio android-sdk-linux_x86). Este comando nos mostrar el Android SDK and
AVD Manager, como en la siguiente imagen:
Sitios de inters
Android Developers
Android.es
Backtrack
Command Line Kung Fu
DragonJAR
El Androide Libre
Exploits Database
Flu Project
Gran Angular
Hispasec
Microsiervos
OpenLibra
Pentester.es
Poesa Binaria
Lo siguiente que vamos a hacer es instalar las API del SDK que vamos a querer. En nuestro caso
van a ser todas, por si quisiramos desarrollar para una versin ms o menos antigua. Para ello nos
vamos a Available Packages, y seleccionamos los dos grupos por completo.
Durante estos pasos debers reiniciar el adb al menos una vez, aunque slo hay que dar a S,
reiniciarlo cuando nos lo pida.
Security By Default
Un informtico en el lado
del mal
World Wide Web
Consistorium
Escribimos lo siguiente:
Name: Android Plugin (en realidad, el nombre que queramos darle).
Location: https://dl-ssl.google.com/android/eclipse
Y pulsamos en OK. En la siguiente pantalla debemos elegir todo y pulsar en Next:
Aceptamos la licencia e instalamos. Tendremos que reiniciar Eclipse para completar dicha
instalacin.
El ltimo paso de la configuracin es decirle a Eclipse dnde est el Android SDK. Para ello vamos
a Window > Preferences > Android, y donde pone SDK Location escribimos la ruta absoluta. Existe
un bug en el momento de la creacin de esta entrada, por el cual no podemos pulsar en Proceed
en el pop-up que veremos hasta que no escribamos la ruta y demos a Enter. Recomiendo escribir
la ruta en lugar de buscarlo con el botn Browse, para evitar quedarnos bloqueados.
Ahora s, hemos acabado de configurar las herramientas. Ahora es momento de comprobar que
funciona!
Si hemos visto algn dispositivo, es que est reconocido perfectamente. Siempre podemos
reiniciar el servicio con los siguientes dos comandos:
cd[path_development]
androidsdklinux_x86/platformtools/adbkillserver
androidsdklinux_x86/platformtools/adbstartserver
Si por el contrario hemos conectado nuestro dispositivo fsico, tendremos algo parecido a lo
siguiente:
Hasta aqu la primera entrada del ciclo de entradas llamado Creando una aplicacin de Android.
En sucesivas entradas veremos cmo continuar, creando nuestra aplicacin y dando los primeros
pasos en las decisiones de diseo.
Hasta pronto!
Ms informacin:
Android Developers
0. Creando una aplicacin de Android: la presentacin
1. Creando una aplicacin de Android: primeros pasos
2. Creando una aplicacin de Android: visin de conjunto y diseo del men
3. Creando una aplicacin de Android: el juego y la lgica (parte 1)
4. Creando una aplicacin de Android: el juego y la lgica (parte 2)
5. Creando una aplicacin de Android: mejoras (parte 1)
6. Creando una aplicacin de Android: mejoras (parte 2)
7. Creando una aplicacin de Android: empaquetado y publicacin
Home
Blog
Sguenos
Concenos
Contacto
Categoras
Android
Curso introduccin
Android
Programacin
Seguridad
Sistemas Operativos
Entradas recientes
Automatizando la
creacin de entornos de
desarrollo con Vagrant
Colorshapes, el juego de
velocidad mental y figuras
de colores para Android
eyeOS: Trabajando en la
nube
Integrando Google
Analytics en aplicaciones
Android
Integrando Twitter en
aplicaciones Android con
SignPost y Twitter4J
Etiquetas
activity
algoritmo android
aplicacion android
arbol backtrack bash BD
acelerometro
BEeF
eclipse
El Application Name va a ser el texto que aparezca en nuestro dispositivo debajo del icono cuando
queramos ejecutarlo.
expresiones regulares
El Package Name es el nombre del paquete de esta aplicacin. Es importante recordar que en el
mismo dispositivo slo puede haber instalada una aplicacin con el mismo package name, por lo
que necesitamos que sea nico. Se recomienda que se usen las convenciones de nombrado de
paquetes de software, por las cuales debemos usar minsculas y usaremos el dominio de la
compaa empezando desde la derecha, y al final el nombre de nuestra aplicacin.
El campo Create Activity sirve para crear la actividad por defecto. Tiene restricciones a la hora de
poner smbolos en el nombre, as que elegiremos nuestra actividad de dicha forma.
metasploitable mitm
El campo Min SDK Version contiene la versin del SDK que aparezca en el Build Target que
hayamos elegido. Normalmente se pone por defecto, pero debemos ponerla en caso contrario.
Ahora tenemos nuestro proyecto creado, con todos los ficheros por defecto. Veremos algo as:
graficos android
metasploit
Sitios de inters
Por lo que podemos ver, tenemos varios directorios, dos ficheros .java y tres ficheros .xml.
Veamos para qu sirve cada uno:
PongvCActivity.java: este es el fichero de la actividad por defecto que nos ha creado Eclipse.
Vamos a entender esto como el mainde una aplicacin Java tradicional, el punto de entrada
al ejecutar la aplicacin. Su cdigo es:
packagecom.vidasconcurrentes.pongvc;
importandroid.app.Activity;
importandroid.os.Bundle;
publicclassPongvCActivityextendsActivity{
/**Calledwhentheactivityisfirstcreated.*/
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Esta clase hereda de Activity y redefine la funcin onCreate(). Esta funcin toma un Bundle,
Android Developers
Android.es
Backtrack
Command Line Kung Fu
DragonJAR
El Androide Libre
Exploits Database
Flu Project
Gran Angular
Hispasec
Microsiervos
OpenLibra
Pentester.es
Poesa Binaria
Security By Default
Un informtico en el lado
del mal
World Wide Web
Consistorium
que es la forma que tiene Android de pasar elementos primitivos entre actividades. Por as
decirlo (y muy cogido con pinzas) es como pasarle a la actividad el estado del sistema. Luego
usa la funcin setContentView(), que dice qu debe mostrarse en la pantalla. Ahora veremos
qu es R.layout.main.
Aqu vemos por primera vez LinearLayout. Define la forma de la que se van a distribuir los
elementos que vayan dentro de ella. En este caso, define que los elementos deben
colocarse uno detrs de otro. Existe una explicacin en detalle de todas las vistas y layouts
disponibles en Android Developers. Vemos que hay tambin un TextView, que es un widget
que permite mostrar un texto. Este texto puede ser hardcoded (es decir, escrito a mano ah)
o que venga del fichero strings.xml. Se recomienda usar la opcin de strings.xml siempre
que podamos, entre otras cosas porque nos ayudar a las traducciones de nuestros textos (si
queremos aceptar varios idiomas).
strings.xml: este fichero define cadenas de texto. Es muy til en situaciones de querer
cambiar un texto que aparece en muchos sitios, que en lugar de tener que buscarlo en todas
partes y cambiarlo, slo lo cambiamos aqu y ya aparece en todos.
AndroidManifest.xml: toda aplicacin debe tener este fichero en su directorio raiz, y entre
otras cosas define el nombre del paquete de la aplicacin, los componentes (actividades y
sus configuraciones, servicios), los permisos que necesita la aplicacin, el nivel de la API
mnimo que necesita, las libreras que el proyecto necesita Se puede editar (y de hecho
tendremos que editarlo antes o despus), y cuenta con una vista grfica muy buena para
esta edicin.
Hemos visto que en el directorio res encontramos todos los recursos (grficos tambin) que va a
usar el proyecto. layouts guarda las distribuciones, values guarda los strings, drawable guarda las
imagenes
Hasta aqu la explicacin de los componentes de nuestro proyecto creado por defecto.
Ahora s, vamos a empezar nuestro proyecto. Como hemos dicho, vamos a crear un Pong. Ser
una aplicacin sencilla, muy sencilla. La aplicacin ejecutar y mostrar un men desde el cual
podremos seleccionar tres opciones: Jugar, Opciones y Salir. Jugar ejecutar el juego, Opciones nos
llevar a elegir la configuracin del juego, y Salir cerrar la aplicacin. En esta entrada vamos a
crear este primer men.
Si ejecutamos el proyecto ahora (click derecho en el proyecto, Run as > Android Application),
veremos lo siguiente:
Como vemos, nos muestra la barra de notificaciones, el nombre de la aplicacin y lo que contiene
R.layout.main. Sin embargo nosotros no queremos que aparezca nada ms que nuestro
R.layout.main. Para hacer esto, vamos a aadir las siguientes lneas de cdigo en PongvCActivity:
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
Con esto estamos pidiendo al sistema de ventanas de Android que nos quite el nombre de la
aplicacin y que adems oculte la barra de notificaciones. Veremos lo siguiente:
Existe otra manera de hacer esto, y es modificando el AndroidManifest.xml. Sin embargo vamos a
hacerlo de forma programtica aqu (con cdigo) y haremos otra cosa de forma estructural (con los
xml) al final de la entrada. Ahora vamos a crear nuestro men. Esta aplicacin va a ser muy simple,
por lo que no vamos a fijarnos en que sea artstico, sino funcional. Para comenzar, vamos a crear
un nuevo directorio en res/ y vamos a llamarlo drawable. Dentro vamos a guardar estas tres
imgenes:
<?xmlversion="1.0"encoding="utf8"?>
<resources>
<stringname="hello">HelloWorld,PongvCActivity!</string>
<stringname="app_name">PongvC</string>
<stringname="menu_play">Jugar</string>
<stringname="menu_options">Opciones</string>
<stringname="menu_exit">Salir</string>
</resources>
<?xmlversion="1.0"encoding="utf8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:weightSum="1">
<ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/pong"android:layout_gravity="center"android:layout_marginB
<TextViewandroid:layout_height="wrap_content"android:text="@string/menu_play"android:textAppearance="?android:attr/textAppearanceLarge"android:layout_width="wrap_c
<TextViewandroid:layout_height="wrap_content"android:text="@string/menu_options"android:textAppearance="?android:attr/textAppearanceLarge"android:layout_width="wra
<TextViewandroid:layout_height="wrap_content"android:text="@string/menu_exit"android:textAppearance="?android:attr/textAppearanceLarge"android:layout_width="wrap_c
<ImageViewandroid:id="@+id/imageView1"android:layout_width="314dp"android:layout_height="wrap_content"android:src="@drawable/vc"android:layout_gravity="center|bot
</LinearLayout>
Si hemos hecho todo como he explicado, no habr errores. Es tan largo porque est aplicado ya
un poco de maquetado para que quede colocado. Podemos ejecutar nuestra aplicacin ahora y
veremos lo siguiente:
Ahora solamente tenemos que darle funcionalidad a los elementos que hemos colocado. Esto lo
hacemos en el fichero PongvCActivity.java. Primero vamos a aadir funcionalidad al botn de
Jugar. Para ello, al final del cdigo que tenemos, escribimos:
TextViewplay=(TextView)findViewById(R.id.play_button);
play.setOnClickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
Toast.makeText(getApplicationContext(),R.string.menu_play,
Toast.LENGTH_SHORT).show();
}
});
Vamos a hacer un acto de fe en la ltima parte del cdigo y vamos a quedarnos con que el cdigo
del ultimo bloque hace que se abra el navegador web del dispositivo y lleve a este blog. En la
siguiente entrada explicaremos esto en detalle, pero para no hacer ms larga esta entrada vamos a
tomarlo as.
Ahora podemos ejecutar la aplicacin y por ejemplo tocar en Opciones, y veremos lo siguiente:
Hasta aqu la entrada de esta semana. En ella hemos visto cmo crear el proyecto de nuestra
aplicacin, de qu partes se compone este proyecto, para qu sirve cada una de estas partes,
hemos diseado nuestro men principal del juego y le hemos dado funcionalidad.
Puedes descargar el proyecto completo en un fichero comprimido, listo para importar en tu
Eclipse, pulsando aqu (MD5: 354b8fb840d9aeb6e91cb2ef35f3203f).
En la siguiente entrada crearemos el juego en s, todas las clases necesarias para representar un
Pong y la lgica de movimientos, adems de mostrar todo esto en pantalla al dar al botn Jugar
del men.
Un saludo a todos los lectores!
0. Creando una aplicacin de Android: la presentacin
1. Creando una aplicacin de Android: primeros pasos
2. Creando una aplicacin de Android: visin de conjunto y diseo del men
3. Creando una aplicacin de Android: el juego y la lgica (parte 1)
4. Creando una aplicacin de Android: el juego y la lgica (parte 2)
5. Creando una aplicacin de Android: mejoras (parte 1)
6. Creando una aplicacin de Android: mejoras (parte 2)
7. Creando una aplicacin de Android: empaquetado y publicacin
Like
Twittear
Follow
Share
Esta entrada fue publicada en Android, Curso introduccin Android, Programacin y etiquetada
como activity, aplicacion android, eclipse, java, layout, menu.
Gonzalo dijo:
9 febrero, 2014 at 14:48
Hola, en primer lugar gracias por tu aporte.
Quera comentarte que tengo algn problema a la hora de seguir los pasos.
En primer lugar el codigo que se me genera en PongvCActivity.java no es igual al que
muestras (esto puede ser por que estoy usando Ubuntu 13.10.
En segundo luegar a la hora de aadir el codigo:
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
me da error donde quiera que lo ponga.
Alguna sugerencia?
muchas gracias por todo
2.
Josue dijo:
5 septiembre, 2011 at 0:30
Fijate q yo quiero hacer q el pong funcione en 2 celulares por medjio de un servidor. Me
pregunto si me podrias explicar como hacerlo. Solo la explicacion sin la necesidad de poner
el codigo
meta dijo:
5 septiembre, 2011 at 0:43
As como primera idea, en fro se me ocurre nicamente lo siguiente:
Podras hacer que el servidor manejase, entre otras cosas, la coordenada en la que se
encuentra cada raqueta y la bola en cada momento. Continuamente (quiz en un
nmero fijo de veces por segundo), cada dispositivo se comunicara con el servidor
mandando paquetes de informacin (dependiendo de si es por Internet, Bluetooth
ser de forma distinta), y el servidor estara enviando a cada uno de los dispositivos
informacin sobre la posicin de ambas raquetas y de la bola.
Cada dispositivo recibira dicha informacin y la usara para actualizar su interfaz
(incluso podra detectar errores en la precisin del servidor o de s mismo, al incluir
redundancia en los datos contnuamente).
Cuando se marca un punto, el servidor sera notificado (l sabra qu tiene que hacer,
puesto que sabe la posicin de la bola siempre) y enviara tambin la informacin a los
dispositivos (o no, porque ellos tambin pueden llevar la cuenta de sus puntos en
local. Lo importante es que el volumen de informacin que se transfiera sea el mnimo
posible, para poder hacerlo rpido.
Es slo una idea, no tienes por qu seguirla ^^
Home
Blog
Sguenos
Concenos
Contacto
En esta entrada vamos a crear el juego, incluyendo todas las clases necesarias para que funcione y
en la siguiente entrada crearemos la lgica de movimientos.
Comencemos!
Importante: esta entrada va a basarse en los cdigos creados en las anteriores entradas del ciclo al
que pertenece. Tienes disponible pinchando aqu (MD5: 354b8fb840d9aeb6e91cb2ef35f3203f)
el proyecto de Eclipse con todo lo hecho hasta ahora, el cual puedes importar a tu Eclipse y
comenzar a trabajar.
Lo primero que vamos a hacer es crear una nueva Activity que ser el juego, y que se ejecutar en
el momento en que pinchemos en el botn Jugar del men mostrado arriba.
Vamos a comenzar aadiendo una nueva clase a nuestro proyecto, que ser nuestra nueva
actividad. Sin embargo esta es la primera vez que vamos a crear una actividad sin que sea el
propio asistente de Eclipse el que cree el cdigo por defecto, y es interesante darse cuenta de que
no se sobrescribe la funcin onCreate() automticamente.
Hacemos click derecho sobre el paquete com.vidasconcurrentes.pongvc y seleccionamos New >
Class. En la ventana emergente que aparece vamos a donde pone Superclass y a la derecha
pulsamos en Browse. Escribimos android.app.Activity y aceptamos. Escribimos el nombre para
nuestra clase, por ejemplo PongJuego, y creamos la clase. Ahora pinchamos en Source >
Override/Implement methods, y buscamos onCreate(Bundle). Ahora nuestra clase debera ser
parecida a esta:
Categoras
Android
Curso introduccin
Android
Programacin
Seguridad
Sistemas Operativos
Entradas recientes
Automatizando la
creacin de entornos de
desarrollo con Vagrant
Colorshapes, el juego de
velocidad mental y figuras
de colores para Android
eyeOS: Trabajando en la
nube
Integrando Google
Analytics en aplicaciones
Android
Integrando Twitter en
aplicaciones Android con
SignPost y Twitter4J
Etiquetas
activity
algoritmo android
aplicacion android
arbol backtrack bash BD
acelerometro
BEeF
eclipse
expresiones regulares
graficos android
metasploit
metasploitable mitm
mysql oauth owasp
packagecom.vidasconcurrentes.pongvc;
importandroid.app.Activity;
importandroid.os.Bundle;
publicclassTestextendsActivity{
persistente
@Override
protectedvoidonCreate(BundlesavedInstanceState){
//TODOAutogeneratedmethodstub
super.onCreate(savedInstanceState);
}
Sitios de inters
Como vemos, no tiene un View que pintar, as que lo que vamos a hacer ahora es crearlo. Para
hacerlo, vamos a seguir el siguiente tutorial que hice hace unas semanas. Pincha en el enlace, sigue
los pasos y tendrs algo como esto:
PongJuego.java:
packagecom.vidasconcurrentes.pongvc;
importcom.vidasconcurrentes.pongvc.pintado.PongGameView;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.view.Window;
importandroid.view.WindowManager;
publicclassPongJuegoextendsActivity{
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(newPongGameView(this));
}
}
PongGameView.java:
packagecom.vidasconcurrentes.pongvc.pintado;
importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.graphics.Color;
importandroid.view.SurfaceHolder;
importandroid.view.SurfaceView;
publicclassPongGameViewextendsSurfaceView
implementsSurfaceHolder.Callback{
privatePongGameThreadpaintThread;
publicPongGameView(Contextcontext){
super(context);
getHolder().addCallback(this);
}
@Override
publicvoidsurfaceChanged(SurfaceHolderholder,intformat,
intwidth,intheight){}
@Override
publicvoidsurfaceCreated(SurfaceHolderholder){
paintThread=newPongGameThread(getHolder(),this);
paintThread.setRunning(true);
paintThread.start();
}
@Override
publicvoidsurfaceDestroyed(SurfaceHolderarg0){
booleanretry=true;
paintThread.setRunning(false);
while(retry){
try{
paintThread.join();
retry=false;
}catch(InterruptedExceptione){}
}
}
@Override
publicvoidonDraw(Canvascanvas){
canvas.drawColor(Color.WHITE);
}
}
PongGameThread.java:
packagecom.vidasconcurrentes.pongvc.pintado;
importandroid.graphics.Canvas;
importandroid.view.SurfaceHolder;
publicclassPongGameThreadextendsThread{
privateSurfaceHoldersh;
privatePongGameViewview;
privatebooleanrun;
Android Developers
Android.es
Backtrack
Command Line Kung Fu
DragonJAR
El Androide Libre
Exploits Database
Flu Project
Gran Angular
Hispasec
Microsiervos
OpenLibra
Pentester.es
Poesa Binaria
Security By Default
Un informtico en el lado
del mal
World Wide Web
Consistorium
publicPongGameThread(SurfaceHoldersh,PongGameViewview){
this.sh=sh;
this.view=view;
run=false;
}
publicvoidsetRunning(booleanrun){
this.run=run;
}
publicvoidrun(){
Canvascanvas;
while(run){
canvas=null;
try{
canvas=sh.lockCanvas(null);
synchronized(sh){
view.onDraw(canvas);
}
}finally{
if(canvas!=null)
sh.unlockCanvasAndPost(canvas);
}
}
}
}
Nota: es importante darse cuenta de que estas dos clases estn dentro de un nuevo paquete
llamado com.vidasconcurrentes.pongvc.pintado. Es interesante mantener los cdigos de nuestros
proyectos ordenados, y los paquetes nos ayudan a agrupar aquellas clases que sirven para el
mismo fin.
Ya tenemos todo lo necesario para pintar nuestra nueva Activity. Ahora slo nos falta ejecutarla.
Para ello vamos a usar un Intent. El Intent es una abstraccin para definir operaciones asncronas
como ejecutar nuevas actividades y pasar informacin entre stas, entre otras.
Una Activity creada de esta forma puede considerarse una sub-actividad si est previsto que
devuelva algn dato a la actividad que la cre. Contamos con dos funciones para crear actividades:
startActivity(): esta funcin crea una nueva Activity que no devolver informacin al acabar.
Una actividad creada de esta forma se considera una actividad aparte.
startActivityForResult(): esta funcin crea una sub-actividad que devolver ciertos valores al
finalizar. Cuando lo haga, la actividad que la cre entrara en su funcin onActivityResult(),
para procesar los datos necesarios.
Despus de esta breve teora, vamos a lo que nosotros necesitamos. Hemos de recordar que las
actividades forman una pila, de modo que si ejecutamos el juego desde el men y luego
acabamos esa actividad (por ejemplo con la tecla apropiada en nuestro terminal), vamos a volver
al men. Por ahora no vamos a necesitar guardar el progreso del juego, por lo que no vamos a
devolverle al men informacin alguna. Ejecutemos entonces nuestra nueva Activity. Recordemos
que nuestro men tena una parte del cdigo as:
[...]
TextViewplay=(TextView)findViewById(R.id.play_button);
play.setOnClickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
Toast.makeText(getApplicationContext(),R.string.menu_play,
Toast.LENGTH_SHORT).show();
}
});
[...]
El constructor de Intent recibe qu clase crea la Activity y de qu clase es esta Activity nueva. Slo
nos resta aadir cdigo a la funcin onCreate() de nuestra nueva Activity. Escribimos lo siguiente
en ella:
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(newPongGameView(this));
}
Ahora s, podemos ejecutar nuestro proyecto. Click derecho sobre el proyecto, Run as > Android
Application. Si todo est bien hecho, veremos el men, y al pulsar sobre Jugar nos abrir una
nueva ventana con el fondo blanco. Ya hemos creado nuestra actividad para pintar el juego!
Lo siguiente que vamos a hacer son los elementos que van a hacer falta en el juego. Haciendo un
pequeo anlisis previo (con poca vista al futuro), vamos a necesitar una bola y dos raquetas.
Tanto las raquetas como la pelota tienen que moverse por la pantalla (y sin salirse), pero no
necesitan ms funcionalidad.
Es ahora el momento en el que diseamos nuestro juego. Debemos recordar que los ordenadores
(y en este caso nuestros dispositivos) son estpidos, no saben nada. Un computador no sabe qu
es una Raqueta, no sabe qu es una Bola, no sabe qu es una pantalla ni siquiera sabe qu es una
actividad. Sin embargo s que sabe qu es un nmero, qu es un carcter y qu es un booleano
(sabe qu es cada tipo de dato primitivo).
As que podemos pensar que una Raqueta es un rectngulo. Qu es un rectngulo? Un
rectngulo no es ms que un punto origen, un ancho y un alto. Y qu es un punto? Un punto va a
ser un par de coordenadas en un plano (la pantalla).
Por tanto tenemos que una Raqueta es dos nmeros que representan las coordenadas del origen,
un nmero que representa el ancho y un nmero que representa el alto. Y una Bola?
Recordemos que en el Pong original, la bola era un cuadrado. Por tanto, y teniendo en cuenta que
un Cuadrado es un Rectngulo con el ancho y alto iguales, podemos llegar a la conclusin de que
ambas tienen en comn su representacin. Esto nos permite pensar en una superclase
ElementoPong que tenga la funcionalidad necesaria para representar tanto Raquetas como Bolas.
Creamos un nuevo paquete llamado com.vidasconcurrentes.pongvc.juego. En l, creamos una
nueva clase llamada Coordenada, y escribimos el siguiente cdigo:
packagecom.vidasconcurrentes.pongvc.juego;
publicclassCoordenada{
privateintx;
privateinty;
publicCoordenada(intx,inty){
this.x=x;
this.y=y;
}
publicintgetX(){
returnx;
}
publicvoidsetX(intx){
this.x=x;
}
publicintgetY(){
returny;
}
publicvoidsetY(inty){
this.y=y;
}
}
Aadimos los getters y setters para ambos atributos porque queremos poder consultar sus valores
y cuando movamos los elementos, querremos modificarlos.
Ahora creamos una nueva clase llamada ElementoPong, y escribimos el siguiente cdigo:
packagecom.vidasconcurrentes.pongvc.juego;
importandroid.graphics.Rect;
publicabstractclassElementoPong{
protectedCoordenadaorigen;
protectedintancho;
protectedintalto;
publicElementoPong(Coordenadaorigen,intancho,intalto){
this.origen=origen;
this.ancho=ancho;
this.alto=alto;
}
publicintgetOrigenX(){
returnorigen.getX();
}
publicintgetOrigenY(){
returnorigen.getY();
}
publicintgetAncho(){
returnancho;
}
publicintgetAlto(){
returnalto;
}
publicRectgetRectElemento(){
returnnewRect(getOrigenX(),getOrigenY(),
getOrigenX()+ancho,getOrigenY()+alto);
}
}
Con esto estamos creando un elemento del juego. Con el modificador abstract en la declaracin
de la clase estamos diciendo que no se pueden instanciar objetos de esta clase, con lo que
obligamos a crear clases que hereden de sta (y por tanto hereden todos los atributos y
funcionalidad ya descrita). La funcin getRectElemento() nos ser til a la hora de pintar los
elementos, entre otras.
Adems querremos que nuestros elementos se muevan, pero cada uno se mover de forma
distinta. En este caso vamos a crear una interfaz que obligue a las clases que la implementen a
incluir una funcin para moverse. El cdigo es el siguiente:
packagecom.vidasconcurrentes.pongvc.juego;
publicinterfaceElementoPongMovil{
publicvoidmove();
}
Ahora slo resta crear nuestra clase Raqueta y nuestra clase Bola. El cdigo para la clase Raqueta
ser:
packagecom.vidasconcurrentes.pongvc.juego;
publicclassRaquetaextendsElementoPong
implementsElementoPongMovil{
publicRaqueta(Coordenadaorigen,intancho,intalto){
super(origen,ancho,alto);
}
@Override
publicvoidmove(){
}
}
Son iguales por ahora, ya que no hemos dado funcionalidad al mtodo move() an.
Para acabar con esta primera parte en la creacin de la Activity del juego, vamos a mostrar todo en
la pantalla. El primer paso va a ser aadir dos raquetas y una bola a nuestra aplicacin. Para ello,
vamos a la clase PongGameView y le aadimos los tres nuevos atributos, de modo que sean:
privatePongGameThreadpaintThread;
privateElementoPongraquetaIzda;
privateElementoPongraquetaDcha;
privateElementoPongbola;
Esto hace que tengamos las raquetas en los laterales a la misma distancia de su pared, y la bola
centrada en pantalla. Las raquetas sern de 20100 pxeles mientras que la bola ser de 1010
pxeles.
Slo nos resta aadir cdigo al pintado para que muestre dichos elementos. Para ello
modificamos el mtodo onDraw() de la siguiente forma:
@Override
publicvoidonDraw(Canvascanvas){
Paintpaint=newPaint();
paint.setColor(Color.WHITE);
canvas.drawColor(Color.BLACK);
canvas.drawRect(raquetaIzda.getRectElemento(),paint);
canvas.drawRect(raquetaDcha.getRectElemento(),paint);
canvas.drawRect(bola.getRectElemento(),paint);
}
Et voil! Podemos ejecutar nuestra aplicacin y probar que lo que hemos hecho est bien. Si has
seguido el tutorial paso a paso, tendrs lo siguiente al pulsar Jugar en el men:
En esta entrada hemos continuado el cdigo de la entrada anterior en la que tenamos un men, y
hemos aadido la funcionalidad para que al pulsar en un determinado elemento del men se cree
nuestro juego. Adems hemos creado las clases necesarias para representar nuestro juego y
hemos pintado estos elementos en pantalla.
Puedes descargar el proyecto de Eclipse con todo lo hecho hasta ahora pulsando aqu (MD5:
e50037a2c1219ea0b5e8e464c72390aa). Adems puedes importarlo a tu workbench
directamente y trabajar con ello.
En la siguiente entrada vamos a crear la lgica del juego: movimientos de las raquetas,
movimiento de la pelota, restricciones de dichos movimientos (que no se salga de la pantalla, que
rebote la pelota) y la creacin del bucle de juego.
Un saludo a todos los lectores, y gracias por dedicarle tiempo!
0. Creando una aplicacin de Android: la presentacin
1. Creando una aplicacin de Android: primeros pasos
2. Creando una aplicacin de Android: visin de conjunto y diseo del men
3. Creando una aplicacin de Android: el juego y la lgica (parte 1)
4. Creando una aplicacin de Android: el juego y la lgica (parte 2)
5. Creando una aplicacin de Android: mejoras (parte 1)
6. Creando una aplicacin de Android: mejoras (parte 2)
7. Creando una aplicacin de Android: empaquetado y publicacin
Like
Twittear
Follow
Share
Esta entrada fue publicada en Android, Curso introduccin Android, Programacin y etiquetada
como activity, aplicacion android, eclipse, graficos android, intent, java.
2.
Rohe dijo:
30 octubre, 2013 at 18:50
Si no quisiera pintar un rectangulo sino un Bitmap, la clase elementopong, solo cambiara en
el mtodo public Rect getRectElemento()? o qu debera hacer?
Home
Blog
Sguenos
Concenos
Contacto
En esta entrada vamos a completar la lgica del juego, haciendo que las raquetas y la bola se
muevan y, en definitiva, se pueda jugar.
Comenzamos!
Importante: esta entrada va a basarse en los cdigos creados en las anteriores entradas del ciclo al
que pertenece. Tienes disponible pinchando aqu (MD5: e50037a2c1219ea0b5e8e464c72390aa)
el proyecto de Eclipse con todo lo hecho hasta ahora, el cual puedes importar a tu Eclipse y
comenzar a trabajar.
Nota: esta entrada es bastante larga, pero incluye mucho cdigo. Quedis avisados!
Recordemos que en la anterior entrada creamos una serie de clases que nos iban a servir para
representar nuestros elementos del juego. Disponamos de una superclase ElementoPong que
describa la representacin de un elemento del juego (un rectngulo definido por una coordenada
origen, un ancho y un alto), una interfaz ElementoPongMovil que obliga a implementar el mtodo
move() y dos clases que heredaban de la primera e implementaban la segunda (Raqueta y Bola).
Vamos a comenzar con el movimiento de las palas. Queremos que se muevan al tocar con el
dedo sobre ellas, y se muevan donde vaya nuestro dedo.
Para hacer esto, vamos a sobrescribir el mtodo onTouchEvent() en nuestro PongGameView:
@Override
publicbooleanonTouchEvent(MotionEventevent){
intx=(int)event.getX();
inty=(int)event.getY();
returntrue;
}
Categoras
Android
Curso introduccin
Android
Programacin
Seguridad
Sistemas Operativos
Entradas recientes
Automatizando la
creacin de entornos de
desarrollo con Vagrant
Colorshapes, el juego de
velocidad mental y figuras
de colores para Android
eyeOS: Trabajando en la
nube
Integrando Google
Analytics en aplicaciones
Android
Integrando Twitter en
aplicaciones Android con
SignPost y Twitter4J
Etiquetas
activity
algoritmo android
aplicacion android
arbol backtrack bash BD
acelerometro
BEeF
eclipse
expresiones regulares
graficos android
metasploit
metasploitable mitm
mysql oauth owasp
De esta forma estamos detectando las coordenadas X e Y en las que se ha detectado el evento,
aunque de momento no hacemos nada con ellas. El siguiente paso es detectar qu tipo de accin
se ha hecho. Hemos pulsado, hemos arrastrado o hemos levantado el dedo? Son los tres eventos
que vamos a detectar. Para ello aadimos lo siguiente:
@Override
publicbooleanonTouchEvent(MotionEventevent){
intx=(int)event.getX();
inty=(int)event.getY();
switch(event.getAction()){
caseMotionEvent.ACTION_DOWN:
//hemospulsado
break;
caseMotionEvent.ACTION_MOVE:
//hemosarrastrado
break;
caseMotionEvent.ACTION_UP:
//hemoslevantado
break;
}
returntrue;
}
Sitios de inters
Android Developers
Android.es
Backtrack
Command Line Kung Fu
DragonJAR
El Androide Libre
Exploits Database
Flu Project
Gran Angular
Hispasec
Microsiervos
OpenLibra
En nuestro Pong vamos a querer poder mover la raqueta izquierda y la raqueta derecha, pero la
bola deber moverse sola. Por tanto, en nuestro ACTION_DOWN vamos a ver si hemos tocado
en la raqueta izquierda, la derecha o en ninguna de ellas (siendo el estado inicial ninguna). Si
hemos tocado en una de las dos, tenemos que quedarnos con cual es la que hemos tocado para
poder aplicarle los movimientos del ACTION_MOVE. Una vez que hagamos ACTION_UP lo que
haremos ser decir ya no estoy tocando ninguna de las raquetas.
Pentester.es
Poesa Binaria
Formas de hacer esto hay muchas y muy buenas, como por ejemplo usar un identificador para
cada elemento, tener una coleccin de elementos mviles y pulsables y luego iterar sobre ella
para encontrar el elemento sobre el que se puls y quedarse con su identificador Sin embargo
nosotros vamos a hacerlo simple, puesto que slo vamos a permitir tocar en dos figuras (y eso
slo cuando jueguen dos personas). Adems, para calcular un desplazamiento, necesitamos la
posicin que vamos a llamar origen y la actual.
Lo primero, entonces, ser aadir un nuevo parmetro al PongGameView, que ser el elemento
activo, y el origen del movimiento, que ser la posicin del eje Y donde hemos puesto el dedo:
privateElementoPongelementoActivo=null;
privateintorigenY;
Lo que hacemos es asignar al elemento activo el elemento sobre el que hemos tocado (si es que
hemos tocado en alguno), y adems asignamos el la posicin Y en la que hemos pulsado a nuestra
variable origenY. Repetimos el cdigo de la asignacin en lugar de hacerlo siempre para evitar
asignaciones innecesarias (los dispositivos son suficientemente rpidos como para procesar unas
miles de asignaciones extra pero es interesante valorar el lugar donde vamos a poner nuestras
instrucciones con respecto del nmero de veces que se ejecutarn). El mtodo contains(int,int) de
la clase Rect nos viene de perlas para no tener que hacer una lnea con 4 and. Aunque nunca en
nuestro juego puede darse que estemos tocando la raqueta izquierda y adems la raqueta
derecha, hacemos un break despus de asignar el elemento para curarnos en salud, y de paso
ejecutar un par de operaciones menos.
Lo siguiente que vamos a hacer es el caso del ACTION_UP, que es tan simple como volver a null
el elemento activo. La variable origenY no la vamos a devolver a ningn estado nulo porque no
nos hace falta (no hacemos comprobaciones con ella). Podramos hacer una comprobacin para
poner null si el elemento activo no lo es ya, pero como en nuestro caso queremos que no haya
nada activo al soltar, lo hacemos de la siguiente forma:
caseMotionEvent.ACTION_UP:
//hemoslevantado
elementoActivo=null;
break;
Security By Default
Un informtico en el lado
del mal
ser slo en la Y. Recordemos que en los grficos de Android (y en Java en general), se considera el
origen de coordenadas la esquina superior izquierda, y no la inferior izquierda como en un sistema
de coordenadas cartesianas. Por tanto, si vamos hacia abajo sumamos y si vamos hacia arriba
restamos.
Es, por tanto, el momento de implementar el mtodo move() para las raquetas. Por ahora, vamos
a tomar la decisin de diseo de cambiar el mtodo move() de la interfaz ElementoPongMovil,
para hacerla de la siguiente forma:
packagecom.vidasconcurrentes.pongvc.juego;
publicinterfaceElementoPongMovil{
publicvoidmove(intx,inty);
}
Ahora al mtodo move() le pasamos dos nmeros enteros, que son el nmero de pxeles que
debe moverse en el eje X y el Y.
El mtodo move() de la Raqueta y la Bola va a necesitar modificar su origen de coordenadas, por
lo que hemos de aadir los siguientes mtodos a ElementoPong:
publicvoidsetOrigenX(intnewX){
origen.setX(newX);
}
publicvoidsetOrigenY(intnewY){
origen.setY(newY);
}
Simple. Recordemos que no nos interesa ningn desplazamiento en el eje X, as que nos da igual
el valor de X que venga.
Volviendo al ACTION_MOVE, ste es su cdigo:
caseMotionEvent.ACTION_MOVE:
//hemosarrastrado
if(elementoActivo!=null){
Raquetar=(Raqueta)elementoActivo;
r.move(0,yorigenY);
}
origenY=y;
break;
Esto ocurre porque no hemos puesto restricciones por los lados (en este caso arriba y abajo). Es
momento de aadrselas.
Una buena prctica de Programacin Orientada a Objetos consiste en tener claro que cada objeto
es un conjunto de atributos y funciones relativas a una entidad. Es decir, cada objeto conoce sus
atributos y sabe operar con ellos, pero no tiene que saber cmo lo hacen los dems.
Pongamos un ejemplo muy simple. Digamos que tenemos una clase Persona que tiene atributos
para definir nombre, apellidos, DNI y operaciones para cambiar y consultar estos datos.
Digamos que queremos escribir un objeto de esta clase Persona por pantalla. Lo primero que
podemos pensar es hacer una funcin dentro de Persona que sea mostrarPorPantalla() y que
escriba en la salida estndar los datos. Sin embargo esto viola nuestra idea de POO, y veamos por
qu. Imaginemos que ahora queremos escribirlo en un fichero. Y en una base de datos. Y en un
Socket. Al final acabamos con una clase Persona que tiene mil y una funciones slo encargadas de
escribir esta clase Persona en diferentes lugares. Tambin podramos hablar de leer de fichero, de
base de datos, de Socket, de entrada estndar
Lo correcto es que nuestra clase Persona tenga funciones para servir sus datos de las formas que
se necesiten, y sean otras clases las encargadas de realizar la entrada y salida. Incluso, una clase se
puede encargar de la entrada y salida de Personas en un fichero, otra en una base de datos, otra
en un Socket En proyectos complejos es interesante crear clases ms simples y especializadas
que operen con un conjunto relativamente pequeo de datos, para facilitar la modularidad.
Despus de este tostn de buenas prcticas, volvamos a lo nuestro y analicemos las restricciones.
No queremos que nuestra Raqueta se salga por arriba ni por abajo (no nos podemos mover en
horizontal, as que izquierda y derecha ni nos interesan). Y, siguiendo nuestra encapsulacin
explicada arriba, es la Raqueta quien sabe sus atributos, por tanto es ella quien sabe si puede
moverse a un sitio o no, y no las dems clases. Una de las cosas que podemos hacer es crear una
nueva funcin para las raquetas que nos diga si podemos hacer un movimiento antes de hacerlo,
que tambin vamos a usar en la Bola (y adems va a ser igual). Para ello aadimos una nueva
declaracin a nuestra superclase ElementoPong:
publicbooleanpuedoMover(intx,inty,Rectscreen){
returnscreen.contains(origen.getX()+x,origen.getY()+y,
origen.getX()+ancho+x,origen.getY()+alto+y);
}
De esta forma podemos consultar si nuestro elemento (sea Raqueta o Bola) podr realizar el
movimiento o no. Con esta funcin estamos pasndole el rectngulo que forma la pantalla para
que la propia Raqueta Modificamos nuestro ACTION_MOVE para que quede as:
caseMotionEvent.ACTION_MOVE:
//hemosarrastrado
if(elementoActivo!=null){
Raquetar=(Raqueta)elementoActivo;
if(r.puedoMover(0,yorigenY,newRect(0,0,getWidth(),getHeight())))
r.move(0,yorigenY);
}
origenY=y;
break;
Ahora podemos ejecutar de nuevo el proyecto e intentar sacar las palas de la pantalla, el resultado
ser similar a este:
Parece ser que Android y los tipos enumerados de datos no se llevan especialmente bien y que se
recomienda usar static final int en lugar de enums, as que esta es la razn que influye para este
diseo. El constructor de la Bola sera el siguiente:
publicBola(Coordenadaorigen,intancho,intalto){
super(origen,ancho,alto);
direccion=1;
}
La variable direccin queda inicializada a 1 por ahora, pero ms adelante la cambiaremos (en otra
entrada). El mtodo move() queda de la siguiente forma:
@Override
publicvoidmove(intx,inty){
switch(direccion){
caseDCHA_ARRIBA:
origen.setX(origen.getX()+x);
origen.setY(origen.getY()y);
break;
caseIZDA_ARRIBA:
origen.setX(origen.getX()x);
origen.setY(origen.getY()y);
break;
caseIZDA_ABAJO:
origen.setX(origen.getX()x);
origen.setY(origen.getY()+y);
break;
caseDCHA_ABAJO:
origen.setX(origen.getX()+x);
origen.setY(origen.getY()+y);
break;
}
Bsicamente nos quitamos de trigonometra para hacer la explicacin ms simple ya que eso no
tiene nada que ver con Android. Ahora es el momento de hacer que automticamente la bola se
mueva. Para ello vamos a crear una nueva clase llamada BolaMoveThread con el siguiente cdigo:
packagecom.vidasconcurrentes.pongvc.juego;
publicclassBolaMoveThreadextendsThread{
privateBolabola;
privatebooleanrun;
privateintspeed;
publicBolaMoveThread(Bolabola){
this.bola=bola;
this.run=false;
this.speed=1;
}
publicvoidsetRunning(booleanrun){
this.run=run;
}
@Override
publicvoidrun(){
while(run){
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
e.printStackTrace();
}
bola.move(speed,speed);
}
}
}
Es muy similar al Thread que se encarga del pintado. Ahora tenemos que ejecutar el Thread. Para
ello, en la clase PongGameView, aadimos como nuevo atributo este Thread, de modo que ahora
tenemos todos estos atributos:
privatePongGameThreadpaintThread;
privateBolaMoveThreadbolaThread;
privateElementoPongraquetaIzda;
privateElementoPongraquetaDcha;
privateElementoPongbola;
privateElementoPongelementoActivo=null;
privateintorigenY;
Y por ltimo, en surfaceDestroyed() paramos el hilo, para que deje de mover la bola y muera:
@Override
publicvoidsurfaceDestroyed(SurfaceHolderarg0){
booleanretry=true;
paintThread.setRunning(false);
bolaThread.setRunning(false);
while(retry){
try{
paintThread.join();
bolaThread.join();
retry=false;
}catch(InterruptedExceptione){}
}
}
Ahora podemos ejecutar el proyecto y veremos que la bola se mueve en la diagonal del primer
cuadrante. Aqu tenemos un par de fotos de la ejecucin:
Ahora tenemos que crear los rebotes, primero con las paredes y luego con las raquetas. Por ahora
vamos a hacer que rebote con todos los lados de la pantalla. Para ello, creamos el siguiente
mtodo en la clase Bola:
publicvoidrebota(intx,inty,Rectscreen,
RectraquetaIzda,RectraquetaDcha){
if(!puedoMover(x,y,screen)){
switch(direccion){
caseDCHA_ARRIBA:
direccion=(origen.getY()y<=screen.top)?
DCHA_ABAJO:IZDA_ARRIBA;
break;
caseIZDA_ARRIBA:
direccion=(origen.getY()y<=screen.top)?
IZDA_ABAJO:DCHA_ARRIBA;
break;
caseIZDA_ABAJO:
direccion=(origen.getY()+alto+y>=screen.bottom)?
IZDA_ARRIBA:DCHA_ABAJO;
break;
caseDCHA_ABAJO:
direccion=(origen.getY()+alto+y>=screen.bottom)?
DCHA_ARRIBA:IZDA_ABAJO;
break;
}
}
}
Con esto estamos haciendo una pequea lgica de rebotes con la pantalla. Para hacernos una
idea, pongamos el ejemplo de que la bola vaya hacia arriba a la derecha (DCHA_ARRIBA). En este
caso slo podemos estar chocando con la parte de la derecha o la parte de arriba. Por ahora (ya lo
cambiaremos en la siguiente entrada), si choca en la derecha va a rebotar en lugar de marcar un
punto. Por tanto, si estamos yendo hacia la derecha y arriba (ngulo de 45), rebotaremos hacia
abajo y a la derecha (ngulo de 315, 45+315=360, con lo que comprobamos que est bien). Para
comprobar esto miramos que la parte mas alta de nuestra Bola, despus de moverse, haya
atravesado la pantalla por arriba. Si no es as, es que estamos chocando con la otra opcin: la
derecha.
La misma idea se usa para el resto de las situaciones.
Slo resta modificar el cdigo del run() en el BolaMoveThread:
@Override
publicvoidrun(){
while(run){
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
e.printStackTrace();
}
if(!bola.puedoMover(speed,speed,screen,
raquetaIzda.getRectElemento(),raquetaDcha.getRectElemento()))
bola.rebota(speed,speed,screen,
raquetaIzda.getRectElemento(),raquetaDcha.getRectElemento());
bola.move(speed,speed);
}
}
this.bola=bola;
this.raquetaIzda=izda;
this.raquetaDcha=dcha;
this.screen=screen;
this.run=false;
this.speed=1;
}
Si ejecutamos ahora, la bola rebotar indefinidamente por la pantalla atravesando las Raquetas.
Ahora vamos a crear los rebotes con stas. Para esta entrada vamos a comprobar los rebotes por
todos los lados de cada raqueta, aunque en el juego final hay colisiones que no tenemos que
comprobar (como el caso del lado izquierdo de la raqueta izquierda, o el del lado derecho de la
raqueta derecha). Modificamos el cdigo del mtodo rebota() aadiendo el siguiente cdigo:
Rectraqueta=null;
if(chocaraCon(x,y,raquetaIzda))
raqueta=raquetaIzda;
if(chocaraCon(x,y,raquetaDcha))
raqueta=raquetaDcha;
if(raqueta!=null){
switch(direccion){
caseDCHA_ARRIBA:
direccion=(origen.getX()+ancho<raqueta.left)?
IZDA_ARRIBA:DCHA_ABAJO;
break;
caseIZDA_ARRIBA:
direccion=(origen.getX()>raqueta.right)?
DCHA_ARRIBA:IZDA_ABAJO;
break;
caseIZDA_ABAJO:
direccion=(origen.getX()>raqueta.right)?
IZDA_ARRIBA:DCHA_ABAJO;
break;
caseDCHA_ABAJO:
direccion=(origen.getX()+ancho<raqueta.left)?
IZDA_ABAJO:DCHA_ARRIBA;
break;
Twittear
Follow
Share
Esta entrada fue publicada en Android, Curso introduccin Android, Programacin y etiquetada
como aplicacion android, eclipse, graficos android, java, thread.
Darker dijo:
27 julio, 2012 at 3:22
Muy buen tutorial!!!! Pero necesito ayuda, he seguido todos los pasos hasta el final de esta
parte, y se muestran las figuras pero no hay manera de moverlas. Me descargu tu versin y
esta todo igual. No se a que puede deberse y me estoy volviendo loco.
Gracias por adelantado y encantado de haber encontrado un tutorial as!
2.
ohcan dijo:
9 agosto, 2011 at 0:30
Buen trabajo META,prefiero que hagas el paso a paso,asi comprendo el codigo y su
funcion.UNsaludo
vidasConcurrentes
Sitio creado por meta y sshMan
Home
Blog
Sguenos
Concenos
Contacto
Vibracin
Para que una aplicacin pueda vibrar, ya que necesita acceder a un elemento del sistema, necesita
que el usuario acepte el uso de este elemento. Para ello tenemos que aadir al
AndroidManifest.xml que queremos usar vibracin. Tenemos dos formas, la primera es aadiendo
<uses-sdk android:minSdkVersion=7 /> justo detrs de la etiqueta <manifest >.
La segunda forma consiste en ir a la pestaa Permissions del manifest, pulsar en Add, elegir Uses
Permission y aceptar, y luego escribir android.permission.VIBRATE en el cuadro de la derecha. Lo
siguiente es programar el uso del vibrador.
El uso de la vibracin est definido por un Context, por lo que vamos a necesitar usar el contexto
de nuestra aplicacin para poder obtener el vibrador y posteriormente hacerlo vibrar. La vibracin
la vamos a realizar solamente cuando la Bola rebote en una de las dos Raquetas. Si recordamos
las entradas anteriores, nuestra Bola y nuestra Raqueta tenan una funcin llamada puedoMover(),
heredada de su superclase ElementoPong, que deca si se poda mover este elemento sin salirse
de la pantalla. Sabemos que cuando una bola rebota es porque se ha chocado con algo. Si se ha
chocado con algo pero an se puede mover por la pantalla significa que, por eliminacin, se ha
chocado con una raqueta. Ya tenemos planteado lo que vamos a hacer, as que hagmoslo.
Primero vamos a aadir un nuevo atributo a la clase BolaMoveThread de la siguiente forma:
privateVibratorv=null;
Este ser nuestro vibrador. Ahora necesitamos inicializarle, puesto que est a null y si lo usramos
ahora la aplicacin se morira debido a un NullPointerException (de ah que se inicialice a null, para
debuggearlo ms fcil). Para inicializarle necesitamos el Context de la aplicacin, de modo que al
constructor de BolaMoveThread le vamos a pasar el Context, quedando as:
publicBolaMoveThread(Bolabola,Raquetaizda,Raquetadcha,
Rectscreen,Contextcontext){
this.bola=bola;
this.raquetaIzda=izda;
this.raquetaDcha=dcha;
this.screen=screen;
this.run=false;
this.speed=1;
this.v=(Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
}
Categoras
Android
Curso introduccin
Android
Programacin
Seguridad
Sistemas Operativos
Entradas recientes
Automatizando la
creacin de entornos de
desarrollo con Vagrant
Colorshapes, el juego de
velocidad mental y figuras
de colores para Android
eyeOS: Trabajando en la
nube
Integrando Google
Analytics en aplicaciones
Android
Integrando Twitter en
aplicaciones Android con
SignPost y Twitter4J
Etiquetas
activity
algoritmo android
aplicacion android
arbol backtrack bash BD
acelerometro
BEeF
eclipse
expresiones regulares
graficos android
metasploit
metasploitable mitm
mysql oauth owasp
Sitios de inters
Android Developers
Android.es
Backtrack
bolaThread=newBolaMoveThread((Bola)bola,(Raqueta)raquetaIzda,
Command Line Kung Fu
(Raqueta)raquetaDcha,newRect(0,0,getWidth(),getHeight()),
this.getContext());
DragonJAR
El Androide Libre
Por ltimo slo queda hacer que vibre, para ello vamos a modificar el cdigo del run() del
BolaMoveThread de la siguiente forma:
Exploits Database
@Override
Flu Project
publicvoidrun(){
Gran Angular
while(run){
try{
Hispasec
Thread.sleep(10);
}catch(InterruptedExceptione){
Microsiervos
e.printStackTrace();
}
OpenLibra
if(!bola.puedoMover(speed,speed,screen,raquetaIzda.getRectElemento(),raquetaDcha.getRectElemento())){
bola.rebota(speed,speed,screen,raquetaIzda.getRectElemento(),raquetaDcha.getRectElemento());
Pentester.es
if(bola.puedoMover(speed,speed,screen))
Poesa Binaria
v.vibrate(50);
}
Security By Default
bola.move(speed,speed);
}
Un informtico en el lado
}
del mal
Con esto estamos haciendo una vibracin breve (50 milisegundos) cada vez que rebotamos
World Wide Web
contra una raqueta. Fcil, verdad?
Consistorium
Faltara cambiar la forma en que se crea este Thread de la siguiente forma (en el mtodo
surfaceCreated() del PongGameView:
Como informacin extra tenemos que saber que un objeto de la clase Vibrator tambin puede
vibrar dado un patrn, utilizando la funcin vibrate(pattern, repeat), siendo pattern un long[] y
repeat un int que dice cuntas veces se repite (-1 si no queremos repetir).
Sonido
El siguiente paso consistir en aadir sonido a los rebotes, el tpico sonido metlico. Existen
diversas formas de usar sonidos en Android, pero vamos a usar la ms simple de todas: el
MediaPlayer. Lo primero que tenemos que hacer es buscar un sonido que nos valga. Por lo general
se recomienda usar ficheros codificados en formato .ogg (Ogg Vorbis) por ser el ms compatible y
tener una gran compresin. Yo he elegido el siguiente sonido. Si quieres usar el mismo, haz click
derecho sobre el enlace y selecciona Guardar enlace como (y gurdalo con un nombre distinto, en
minsculas, sin espacios y sin tildes).
Ahora crearemos una nueva carpeta dentro de la carpeta res de nuestro proyecto, y la llamaremos
raw. Dentro de ella meteremos nuestro fichero de audio (en mi caso pong.ogg). A partir de ahora
podremos acceder a ello referenciando a R.raw.pong. Aadimos un nuevo atributo a
BolaMoveThread:
privateMediaPlayermp=null;
this.bola=bola;
this.raquetaIzda=izda;
this.raquetaDcha=dcha;
this.screen=screen;
this.run=false;
this.speed=1;
this.v=(Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
this.mp=MediaPlayer.create(context,R.raw.pong);
}
La llamada a MediaPlayer.create() crea y prepara el audio local para ser reproducido. Existe una
funcin de los objetos MediaPlayer llamada prepare() que hace lo mismo (pero slo hay que
llamarla en ciertos momentos, ahora explicamos ms). Falta hacer que reproduzca el sonido, de
modo que vamos a la funcin run(), que queda:
@Override
publicvoidrun(){
while(run){
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
e.printStackTrace();
if(!bola.puedoMover(speed,speed,screen,raquetaIzda.getRectElemento(),raquetaDcha.getRectElemento())){
mp.start();
bola.rebota(speed,speed,screen,raquetaIzda.getRectElemento(),raquetaDcha.getRectElemento());
if(bola.puedoMover(speed,speed,screen))
v.vibrate(50);
bola.move(speed,speed);
}
}
Podramos hacer un stop() y prepare() despus y antes (respectivamente) de cada start(). Sin
embargo eso sera un consumo muy grande de los recursos, y start() ya mantiene preparado el
audio para hacer un replay. Sera interesante, sin embargo, hacer una llamada a stop() y prepare()
dentro del setRunning() dependiendo de si paramos o iniciamos el thread. Agregar sonidos
simples ha resultado ser tambin muy fcil, no?
Activar y desactivar
Ahora mismo tenemos que la aplicacin hace que el dispositivo vibre al rebotar con una pala, y
hace que reproduzca un sonido de choque metlico cada vez que rebote con algo (sea pared o
raqueta). Recordemos que tenemos un men en el cual tenamos una parte de Opciones, pero
que no tena nada dentro. Es ahora el momento de crear las opciones del juego, permitiendo
activar y desactivar estas dos funcionalidades.
Comenzamos creando un nuevo layout que tendr el siguiente cdigo:
<?xmlversion="1.0"encoding="utf8"?>
<TableLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TableRowandroid:id="@+id/tableRow1"android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextViewandroid:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"android:layout_height="wrap_content"
android:width="250dip"android:paddingLeft="30dip"android:id="@+id/labelSonido"
android:text="@string/sonidoMenu"></TextView>
<CheckBoxandroid:layout_width="wrap_content"android:id="@+id/checkBoxSonido"
android:layout_height="wrap_content"android:checked="true"></CheckBox>
</TableRow>
<TableRowandroid:id="@+id/tableRow2"android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextViewandroid:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"android:layout_height="wrap_content"
android:paddingLeft="30dip"android:id="@+id/labelVibracion"
android:text="@string/vibracionMenu"></TextView>
<CheckBoxandroid:layout_width="wrap_content"android:id="@+id/checkBoxVibracion"
android:layout_height="wrap_content"android:checked="true"></CheckBox>
</TableRow>
</TableLayout>
<stringname="app_name">Pong</string>
<stringname="menu_play">Jugar</string>
<stringname="menu_options">Opciones</string>
<stringname="menu_exit">Salir</string>
<stringname="sonidoMenu">Sonido</string>
<stringname="vibracionMenu">Vibracin</string>
</resources>
Tenemos que aadir la Activity al AndroidManifest.xml igual que hicimos en otra de las entradas.
Para ello abrimos el AndroidManifest.xml y aadimos lo siguiente antes de </application>:
<activityandroid:name=".PongOpcionesActivity"android:screenOrientation="portrait"></activity>
Lo siguiente que necesitamos hacer es aadir el cdigo necesario para crear una actividad nueva
que muestre este nuevo layout. Creamos una nueva clase llamada PongOpcionesActivity, cuyo
cdigo es el siguiente:
packagecom.vidasconcurrentes.pongvc;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.view.Window;
importandroid.view.WindowManager;
publicclassPongOpcionesActivityextendsActivity{
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.options);
}
}
Ahora slo falta hacer el cdigo en la actividad principal para que se ejecute esta. Para ello vamos a
la clase PongvCActivity (la principal), y aadimos la funcin:
privatevoidmuestraOpciones(){
Intentopciones=newIntent(this,PongOpcionesActivity.class);
this.startActivity(opciones);
}
Ahora en el onCreate() de esta clase, vamos al lugar donde registramos el listener para el botn de
Opciones y cambiamos el contenido por lo siguiente:
TextViewoptions=(TextView)findViewById(R.id.options_button);
options.setOnClickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
muestraOpciones();
}
});
Ahora s, si hacemos una ejecucin, obtendremos esto tras pulsar en el botn Opciones del men
principal:
Ahora tenemos que programar qu pasa cuando activamos y desactivamos estos checkboxes. He
elegido hacer lo siguiente con un patrn Singleton. A grandes rasgos, un patrn Singleton ofrece la
garanta de que existe como mximo una instancia de una clase y que es accesible globalmente.
Nosotros queremos poder acceder al estado de estas opciones desde el juego, pero modificarlas
desde esta actividad. De modo que comenzamos creando nuestra clase PongOpciones dentro de
un nuevo paquete llamado com.vidasconcurrentes.pongvc.opciones:
packagecom.vidasconcurrentes.pongvc.opciones;
publicclassPongOpciones{
privatestaticPongOpcionesopciones=null;
privatebooleansonido;
privatebooleanvibracion;
privatePongOpciones(){
sonido=true;
vibracion=true;
}
publicstaticsynchronizedPongOpcionesgetInstance(){
if(opciones==null)
opciones=newPongOpciones();
returnopciones;
}
publicvoidtoggleSound(){
sonido=!sonido;
}
publicvoidtoggleVibration(){
vibracion=!vibracion;
}
publicbooleansoundEnabled(){
returnsonido;
}
publicbooleanvibrationEnabled(){
returnvibracion;
}
Las ponemos inicializadas a true porque, por defecto, nuestra aplicacin va a tener ambas
activadas. Ahora aadimos el comportamiento al pulsar sobre los checkboxes. Para ello vamos al
onCreate() de la clase PongOpcionesActivity y aadimos lo siguiente al final:
CheckBoxsonido=(CheckBox)findViewById(R.id.checkBoxSonido);
sonido.setOnClickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
PongOpciones.getInstance().toggleSound();
}
});
CheckBoxvibracion=(CheckBox)findViewById(R.id.checkBoxVibracion);
vibracion.setOnClickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
PongOpciones.getInstance().toggleVibration();
}
});
sonido.setChecked(PongOpciones.getInstance().soundEnabled());
vibracion.setChecked(PongOpciones.getInstance().vibrationEnabled());
Como vemos, lo ltimo que hacemos es poner el estado de cada CheckBox acorde con el estado
de la instancia del patrn Singleton. Cuando pulsamos en un CheckBox, cambiamos el valor de la
variable a la que se refiere de true a false y viceversa.
Efectivamente, si ejecutsemos ahora, comprobaramos que podemos tener ambas activas,
desactivadas o una activa y otra no.
Acelermetro
El acelermetro del dispositivo va a permitirnos registrar movimientos de ste para saber si se ha
cambiado la inclinacin con respecto de la posicin inicial con la que se comenz el juego. Existen
varias formas de usar el acelermetro, y por supuesto existen muchsimas e infinitas formas de
programar dnde debe ir cada cosa en nuestro proyecto.
Mis decisiones han sido las siguientes:
Queremos que se ejecute un Thread que controle la raqueta izquierda con el acelermetro.
Queremos quitar el registro del acelermetro cuando no lo necesitemos.
Queremos reanudar el uso del acelermetro al volver al juego.
Al igual que hicimos al crear los hilos anteriores (pintado y movimiento de la bola), vamos a crear
un hilo nuevo para las raquetas:
packagecom.vidasconcurrentes.pongvc.juego;
importandroid.graphics.Rect;
publicclassRaquetaMoveThreadextendsThread{
privateRaquetaraqueta;
privateRectscreen;
privatebooleanrun;
publicRaquetaMoveThread(Raquetar,Rects){
raqueta=r;
screen=s;
}
publicvoidsetRunning(booleanrun){
this.run=run;
}
publicvoidrun(){
while(run){
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
e.printStackTrace();
}
//nuestrocodigovaaqui
booleanretry=true;
paintThread.setRunning(false);
bolaThread.setRunning(false);
raquetaThread.setRunning(false);
while(retry){
try{
paintThread.join();
bolaThread.join();
raquetaThread.join();
retry=false;
}catch(InterruptedExceptione){}
}
}
Ahora es el momento de crear nuestro acelermetro. Para ello vamos a crear una clase envolvente
para la funcionalidad que queremos que nos ofrezca. Un dispositivo emulado no puede usar
acelermetro, as que ser necesario el uso de un dispositivo fsico.
Nosotros vamos a querer que se mueva la raqueta. Esta raqueta pertenece a una actividad que
est en modo landscape (apaisado) continuamente. Un dispositivo fsico tiene su eje X a lo alto, es
decir, es una lnea imaginaria que va desde los botones del dispositivo hasta el auricular. Si lo
prefers: de abajo a arriba. Su eje Y es el perpendicular a ste que cruza de lado a lado. Como hasta
ahora hemos visto a la hora de pintar, con el dispositivo en modo apaisado, el eje X ser el ancho y
el eje Y ser el alto. De modo que si nosotros rotamos el dispositivo hacia delante en modo
apaisado, queremos que nuestra pala suba. Si rotamos el dispositivo hacia nosotros en modo
apaisado, queremos que nuestra pala baje.
Dicho en otras palabras: si la rotacin del eje X es negativa, queremos que vaya arriba; si es
positiva, queremos que vaya abajo. Para ms informacin sobre los ejes de coordenadas
tridimensionales pulsa aqu.
Por tanto slo nos interesa la rotacin del eje X para nuestra pala, pero podemos acceder a los
valores de Y y Z consultando event.values[1] y event.values[2] respectivamente. Creamos una
nueva clase AcelerometroPong en el paquete com.vidasconcurrentes.pongvc.juego:
packagecom.vidasconcurrentes.pongvc.juego;
importandroid.content.Context;
importandroid.hardware.Sensor;
importandroid.hardware.SensorEvent;
importandroid.hardware.SensorEventListener;
importandroid.hardware.SensorManager;
publicclassAcelerometroPongimplementsSensorEventListener{
privateSensorManagersm=null;
privateintx;
publicAcelerometroPong(Contextcontext){
sm=(SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
}
publicvoidregister(){
sm.registerListener(this,sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
publicvoidunregister(){
sm.unregisterListener(this);
}
@Override
publicvoidonAccuracyChanged(Sensorsensor,intaccuracy){}
@Override
publicvoidonSensorChanged(SensorEventevent){
if(event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){
x=Math.round(event.values[0]*100);
}
}
publicintgetXInclination(){
returnx;
}
Desde la Activity PongJuego vamos a usar esta clase como atributo, y aadiremos dos nuevos
mtodos de modo que quedar as:
packagecom.vidasconcurrentes.pongvc;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.view.Window;
importandroid.view.WindowManager;
importcom.vidasconcurrentes.pongvc.juego.AcelerometroPong;
importcom.vidasconcurrentes.pongvc.pintado.PongGameView;
publicclassPongJuegoextendsActivity{
privateAcelerometroPongacelerometro;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
acelerometro=newAcelerometroPong(this.getApplicationContext());
setContentView(newPongGameView(this,acelerometro));
@Override
protectedvoidonResume(){
super.onResume();
acelerometro.register();
}
@Override
protectedvoidonStop(){
super.onStop();
acelerometro.unregister();
}
super(context);
getHolder().addCallback(this);
this.acelerometro=acelerometro;
Ahora, queremos que sea el Thread que controla el movimiento de la raqueta el encargado de
consultar el acelermetro, as que igualmente cambiamos el constructor de ste y lo aadimos
raqueta=r;
screen=s;
this.acelerometro=a;
}
Adems, aadimos esta nueva variable xInit de tipo Integer (para poder inicializarla a null). Y por
qu queremos inicializarla a null? Es tan slo una pequea treta que se me ha ocurrido para poder
realizar una calibracin en cada ejecucin. Si es null es que an no hemos calibrado la posicin en
la que est el dispositivo al arrancar el Thread, si no es null es que ya est calibrado.
Ahora modificaremos el run() de este Thread, de la siguiente forma:
publicvoidrun(){
if(xInit==null)
xInit=acelerometro.getXInclination();
while(run){
try{
if(Math.abs(xInitacelerometro.getXInclination())<200)
Thread.sleep(5);
else
Thread.sleep(2);
}catch(InterruptedExceptione){
e.printStackTrace();
if(xInit<acelerometro.getXInclination()UMBRAL||
xInit<acelerometro.getXInclination()+UMBRAL)
if(raqueta.puedoMover(0,1,screen))
raqueta.move(0,1);
if(xInit>acelerometro.getXInclination()UMBRAL||
xInit>acelerometro.getXInclination()+UMBRAL)
if(raqueta.puedoMover(0,1,screen))
raqueta.move(0,1);
}
Lo primero que hacemos es inicializar la posicin de calibrado, si es null. Lo siguiente que hacemos
es hacer que el movimiento de la raqueta sea ms o menos rpido dependiendo de si hemos
inclinado mucho el dispositivo o no. En nuestro caso, si hay una diferencia absoluta (positiva o
negativa) de menos de 200 unidades, entonces nos vamos a mover a una velocidad normal. Si
esto es mayor significa que hemos inclinado el dispositivo mucho ms, por lo que deseamos que
se mueva ms rpido. La variable UMBRAL no es ms que una variable final de la clase que en este
caso tiene el valor de 20. Este UMBRAL nos sirve para no mover la raqueta si el movimiento es
demasiado pequeo (quiz por errores de medida o de redondeo). Adems aadimos la
comprobacin de si puedoMover() para evitar salirse de la pantalla.
Con esto ya tenemos la raqueta izquierda funcionando para moverse con el acelermetro, pero a
la vez funciona con el dedo y esto no es lo deseable.
sonido=true;
vibracion=true;
acelerometro=false;
}
Aadimos tambin los siguientes dos mtodos, para cambiar el valor y consultarlo:
publicvoidtoggleAcelerometro(){
acelerometro=!acelerometro;
}
publicbooleanaccelerometerEnabled(){
returnacelerometro;
}
Ahora tenemos que llamar a estos mtodos desde la actividad de las opciones, la cual necesita ser
cambiada para aadir una nueva fila. Por tanto, antes del </TableLayout> de options.xml,
aadimos:
<TableRowandroid:id="@+id/tableRow3"android:layout_width="wrap_content"android:layout_height="wrap_content">
<TextViewandroid:textAppearance="?android:attr/textAppearanceLarge"android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/labe
<CheckBoxandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/checkBoxAccel"></CheckBox>
</TableRow>
Hay que aadir tambin el String al fichero strings.xml. De esta forma veramos la siguiente
imagen al ejecutar:
@Override
publicvoidonClick(Viewv){
PongOpciones.getInstance().toggleAcelerometro();
}
});
acelerometro.setChecked(PongOpciones.getInstance().accelerometerEnabled());
raquetaThread=newRaquetaMoveThread((Raqueta)raquetaIzda,
newRect(0,0,getWidth(),getHeight()),acelerometro);
raquetaThread.setRunning(true);
raquetaThread.start();
}
booleanretry=true;
paintThread.setRunning(false);
bolaThread.setRunning(false);
if(PongOpciones.getInstance().accelerometerEnabled())
raquetaThread.setRunning(false);
while(retry){
try{
paintThread.join();
bolaThread.join();
if(PongOpciones.getInstance().accelerometerEnabled())
raquetaThread.join();
retry=false;
}catch(InterruptedExceptione){}
}
//aquitodoelcodigoanterior,incluyendoelswitch
}
returntrue;
Hecho esto podemos ejecutar la aplicacin y trastear con ella activando y desactivando cosas,
reiniciando el juego La idea es iniciar el juego, pulsar la tecla de actividad anterior que nos lleva
al men, elegir Opciones y cambiarlas, dar a actividad anterior y luego a Jugar.
Aqu llega el final de la entrada de hoy. En ella hemos visto cmo usar distintos sensores del
sistema como la vibracin o el acelermetro, adems de las herramientas que nos ofrece para
reproducir sonidos locales. En la siguiente entrada acabaremos la aplicacin aadiendo las ltimas
mejoras como un pequeo umbral para el juego tctil, el marcador de juego y la posibilidad de que
se cuele la bola y por ltimo una pequea Inteligencia Artificial para la raqueta derecha.
Como siempre, podis descargar el proyecto de Eclipse desde aqu (MD5:
1e3eeda28b041716b8526aa59f1aa312) e importarlo a vuestro Eclipse.
Muchas gracias por la lectura y hasta la prxima semana!
0. Creando una aplicacin de Android: la presentacin
1. Creando una aplicacin de Android: primeros pasos
2. Creando una aplicacin de Android: visin de conjunto y diseo del men
3. Creando una aplicacin de Android: el juego y la lgica (parte 1)
4. Creando una aplicacin de Android: el juego y la lgica (parte 2)
5. Creando una aplicacin de Android: mejoras (parte 1)
6. Creando una aplicacin de Android: mejoras (parte 2)
7. Creando una aplicacin de Android: empaquetado y publicacin
Like
Twittear
Follow
Share
Esta entrada fue publicada en Android, Curso introduccin Android, Programacin y etiquetada
como acelerometro, activity, aplicacion android, mejoras, sonido, vibracion.
ohcan dijo:
22 agosto, 2011 at 0:02
Gracias como siempre,en cuanto tenga tiempo me pongo a picar codigo,desarrollas cosas
muy interesantes en este simple juego
vidasConcurrentes
Sitio creado por meta y sshMan
Home
Blog
Sguenos
Concenos
Contacto
Categoras
Android
Curso introduccin
Android
Programacin
Seguridad
Sistemas Operativos
Entradas recientes
Automatizando la
creacin de entornos de
desarrollo con Vagrant
Colorshapes, el juego de
velocidad mental y figuras
de colores para Android
eyeOS: Trabajando en la
nube
Integrando Google
Analytics en aplicaciones
Android
Integrando Twitter en
aplicaciones Android con
SignPost y Twitter4J
Etiquetas
activity
algoritmo android
aplicacion android
arbol backtrack bash BD
acelerometro
BEeF
eclipse
expresiones regulares
caseMotionEvent.ACTION_DOWN:
//hemospulsado
Rectaux;
aux=newRect(raquetaIzda.getRectElemento());
aux.set(aux.leftUMBRAL_TACTIL,aux.top,
aux.right+UMBRAL_TACTIL,aux.bottom);
graficos android
if(aux.contains(x,y)){
elementoActivo=raquetaIzda;
origenY=y;
break;
}
metasploitable mitm
metasploit
13
14
15
16
17
18
19
20
21
22
aux=newRect(raquetaDcha.getRectElemento());
aux.set(aux.leftUMBRAL_TACTIL,aux.top,
aux.right+UMBRAL_TACTIL,aux.bottom);
if(aux.contains(x,y)){
elementoActivo=raquetaDcha;
origenY=y;
break;
}
break;
As, usamos un rectngulo a partir de los rectngulos definidos por las raquetas, con la salvedad de
que los expandimos por los lados tantas unidades como UMBRAL_TACTIL diga. Hasta aqu la
mejora del control tctil.
Marcador
Lo siguiente que vamos a hacer es crear el marcador de juego y todo lo necesario para que
funcione. Es decir, cuando completemos esta seccin tendremos algo jugable de principio a fin.
Comenzamos creando una clase Marcador:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
packagecom.vidasconcurrentes.pongvc.juego;
publicclassMarcador{
publicstaticfinalintMAX_PUNT=9;
privateintpuntosIzda;
privateintpuntosDcha;
publicvoidinitMarcador(){
puntosIzda=0;
puntosDcha=0;
}
publicMarcador(){
initMarcador();
}
publicintgetPuntosIzda(){
returnpuntosIzda;
}
publicintgetPuntosDcha(){
returnpuntosDcha;
}
publicvoidaddPuntoIzda(){
puntosIzda++;
}
publicvoidaddPuntoDcha(){
puntosDcha++;
}
publicbooleanacabado(){
returnpuntosDcha==MAX_PUNT||puntosIzda==MAX_PUNT;
}
}
De esta forma estamos definiendo que el juego acabar cuando uno de los dos jugadores haga 9
puntos. Adems estamos definiendo los comportamientos necesarios para inicializar el marcador,
consultar el valor y aadir un punto a los jugadores.
Una cosa est clara cuando programamos, y es que queremos ver que las cosas que hacemos
funcionan, y queremos verlo lo antes posible. Por esta razn lo siguiente que vamos a hacer es lo
necesario para mostrar en pantalla el marcador para que veamos que lo que vayamos haciendo
realmente funciona.
Vamos a la clase PongGameView y aadimos un nuevo atributo de clase Marcador:
1 privateMarcadormarcador;
Adems, aadimos el constructor de este objeto al constructor de la clase, de modo que el
constructor quedar:
1 publicPongGameView(Contextcontext,AcelerometroPongacelerometro)
{
2
3
4
5
6
7
super(context);
getHolder().addCallback(this);
this.acelerometro=acelerometro;
this.marcador=newMarcador();
}
Ahora ya contamos con un marcador. Lo siguiente ser crear en PongGameView las funciones
necesarias para pintar los nmeros en pantalla. Queremos crear una linea divisoria a la mitad de la
pantalla, al estilo Pong original. Comenzamos creando este mtodo:
Sitios de inters
Android Developers
Android.es
Backtrack
Command Line Kung Fu
DragonJAR
El Androide Libre
Exploits Database
Flu Project
Gran Angular
Hispasec
Microsiervos
OpenLibra
Pentester.es
Poesa Binaria
Security By Default
Un informtico en el lado
del mal
World Wide Web
Consistorium
1
2
3
4
5
6
7
8
9
10
11
12
privatevoiddrawCenterLine(Canvascanvas,Paintpaint){
intw=6;
inth=20;
intgap=10;
intini=gap/2;//porestetica,sinoseria0
for(inti=0;i<this.getHeight()/(h+gap);i++){
canvas.drawRect(this.getWidth()/2w/2,ini,
this.getWidth()/2+w/2,ini+h,paint);
ini+=h+gap;
}
}
En este cdigo tenemos unas variables iniciales, que muy bien podan ser parte de los atributos de
la clase puesto que no vamos a modificarlos en ningn momento, pero quera mantener la
explicacin en cdigos breves. La variable w ser el ancho de cada una de las lineas divisorias. Se
recomienda que sea par. La variable h es la altura de cada linea divisoria y gap es el espacio entre
una y otra linea. La variable ini define dnde comenzaremos a pintar. He elegido gap / 2 para su
inicializacin para que est igual de separada por arriba que por abajo de los lmites, pero es una
eleccin emprica. En el bucle vamos pintando cada uno de los tramos de la linea discontnua
hasta llegar abajo. Slo faltara aadir la llamada a este mtodo dentro del onDraw():
1
2
3
4
5
6
7
8
9
10
11
@Override
publicvoidonDraw(Canvascanvas){
Paintpaint=newPaint();
paint.setColor(Color.WHITE);
canvas.drawColor(Color.BLACK);
drawCenterLine(canvas,paint);
canvas.drawRect(raquetaIzda.getRectElemento(),paint);
canvas.drawRect(raquetaDcha.getRectElemento(),paint);
canvas.drawRect(bola.getRectElemento(),paint);
}
Lo siguiente que vamos a aadir es el pintado de los nmeros de las puntuaciones de cada
jugador. Adems, vamos a usar una font propia, que no viene en el SDK de Android. Lo primero
ser buscar una, yo eleg la font Kelly Slab de Google Web Fonts. Ahora la incluimos en nuestra
aplicacin, para lo cual vamos a aadir un directorio llamado fonts en nuestro directorio assets, y
ah incluimos nuestra recin descargada font:
privatevoiddrawMarcador(Canvascanvas,Paintpaint){
paint.setTextAlign(Align.CENTER);
paint.setTypeface(Typeface.createFromAsset(this.getContext().getAssets(),
"fonts/KellySlabRegular.ttf"));
paint.setTextSize(80);
paint.setAntiAlias(true);
canvas.drawText(Integer.toString(marcador.getPuntosIzda()),
getWidth()/280,80,paint);
canvas.drawText(Integer.toString(marcador.getPuntosDcha()),
getWidth()/2+80,80,paint);
}
Con esto aadimos opciones al objeto Paint y pintamos los nmeros del marcador. Si ahora
modificamos el mtodo onDraw():
1
2
3
4
@Override
publicvoidonDraw(Canvascanvas){
Paintpaint=newPaint();
paint.setColor(Color.WHITE);
5
6
7
8
9
10
11
12
canvas.drawColor(Color.BLACK);
drawCenterLine(canvas,paint);
drawMarcador(canvas,paint);
canvas.drawRect(raquetaIzda.getRectElemento(),paint);
canvas.drawRect(raquetaDcha.getRectElemento(),paint);
canvas.drawRect(bola.getRectElemento(),paint);
}
Si continuamos con el cdigo actual, con lo de arriba explicado, hagamos una reflexin. Pongamos
que la carga de esa font gastara 1KB de memoria por cada ejecucin. Nuestos dispositivos tienen
512MB de media, as que eso no es un problema! Falso.
Nuestra aplicacin no ejecuta un nmero de frames por segundo fijo, sino que ejecuta todo lo
rpido que puede. Por ejemplo, la aplicacin podra estar refrescando la pantalla a una velocidad
de 60FPS, lo que conlleva una carga de la font en cada refresco con el consecuente tiempo de
carga y el consecuente gasto de memoria. Si esto lo prolongamos con el tiempo entonces nos
vamos a quedar sin memoria (been there, done that).
Por lo tanto, dado que esto no es un PC de mesa que suelen tener varios GB de memoria RAM
es de especial importancia no realizar la carga de ficheros sin necesidad (y otras operaciones
costosas y que comen RAM). Si podemos hacerlas una sola vez, mejor.
Ahora s, vamos a crear el cdigo necesario y relativamente optimizado. Lo primero va a ser
agregar el siguiente atributo a la clase PongGameView:
1 privatePaintpaint;
Ahora el constructor de la clase ser de la siguiente forma (puesto que el objeto Paint no se
modifica en los dems mtodos):
1 publicPongGameView(Contextcontext,AcelerometroPongacelerometro)
{
2 super(context);
3 getHolder().addCallback(this);
4
5 this.acelerometro=acelerometro;
6 this.marcador=newMarcador();
7
8 paint=newPaint();
9 paint.setColor(Color.WHITE);
10 paint.setTextAlign(Align.CENTER);
11 paint.setTypeface(Typeface.createFromAsset(this.getContext().getAssets(),
12 "fonts/KellySlabRegular.ttf"));
13 paint.setTextSize(80);
14 paint.setAntiAlias(true);
15 }
El mtodo de pintado completo ser el conjunto de lo siguiente:
1 @Override
2 publicvoidonDraw(Canvascanvas){
3 canvas.drawColor(Color.BLACK);
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
drawCenterLine(canvas);
drawMarcador(canvas);
canvas.drawRect(raquetaIzda.getRectElemento(),paint);
canvas.drawRect(raquetaDcha.getRectElemento(),paint);
canvas.drawRect(bola.getRectElemento(),paint);
}
privatevoiddrawCenterLine(Canvascanvas){
intw=6;
inth=20;
intgap=10;
intini=gap/2;//porestetica,sinoseria0
for(inti=0;i<this.getHeight()/(h+gap);i++){
canvas.drawRect(this.getWidth()/2w/2,ini,
this.getWidth()/2+w/2,ini+h,paint);
ini+=h+gap;
}
}
privatevoiddrawMarcador(Canvascanvas){
canvas.drawText(Integer.toString(marcador.getPuntosIzda()),
getWidth()/280,80,paint);
canvas.drawText(Integer.toString(marcador.getPuntosDcha()),
28 getWidth()/2+80,80,paint);
29 }
Ahora s, tenemos un pintado inteligente intentando optimizar el uso de Paint.
El siguiente paso ser hacer que, al tocar en uno de los laterales de la pantalla (izquierdo o
derecho), se sume un punto al jugador en cuestin.
Comenzamos modificando el mtodo rebota() de la Bola, de modo que ahora va a devolver un
valor. Devolver -1 si la bola entr por la izquierda, 1 si entr por la derecha y 0 si sigue en la
pantalla. Por tanto, este mtodo ahora es:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
publicintrebota(intx,inty,Rectscreen,RectraquetaIzda,
RectraquetaDcha){
if(!puedoMover(x,y,screen)){
switch(direccion){
caseDCHA_ARRIBA:
if(origen.getY()y<=screen.top)
direccion=DCHA_ABAJO;
else
return1;
break;
caseIZDA_ARRIBA:
if(origen.getY()y<=screen.top)
direccion=IZDA_ABAJO;
else
return1;
break;
caseIZDA_ABAJO:
if(origen.getY()+alto+y>=screen.bottom)
direccion=IZDA_ARRIBA;
else
return1;
break;
caseDCHA_ABAJO:
if(origen.getY()+alto+y>=screen.bottom)
direccion=DCHA_ARRIBA;
else
return1;
break;
}
}
Rectraqueta=null;
if(chocaraCon(x,y,raquetaIzda))
raqueta=raquetaIzda;
if(chocaraCon(x,y,raquetaDcha))
raqueta=raquetaDcha;
if(raqueta!=null){
switch(direccion){
caseDCHA_ARRIBA:
direccion=(origen.getX()+ancho<raqueta.left)?
IZDA_ARRIBA:DCHA_ABAJO;
break;
caseIZDA_ARRIBA:
direccion=(origen.getX()>raqueta.right)?
DCHA_ARRIBA:IZDA_ABAJO;
break;
caseIZDA_ABAJO:
direccion=(origen.getX()>raqueta.right)?
49
50
51
52
53
54
55
56
57
58
59
IZDA_ARRIBA:DCHA_ABAJO;
break;
caseDCHA_ABAJO:
direccion=(origen.getX()+ancho<raqueta.left)?
IZDA_ABAJO:DCHA_ARRIBA;
break;
}
}
return0;
}
De esta forma hemos modificado la primera parte del cdigo del mtodo, si ahora mismo
ejecutsemos la aplicacin podramos ver que la bola se cuela por los lados, pero no ocurre nada.
Ahora es cuando haremos que ocurra ese algo al colarse.
Comenzamos aadiendo el Marcador a la clase BolaMoveThread, pues va a ser ste el que se
encargue de modificarlo. El constructor con el nuevo atributo quedara:
1
2
3
4
5
6
7
8
9
10
11
privateMarcadormarcador;
publicBolaMoveThread(Bolabola,Raquetaizda,Raquetadcha,
Rectscreen,Contextcontext,Marcadormarcador){
this.bola=bola;
this.raquetaIzda=izda;
this.raquetaDcha=dcha;
this.screen=screen;
this.run=false;
this.speed=1;
this.v=(Vibrator)
context.getSystemService(Context.VIBRATOR_SERVICE);
12 this.mp=MediaPlayer.create(context,R.raw.pong);
13 this.marcador=marcador;
14 }
Ahora vamos a modificar el mtodo run() de esta clase. Queremos que, si el mtodo bola.rebota()
devuelve 0, haga lo que hace hasta ahora. Si devuelve -1 queremos que sume un punto a la
raqueta derecha y si devuelve 1 que sume a la raqueta izquierda (recordamos que el signo indica
por qu lado entr). De esta forma, modificamos as:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@Override
publicvoidrun(){
while(run){
try{
Thread.sleep(5);
}catch(InterruptedExceptione){
e.printStackTrace();
}
if(punto){
try{
Thread.sleep(2000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
if(!marcador.acabado()){
punto=false;
}
continue;
}
if(!bola.puedoMover(speed,speed,screen,
raquetaIzda.getRectElemento(),
raquetaDcha.getRectElemento())){
switch(bola.rebota(speed,speed,screen,
raquetaIzda.getRectElemento(),
raquetaDcha.getRectElemento())){
case0:
if(PongOpciones.getInstance().soundEnabled())
mp.start();
if(bola.puedoMover(speed,speed,screen)&&
PongOpciones.getInstance().vibrationEnabled())
v.vibrate(50);
break;
case1:
marcador.addPuntoDcha();
reinitBola();
punto=true;
break;
case1:
marcador.addPuntoIzda();
reinitBola();
punto=true;
break;
}
43
44
45
46
}
bola.move(speed,speed);
}
}
23
24
privateintbolaInitX;
privateintbolaInitY;
privatebooleanpunto;
publicBolaMoveThread(Bolabola,Raquetaizda,Raquetadcha,
Rectscreen,Contextcontext,Marcadormarcador){
this.bola=bola;
this.bolaInitX=bola.getOrigenX();
this.bolaInitY=bola.getOrigenY();
this.raquetaIzda=izda;
this.raquetaDcha=dcha;
this.screen=screen;
this.run=false;
this.speed=1;
this.v=(Vibrator)
16
17
18
19
20
21
22
23
24
context.getSystemService(Context.VIBRATOR_SERVICE);
this.mp=MediaPlayer.create(context,R.raw.pong);
this.marcador=marcador;
this.punto=false;
}
privatevoidreinitBola(){
bola.setOrigenX(bolaInitX);
bola.setOrigenY(bolaInitY);
}
Adems hemos cambiado el primer Thread.sleep() a 5 para que vaya ms rpido la bola con
respecto de cmo iba hasta ahora. Una pequea y rpida partida jugando a propsito nos podra
dar la siguiente imagen:
Ya tenemos el marcador completo, funcional y en pantalla. Sin embargo, si ahora mismo jugamos
y volvemos al men en mitad de una partida, no mantendremos nuestra puntuacin guardada.
Para ilustrar el paso de datos entre actividades vamos a hacer que se mantenga la puntuacin.
Lo primero que tenemos que hacer es modificar el cdigo en la clase PongvCActivity. Localizamos
el mtodo empiezaJuego(), que contiene este cdigo:
1
2
3
4
privatevoidempiezaJuego(){
Intentjuego=newIntent(this,PongJuego.class);
this.startActivity(juego);
}
privatevoidempiezaJuego(){
Intentjuego=newIntent(this,PongJuego.class);
this.startActivityForResult(juego,Activity.RESULT_OK);
}
De esta forma, en lugar de iniciar una Activity nueva, decimos que queremos que nos mande algo
de vuelta. Ahora tenemos que crear el lugar donde procesar ese algo. Para ello sobrecargamos el
mtodo onActivityResult():
1 @Override
2 publicvoidonActivityResult(intrequestCode,intresultCode,
Intentdata){
3 super.onActivityResult(requestCode,resultCode,data);
4 switch(requestCode){
5 case1:
6 if(resultCode==Activity.RESULT_OK){
7 //solosielcodigodevueltoesRESULT_OK,procesamos
8 }
9 break;
10 }
11 }
Lo siguiente que vamos a hacer es crear el cdigo que devuelve las puntuaciones del marcador.
Vamos a la clase PongJuego, y aadimos el siguiente atributo con la necesaria modificacin del
constructor:
1
2
3
4
5
6
7
8
9
10
privateAcelerometroPongacelerometro;
privatePongGameViewview;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
acelerometro=new
AcelerometroPong(this.getApplicationContext());
11 view=newPongGameView(this,acelerometro);
12 setContentView(view);
13 }
Adems, en PongGameView vamos a poner un nuevo mtodo:
1 publicMarcadorgetMarcador(){
2 returnmarcador;
3 }
As podremos consultar el marcador desde la actividad y poder devolver el valor. Para ello, en
PongJuego crearemos el siguiente mtodo:
1
2
3
4
5
6
7
8
9
10
11
@Override
publicvoidonBackPressed(){
Bundlebundle=newBundle();
bundle.putInt("PuntosIzda",
view.getMarcador().getPuntosIzda());
bundle.putInt("PuntosDcha",
view.getMarcador().getPuntosDcha());
IntentmIntent=newIntent();
mIntent.putExtras(bundle);
setResult(Activity.RESULT_OK,mIntent);
super.onBackPressed();
}
Ahora slo falta procesar estos datos devueltos. Lo primero ser aadir dos nuevos atributos en
PongvCActivity, con su inicializacin:
1 privateintpuntosIzdaIniciales=0;
2 privateintpuntosDchaIniciales=0;
Ahora volvemos al mtodo onActivityResult() de la clase PongvCActivity, y aadimos el cdigo
interno a este if:
1
2
3
4
5
if(resultCode==Activity.RESULT_OK&&data.getExtras()!=null){
//solosielcodigodevueltoesRESULT_OK,procesamos
puntosIzdaIniciales=data.getExtras().getInt("PuntosIzda");
puntosDchaIniciales=data.getExtras().getInt("PuntosDcha");
}
Solo falta hacer que se usen estos valores al arrancar la actividad de PongJuego. Para ello vamos a
modificar la forma de llamarla en empiezaJuego(), incluyendo estos dos valores. Usamos la misma
idea de aadir extras, obteniendo este cdigo:
1
2
3
4
5
6
privatevoidempiezaJuego(){
Intentjuego=newIntent(this,PongJuego.class);
juego.putExtra("PuntosIzda",puntosIzdaIniciales);
juego.putExtra("PuntosDcha",puntosDchaIniciales);
this.startActivityForResult(juego,1);
}
Ahora falta usar estos valores en PongJuego, de modo que modificamos el constructor para que
quede as:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
acelerometro=new
AcelerometroPong(this.getApplicationContext());
if(getIntent().getExtras()!=null){
intpuntosIzda=
getIntent().getExtras().getInt("PuntosIzda");
intpuntosDcha=
getIntent().getExtras().getInt("PuntosDcha");
if(puntosIzda==Marcador.MAX_PUNT||
puntosDcha==Marcador.MAX_PUNT)
view=newPongGameView(this,acelerometro,0,0);
else
view=newPongGameView(this,acelerometro,puntosIzda,
puntosDcha);
}else
view=newPongGameView(this,acelerometro,0,0);
setContentView(view);
}
publicPongGameView(Contextcontext,AcelerometroPongacelerometro,
intpuntosIzda,intpuntosDcha){
super(context);
getHolder().addCallback(this);
this.acelerometro=acelerometro;
this.marcador=newMarcador(puntosIzda,puntosDcha);
9
10
11
12
13
14
15
16
paint=newPaint();
paint.setColor(Color.WHITE);
paint.setTextAlign(Align.CENTER);
paint.setTypeface(Typeface.createFromAsset(this.getContext().getAssets(),
"fonts/KellySlabRegular.ttf"));
paint.setTextSize(80);
paint.setAntiAlias(true);
}
publicMarcador(inti,intd){
puntosIzda=i;
puntosDcha=d;
}
Ahora s, podemos ejecutar nuestra aplicacin y veremos que si volvemos al men (por ejemplo
para cambiar alguna opcin) y luego volvemos a dar a Jugar, mantendremos la puntuacin que
tenamos acumulada. Llegados a este punto podra crearse un men emergente que permitiera
elegir continuar partida existente (si la hay) o iniciar una nueva. Sin embargo considero que es
sobrecargar sin necesidad la entrada, y sera una cosa a tener en cuenta si sta fuera una aplicacin
comercial.
privateWakeLockwl;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
[...]
setContentView(view);
PowerManagerpm=(PowerManager)
this.getSystemService(Context.POWER_SERVICE);
9 wl=pm.newWakeLock(PowerManager.FULL_WAKE_LOCK,"PongvC");
10 }
Ahora aadimos el mtodo onPause() y modificamos el mtodo onResume():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protectedvoidonPause(){
super.onPause();
if(PongOpciones.getInstance().accelerometerEnabled())
wl.release();
}
@Override
protectedvoidonResume(){
super.onResume();
acelerometro.register();
if(PongOpciones.getInstance().accelerometerEnabled())
wl.acquire();
}
ltima mejora
Las ltimas cosas se dejan para el final, y si nos damos cuenta hasta ahora no hemos usado el
botn de Salir del men. Queremos que cuando se pulse se cierre la aplicacin.
Vamos a la clase PongvCActivity, en el mtodo onCreate(), en la parte que aadimos el
onTouchListener() al botn de salir. Modificamos su cdigo as:
1
2
3
4
5
6
7
TextViewexit=(TextView)findViewById(R.id.exit_button);
exit.setOnClickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
finish();
}
});
Hasta aqu la entrada de hoy. Con esta entrada podemos decir que hemos acabado el desarrollo
de la aplicacin. La siguiente entrada consistir en todos los pasos necesarios para publicar la
aplicacin, desde la creacin de una cuenta de Google Checkout hasta la publicacin.
Quedaran varias cosas que hacer en la aplicacin, como por ejemplo la creacin de una pequea
inteligencia artificial para la raqueta derecha, uso del multitctil para poder jugar dos personas
tocando a la vez o localizacin de idioma para los botones del men principal.
Sin embargo sera sobrecargar demasiado esta serie de tutoriales puesto que estamos intentando
hacer una pequea introduccin a Android con la excusa de crear un juego. Nuestra intencin no
es crear una aplicacin con todo lo que tiene Android a la vez.
Como siempre podis descargar el proyecto de Eclipse completo para poder importarlo y usarlo
pulsando aqu (MD5: 209d4e4393a45dadd15c18bfb22621c1).
Una vez ms, muchas gracias por vuestro tiempo!
0. Creando una aplicacin de Android: la presentacin
1. Creando una aplicacin de Android: primeros pasos
2. Creando una aplicacin de Android: visin de conjunto y diseo del men
3. Creando una aplicacin de Android: el juego y la lgica (parte 1)
4. Creando una aplicacin de Android: el juego y la lgica (parte 2)
5. Creando una aplicacin de Android: mejoras (parte 1)
6. Creando una aplicacin de Android: mejoras (parte 2)
7. Creando una aplicacin de Android: empaquetado y publicacin
Like
Twittear
Follow
Share
Esta entrada fue publicada en Android, Curso introduccin Android, Programacin y etiquetada
como acelerometro, activity, aplicacion android, canvas, eclipse, graficos android, graphics
android, java, menu, subactivity, wake lock.
alex dijo:
30 abril, 2012 at 22:39
Gracias por el tuto, en todo caso como quedaria lo de la IA?
saludos
2.
3.
Jumax9 dijo:
15 septiembre, 2011 at 16:44
Muy buen tutorial, muchas gracias! ^____^!
vidasConcurrentes
Sitio creado por meta y sshMan
Home
Blog
Sguenos
Concenos
Contacto
Preparacin
La primera cosa que tenemos que hacer es preparar la aplicacin para poder publicarla. Esto
implica crear el icono, poner el nombre de la aplicacin y quitar todos los restos de trazas de
cdigo y debug. Para poder poner el nombre a la aplicacin (el que saldr debajo del icono) y el
propio icono, debemos ir al AndroidManifest.xml y localizar la etiqueta <application>, como aqu
mostramos:
1 <applicationandroid:icon="@drawable/icon"
android:label="@string/app_name">
Aqu estamos diciendo que el nombre de la aplicacin aparece en el fichero strings.xml bajo el
string llamado app_name, y que el icono de la aplicacin est en el directorio drawable.
Comprobamos el fichero strings.xml y vemos:
1 <stringname="app_name">Pong</string>
Lo vamos a cambiar por:
1 <stringname="app_name">PongvC</string>
La parte del nombrado de la aplicacin ya est, ahora vamos con el icono. Es interesante consultar
las guas para el diseo de iconos de Android Developers para saber ms acerca de los tamaos
adecuados y diferentes resoluciones. En nuestro caso comenzamos creando un icono en
Photoshop, el cual guardamos con tamao 7272 pxeles y usando Guardar para web y
dispositivos marcando PNG-24 y sin ningn metadato (as, entre otras cosas, reducimos el
tamao). El resultado podra ser el siguiente, que es el que usaremos:
Categoras
Android
Curso introduccin
Android
Programacin
Seguridad
Sistemas Operativos
Entradas recientes
Automatizando la
creacin de entornos de
desarrollo con Vagrant
Colorshapes, el juego de
velocidad mental y figuras
de colores para Android
eyeOS: Trabajando en la
nube
Integrando Google
Analytics en aplicaciones
Android
Integrando Twitter en
aplicaciones Android con
SignPost y Twitter4J
Etiquetas
activity
algoritmo android
aplicacion android
arbol backtrack bash BD
acelerometro
BEeF
eclipse
expresiones regulares
graficos android
metasploit
metasploitable mitm
mysql oauth owasp
eliminarlos veremos que el AndroidManifest.xml se nos queja. Esto es porque nos resta cambiar la
ruta del icono. La etiqueta <application>entonces quedar as:
1 <applicationandroid:icon="@drawable/icon_pong"
android:label="@string/app_name">
Ahora vamos a quitar todos los restos de trazas de cdigo y el debug de la aplicacin. Debemos
quitar, en caso de tenerlo (no en el nuestro, pero quiz s en futuras aplicaciones) la opcin
android:debuggable=true de la etiqueta <application>. Debemos buscar todas las llamadas a la
clase Log, para quitar toda traza que hayamos usado durante el desarrollo. Es tambin muy
importante buscar en nuestros cdigos si hemos incluido por alguna razn informacin privada
que no deseemos que se vea, adems de todo fichero que no sea necesario del proyecto y
posibles ficheros de logging o backup que hayamos usado. Por ltimo es de vital importancia la
versin de la aplicacin, y sera muy interesante echar un vistazo a la gua sobre versionado de
Android Developers. Comenzando por la versin 1.0, por cada actualizacin que hagamos
deberamos aumentarla. Las dos etiquetas importantes que tenemos que tener en cuenta son
android:versionCode y android:versionName en la etiqueta <manifest>. Debemos comprender
para qu sirve cada una de las dos:
versionCode: este atributo es un nmero entero que tpicamente comienza en 1 y que se va
aumentando por cada actualizacin. Representa el orden de la versin. Lo suyo es que, cada
vez que hagamos una actualizacin, aumentemos este nmero en una unidad, ya sea por
una actualizacin grande o pequea.
versionName: este atributo es una cadena de texto que representa la versin tal y como
debe ser mostrada a los usuarios. Comenzando tpicamente en 1.0 ir aumentando a 1.1,
1.2 Si es una actualizacin menor, aumentamos el segundo nmero. Si es una
actualizacin grande aumentaremos el primero (para tener 2.0, luego 2.1).
Por tanto, nuestra etiqueta <manifest>quedar as:
1 <manifest
xmlns:android="http://schemas.android.com/apk/res/android"
2 package="com.vidasconcurrentes.pongvc"android:versionCode="1"
3 android:versionName="1.0">
Firmar la aplicacin
La ltima etapa previa a la publicacin ser el firmado de sta. De nuevo, deberamos consultar la
gua sobre el firmado de Android Developers. Comenzamos haciendo click derecho sobre nuestro
proyecto. Elegimos Android Tools > Export Signed Application Package. Lo siguiente sern una
sucesin de ventanas en las que se nos guiar en el proceso. Lo primero que veremos ser lo
siguiente:
Elegimos Create new keystore, y elegimos el lugar con el botn Browse. Lo siguiente es escribir la
contrasea que usaremos para el fichero. Recomendamos usar una contrasea fuerte,
posiblemente creada con algn generador de contraseas. Una vez hemos rellenado los campos,
damos a Next y vemos la siguiente ventana:
Sitios de inters
Android Developers
Android.es
Backtrack
Command Line Kung Fu
DragonJAR
El Androide Libre
Exploits Database
Flu Project
Gran Angular
Hispasec
Microsiervos
OpenLibra
Pentester.es
Poesa Binaria
Security By Default
Un informtico en el lado
del mal
World Wide Web
Consistorium
Aqu es donde tenemos que poner toda la informacin de la firma. Alias debe rellenarse con 8
caracteres como mximo, y es el alias de la clave. La contrasea, por experiencia propia, debe ser
la misma que pusimos anteriormente. Lo siguiente es la validez, en aos, que va a tener la clave
(entre 1 y 1000). Los campos de la parte de abajo no son obligatorios, si bien debemos rellenar al
menos uno para poder continuar. Una vez hayamos concluido con esta ventana, pulsamos Next y
veremos esta otra:
Aqu elegimos la ruta donde queremos guardar nuestro .apk ya firmado. Una vez hayamos
concluido pulsamos en Finish y dejamos que Eclipse trabaje. Una vez haya completado el proceso
(dependiendo del tamao de la aplicacin puede resultar un proceso relativamente largo),
tendremos nuestro fichero de la clave y nuestro .apk firmado. Para comprobar que efectivamente
est todo correcto, podemos guardar dicho .apk en nuestro dispositivo (por ejemplo por medio de
USB), y ejecutarlo con un Explorador de Ficheros (primero debemos desinstalarlo si lo tenemos
por haber desarrollado en el dispositivo). Si hacemos esto, podremos ver que nuestro dispositivo
muestra algo similar a lo siguiente:
Una vez instalada veremos que funciona exactamente igual que cuando lo hacamos al desarrollar
en Eclipse y usar Run as Android Application. Ya estamos listos para publicar nuestra aplicacin!
Meteremos los datos de nuestra cuenta de Google (la de gmail, para entendernos), y continuamos
con la siguiente pantalla:
En ella debemos leer el link que dice Acuerdo de distribucin para desarrolladores de Android
Market. Una vez hemos rellenado los campos (posteriormente podrn editarse), continuamos con
la siguiente pantalla:
Aqu simplemente damos a Continuar. El siguiente paso es poner la informacin para realizar el
pago:
Entiendo que, en caso de ya haber comprado algo con Google Checkout, este paso se omitira o
los campos ya estaran completados. En cualquier caso, rellenamos el formulario (importante
fijarse en el https:// de la barra de direcciones), y continuamos al siguiente paso:
En este paso nada ms que veremos el resumen de la compra que vamos a hacer. Podemos elegir
las opciones que se nos muestran, y luego pulsamos en Realizar pedido ahora. Una vez est
completado veremos lo siguiente, que confirma que nuestra compra se ha realizado
correctamente:
En el cuadro amarillo hay un link que dice sitio de desarrolladores de Android Market, en el cual
pulsaremos. El siguiente paso consiste en leer el acuerdo de licencia en espaol y continuar:
Si todo ha ido sin errores (no debera haberlos) veremos que nuestro registro en el Android Market
se ha aprobado y estaremos frente a nuestra Consola del desarrollador:
Con esto hemos acabado nuestro registro en el Android Market como desarrolladores.
Elegimos la ruta de nuestro .apk firmado, y dejamos que se suba. Una vez subido nos har un
resumen de los datos con el cdigo de versin y el nombre de la versin adems de todos los
permisos que puedan tener que aceptar los usuarios. La siguiente parte consiste en rellenar los
campos (y tambin los opcionales si as lo deseamos). En la Especificacin de detalles, es
importante que nos demos cuenta de que nos pide la informacin en ingls (descripcin, ttulo).
Podemos elegir aadir nuevos idiomas y poner la informacin en cada uno de ellos (incluso
cambiar el idioma predeterminado). Es muy importante esta parte, ya que ser la que vean los
usuarios del Android Market. Dato importante: en caso de que queramos cobrar una cantidad por
nuestras aplicaciones, lo primero que tenemos que hacer ser configurar una cuenta bancaria que
ser en la que recibiremos los pagos. Pulsa en el correspondiente enlace en la seccin de Precios >
Quieres vender aplicaciones? Configura una cuenta de comerciante en Google Checkout. Una
vez hayamos completado toda la informacin (importante tambin el sitio web y el correo de
contacto), procedemos a aceptar los Consentimientos de la parte baja de la web. Finalmente
guardamos nuestros progreso pulsando en Guardar en la parte superior derecha de los formularios
y comprobamos que tenemos correcto todas las opciones que hemos querido rellenar. En la
pestaa Archivos APK tenemos nuestra aplicacin, la cual necesitamos Activar. Una vez hecho
esto slo nos resta pulsar en Publicar, en la parte superior derecha. Seremos redirigidos a la
siguiente ventana:
Nos restara comprobar que, efectivamente, nuestra aplicacin est realmente publicada y
accesible. Se supone que la publicacin en el Android Market es instantnea, pero no podremos
encontrarla usando la herramienta de bsqueda del market hasta que no haya pasado un tiempo
(quiz horas). Veamos las capturas:
Importante: es necesario que probemos que funciona todo correctamente antes de distribuir
enlaces a diestro y siniestro. Y es necesario que desinstalemos nuestra versin previa (sea la que
usamos dirctamente con Eclipse o desde el .apkfirmado).