Escolar Documentos
Profissional Documentos
Cultura Documentos
Construya el fondo de un juego de tres en línea de multijugador y habilitado para la red con una
aplicación frontal de Android en este artículo.
Los juegos casuales son extremadamente populares y muy lucrativos, y es fácil saber por qué. No todas las
personas de todos los grupos de edades están interesadas en jugar online videojuegos de disparos en primera
persona contra hordas de adolescentes con reflejos tan rápidos como la velocidad de la luz. Algunas veces,
es más interesante jugar videojuegos donde tiene tiempo para pensar y realizar una estrategia o donde la
meta es cooperar unos con otros para ganar el juego.
Lo genial sobre los videojuegos casuales desde la perspectiva de los desarrolladores es que son mucho más
fáciles de construir que los videojuegos intensivos en gráficos de disparos en primera persona o de deportes.
Así que es más fácil para un solo desarrollador, o para un grupo de desarrolladores, producir una primera
versión de un nuevo videojuego original.
En este artículo, pasamos a través de las bases para crear un juego de línea de tres casual de multijugador en
red. El servidor del videojuego es una aplicación web basada en MySQL y PHP con una interfaz XML. La
parte frontal es una aplicación nativa de Android que funciona en teléfonos de Android.
Construyendo el fondo
El fondo inicia con una base de datos simple de MySQL que tiene dos tablas. El Listado 1 muestra el
esquema para la base de datos.
Listado 1. db.sql
DROP TABLE IF EXISTS games;
CREATE TABLE games(
id INT NOT NULL AUTO_INCREMENT,
primary key ( id ) );
La primera de las dos tablas es la tabla de los juegos, que sólo tiene el ID exclusivo del juego. En una
aplicación de producción, probablemente tenga una tabla de usuarios, y la tabla de juegos incluye los IDs de
usuario de ambos jugadores. Para hacerlo simple, sin embargo, renunciaré a este enfoque para concentrarme
en las bases de almacenar los datos del juego, la comunicación entre el cliente y el servidor y la construcción
de la parte frontal.
La segunda tabla es la tabla de movimientos, que incluye los movimientos individuales para el juego dado,
así que tiene cinco columnas. La primera columna es el ID exclusivo del movimiento. La segunda columna
es el ID del juego al que aplica este movimiento. Después vienen las posiciones 'x' y 'y' del movimiento.
Estos valores deben estar entre 0 y 2 para 'x' y 'y', ya que cuenta con una red de tres por tres. El último
campo es el "color" del movimiento, que es un entero que indica X u O.
Para construir la base de datos, primero use mysqladmin para crearla y después use el comando mysql para
ejecutar el script db.sql como se muestra aquí:
Esta etapa crea una nueva base de datos llamada "ttt", que tiene el esquema del juego de tres en línea.
ahora que tiene el esquema, necesita crear una forma de iniciar un juego. Para esto, usted cuenta con un
script llamado start.php, como en el Listado 2.
Listado 2. start.php
<?php
header( 'Content-Type:text/xml' );
print $doc->saveXML();
?>
El script comienza por conectarse a la base de datos. Después ejecuta una sentencia INSERT en la tabla de
juegos y recupera el ID que fue generado. Desde ahí crea un documento XML, añade el ID a una etiqueta de
juego y exporta el XML.
Necesita ejecutar este script para poner un juego en la base de datos, ya que la simple aplicación de Android
no tiene una interfaz para crear juegos. Este es el código:
$ php start.php
<?xml version="1.0"?>
<game id="1"/>
$
Ahora ya tiene su primer juego. Para ver la lista de juegos, use el script games.php que está en el Listado 3.
Listado 3. games.php
<?php
header( 'Content-Type:text/xml' );
$q = $dbh->prepare( $sql );
$q->execute( array() );
print $doc->saveXML();
?>
Este script, igual que el script.php, comienza por conectarse a la base de datos. Después de eso, consulta la
tabla de juegos para ver qué está disponible. Y desde ahí crea un nuevo documento XML, añade una etiqueta
de juegos, después añade etiquetas de juego para cada uno de los juegos disponibles.
Cuando ejecuta este script desde la línea de comandos, ve algo como esto:
$ php games.php
<?xml version="1.0"?>
<games><game id="1"/></games>
$
También puede ejecutar este script desde el navegador web para ver la misma salida.
¡Excelente! Con la API de juegos fuera del camino, es momento de escribir el código de servidor para
manejar los movimientos. Este código inicia con la construcción de un script ayudante llamado show_moves
que obtiene los movimientos actuales para un juego dado y los exporta como XML. El Listado 4 muestra el
código PHP para esta función de ayudante.
Listado 4. show_moves.php
<?php
function show_moves( $dbh, $game ) {
$sql = 'SELECT * FROM moves WHERE game=?';
$q = $dbh->prepare( $sql );
$q->execute( array( $game ) );
print $doc->saveXML();
}
?>
El script toma un manejador de base de datos y el ID de juego. Desde ahí ejecuta el SQL para obtener la lista
de movimientos. Después crea un documento XML con los movimientos para el juego dado.
Usted creó esta función de ayudante porque hay dos scripts que la usan; el primero es un script moves.php
que retorna los movimientos actuales para el juego especificado. El Listado 5 muestra este script.
Listado 5. moves.php
<?php
require_once( 'show_moves.php' );
header( 'Content-Type:text/xml' );
Este simple script incluye el código de la función de ayudante, se conecta a la base de datos y después
invoca la función show_moves con el ID del juego especificado. Para probar este código, use el comando
curl para invocar el script en el servidor desde la línea de comandos:
$ curl "http://localhost/ttt/moves.php?game=1"
<?xml version="1.0"?>
<moves/>
$
Desgraciadamente, aún no ha hecho ningún movimiento, así que no es una salida particularmente
interesante. Para remediar eso necesita añadir el script final a la API del servidor. El Listado 6 muestra el
script move.php.
Listado 6. move.php
<?php
require_once( 'show_moves.php' );
header( 'Content-Type:text/xml' );
Este script comienza por incluir la función de ayudante y conectarse a la base de datos. Después ejecuta
dos sentencias SQL. La primera elimina cualquier movimiento que pueda chocar con la que está siendo
enviada. La segunda inserta una nueva fila en la tabla de movimientos para el movimiento especificado. El
script después retorna la lista de movimientos al cliente. Esta etapa salva al cliente de tener que hacer dos
solicitudes cada vez que hace un movimiento. El ancho de banda no es barato, así que siempre que pueda
conglomerar solicitudes debe hacerlo.
$ curl "http://localhost/ttt/move.php?game=1&x=1&y=2&color=1"
<?xml version="1.0"?>
<moves><move x="1" y="2" color="1"/></moves>
Con el código del servidor del juego completo, puede construir la parte frontal de Android para este juego en
red de multijugador.
Después de que configure el entorno de desarrollo, lance Eclipse e inicie un nuevo proyecto de Android.
Debe ver algo similar a la Figura 1.
En la sección Properties , llene el nombre de la aplicación y el nombre del paquete. Yo usé "Tic Tac
Toe" y "com.jherrington.tictactoe" en los campos respectivos. Después, marque el recuadro de selección
Create Activity e ingrese un nombre para la actividad. Yo usé "TicTacToeActivity" como el nombre de la
actividad.
Haga clic en Finish para ver un nuevo proyecto que se parece a la Figura 2.
La Figura 2 muestra los directorios de alto nivel y los archivos para una aplicación de Android
(los directorios son src, gen, Android 2.3.1 y res y los archivos son assets, AndroidManifest.xml,
default.properties y proguard.cfg). Los elementos importantes son:
Su primera edición es en el archivo manifest. La mayoría del archivo ya está correcto, pero necesita añadir el
permiso de Internet, de forma que la aplicación pueda hacer solicitudes en Internet. El Listado 7 muestra el
archivo manifest completado.
Listado 7. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0" package="com.jherrington.tictactoe">
<uses-permission
android:name="android.permission.INTERNET" />
</application>
</manifest>
El único cambio fue añadir la etiqueta uses-permission en la parte superior del archivo.
Su siguiente tarea es diseñar la IU. Para esto, ajuste el archivo layout.xml, que está contenido en el directorio
res/layout. El Listado 8 muestra el nuevo contenido para este archivo.
Listado 8. layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout android:layout_height="wrap_content"
android:layout_width="match_parent" android:id="@+id/linearLayout1">
<Button android:text="Play X" android:id="@+id/playx"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
<Button android:text="Play O" android:id="@+id/playo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
</LinearLayout>
<com.jherrington.tictactoe.BoardView android:id="@+id/bview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
></com.jherrington.tictactoe.BoardView>
</LinearLayout>
Este es un diseño sencillo. La parte superior es un conjunto de dos botones envueltos en un diseño lineal con
una orientación horizontal. Estos dos botones son los botones X y O que el usuario usa para especificar qué
color está jugando.
El resto del código está llenado con una clase BoardView, que muestra el tablero de tres en línea con el
juego actual. El código para la clase BoardView está en el Listado 11.
Con el diseño a la mano, es momento de escribir algo de código de Java para la aplicación. Esta codificación
comienza con la clase TicTacToeActivity en el Listado 9. Las actividades son los componentes básicos de
aplicaciones de Android. Cada aplicación tiene una o más actividades que representan los diversos estados
de la aplicación. A medida que navega a través de la aplicación construye una pila de actividades que puede
después sacar al usar el botón de retroceso en el teléfono. La aplicación TicTacToe tiene una sola actividad.
Listado 9. TicTacToeActivity.java
package com.jherrington.tictactoe;
import java.util.Timer;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.Gallery;
import android.widget.LinearLayout;
La actividad tiene dos métodos. El primero es el método onCreate, que construye la interfaz de usuario,
conecta al manejador onClick a los botones X y O e inicia el temporizador de actualización. El temporizador
de actualización es usado para renovar el estado del juego cada 200 milisegundos. Este dispositivo permite a
ambos jugadores ver cuando el otro jugador se mueve.
El manejador onClick establece el color actual del tablero con base en si el usuario hace clic en el botón X o
en el botón O.
La clase GameService, en el Listado 10, es una clase singleton que representa el servidor del juego y el
estado actual del juego dado.
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import android.util.Log;
{ 0, 0, 0 },
{ 0, 0, 0 }
};
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("game", Integer.toString(game)));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
positions[x][y] = color;
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("game", Integer.toString(game)));
nameValuePairs.add(new BasicNameValuePair("x", Integer.toString(x)));
nameValuePairs.add(new BasicNameValuePair("y", Integer.toString(y)));
nameValuePairs.add(new BasicNameValuePair("color", Integer.toString(color)));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
Este código es algo del código más interesante en la aplicación. Primero, tiene el método updatePositions,
que toma el XML retornado del servidor y busca los elementos de movimiento, después actualiza la matriz
de posiciones con el conjunto de movimientos actual. La matriz de posiciones tiene un valor para cada
posición en el tablero; cero indica un espacio vacío, 1 representa "O" y 2 es para "X".
Las otras dos funciones, startGame y setPosition, son la forma en que se comunica con el servidor. El
método startGame solicita el conjunto de movimientos actual del servidor y actualiza la lista de posiciones.
El método setPosition publica el movimiento en el servidor al crear una solicitud de publicación HTTP y
configurar los datos para la publicación usando una matriz de pares de valores de nombre, los cuales son
después son codificados para transporte. Después analiza el XML de respuesta para actualizar la lista de
posiciones.
Entonces, ¿dónde estamos? Usted tiene la actividad, que es el componente principal para la aplicación; tiene
la configuración del diseño de IU; tiene el código de Java para conectarse al servidor. Ahora necesita dibujar
el tablero del juego. Esto es realizado por la clase BoardView en el Listado 11.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
paint.setColor(Color.DKGRAY);
paint.setStrokeWidth( 5 );
for( int col = 0; col < 2; col++ ) {
int cx = offsetX + ( ( col + 1 ) * lineSize );
canvas.drawLine(cx, offsetY, cx, offsetY + size, paint);
}
for( int row = 0; row < 2; row++ ) {
int cy = offsetY + ( ( row + 1 ) * lineSize );
canvas.drawLine(offsetX, cy, offsetX + size, cy, paint);
}
int inset = (int) ( (float)lineSize * 0.1 );
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth( 10 );
for( int x = 0; x < 3; x++ ) {
La mayoría del trabajo aquí es realizado en el método onTouch, que responde al usuario tocando una célula
particular en el tablero del juego, y el método onDraw, que pinta el tablero del juego usando el mecanismo
de pintura de Android.
El método onTouch usa las funciones de tamaño para definir un rectángulo para cada posición de célula.
Después usa el método contains en el rectángulo para ver si el usuario hizo clic dentro de la célula. Si lo
hizo, ejecuta una solicitud al servicio del juego para que haga un movimiento.
La función onDraw usa las funciones de tamaño para dibujar las líneas del tablero y para dibujar cualquier
X u O jugada. El singleton GameServer es usado para su matriz de posiciones, que tiene el estado actual de
cada cuadro en el tablero del juego.
La última clase que necesita es UpdateTimer, que usa el servicio del juego para actualizar las posiciones del
tablero con sus últimos valores. El Listado 12 muestra el código para el temporizador.
import java.util.TimerTask;
@Override
public void run() {
GameService.getInstance().startGame( 0 );
boardView.post(new Runnable(){ public void run(){ boardView.invalidate(); } });
}
}
El temporizador es iniciado por la clase TicTacToeActivity cuando la aplicación se inicia. Este temporizador
es un mecanismo de sondeo. Esta no es la forma más eficiente para la comunicación entre el cliente y el
servidor, pero es la más simple y confiable. La forma más eficiente es usar la versión 1.1 del protocolo de
HTTP para mantener la conexión abierta y para que el servidor envíe actualizaciones al cliente cuando se
hagan los movimientos. Este enfoque es mucho más complejo; requiere que el cliente y el servidor soporten
el protocolo 1.1 y tiene problemas de escalabilidad con el número de conexiones. Ese enfoque está fuera del
ámbito de este artículo. Para juegos simples de demostración como este, un mecanismo de sondeo funciona
bien.
Con el código hecho, puede probar la aplicación. Eso significa iniciar el emulador. Debe ver algo como la
Figura 3 después de inicializar.
Este es el emulador cargando una fantástica interfaz "A N D R O I D". Después de ser cargada, ve la pantalla
power-on en la Figura 4.
Para entrar al teléfono, deslice el icono de bloqueo hacia la derecha. Esa acción lo lleva a la pantalla de
inicio y generalmente lanza la aplicación que está depurando. En este caso, esta acción muestra la pantalla
del juego en la Figura 5.
Dependiendo del estado de su servidor, puede ver o no ningún movimiento. En este caso, el juego estaba
vacío. Los botones Play X y Play O están en la parte superior con el tablero del juego de línea de tres en el
centro de la visualización. A continuación, haga clic en Play X, después haga clic en el cuadro del centro
para ver algo como la Figura 6.
La Figura 6 muestra la visualización del tablero del juego con una X ahora llenando el cuadro del centro.
Para verificar que el servidor estaba conectado, puede ejecutar el comando curl en el script moves.php en el
servidor para obtener la lista más reciente de movimientos del juego.
Para probar que funcionen las Os, haga clic en Play O y seleccione el cuadro de una esquina como en la
Figura 7.
Puede jugar con Xs y Os. La aplicación se conecta al servidor para alojar el estado del juego en una
ubicación compartida. Y debido al temporizador de actualización, cada usuario puede ver los movimientos
realizados por el otro.
Conclusión
¿Es este un juego completo? No realmente. No hay verificación de condición de victoria, los jugadores
pueden sobrescribir posiciones y no hay verificación de turno. Pero las piezas de tecnología básicas están
presentes: un servidor de juego con el estado almacenado compartido entre los jugadores y una aplicación
gráfica nativa en un dispositivo móvil que se conecta al servidor del juego para proporcionar un interfaz para
el juego. Puede usar este juego como un punto de partida para su propio juego y construirlo como desee.
Sólo recuerde mantenerlo casual y divertido, y tal vez sea el creador del siguiente Words With Friends o
multijugador de Angry Birds.
Sobre el autor
Jack D. Herrington
Jack Herrington es un ingeniero, autor y presentador que vive y trabaja en el Área de la Bahía.
Puede mantenerse al tanto de su trabajo y sus escritos en http://jackherrington.com.