Anda di halaman 1dari 30

Crear un juego de tres en lnea en red

para Android
Construir un juego de tres en lnea de multijugador en red con PHP, XML y el
kit de desarrollo de Android

Construya el fondo de un juego de tres en lnea de multijugador y habilitado


para la red con una aplicacin frontal de Android en este artculo.
3
Comentarios:
Jack D. Herrington, Senior Software Engineer, Leverage Software Inc.
09-04-2012

Tabla de contenidos

Juego de tres en lnea de multijugador en red


Acrnimos de uso frecuente

API: Interfaz de programacin de aplicaciones


HTTP: Protocolo de Transferencia de Hipertexto
IP: Protocolo Internet
SDK: Kit de desarrollo de software
SQL: Lenguaje de Consulta Estructurado
IU: Interfaz de Usuario
XML: Extensible Markup Language

Los juegos casuales son extremadamente populares y muy lucrativos, y es fcil saber por
qu. No todas las personas de todos los grupos de edades estn interesadas en jugar
online videojuegos de disparos en primera persona contra hordas de adolescentes con
reflejos tan rpidos como la velocidad de la luz. Algunas veces, es ms 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 ms fciles de construir que los videojuegos intensivos en grficos de
disparos en primera persona o de deportes. As que es ms fcil para un solo
desarrollador, o para un grupo de desarrolladores, producir una primera versin de un
nuevo videojuego original.

En este artculo, pasamos a travs de las bases para crear un juego de lnea de tres
casual de multijugador en red. El servidor del videojuego es una aplicacin web basada
en MySQL y PHP con una interfaz XML. La parte frontal es una aplicacin nativa de
Android que funciona en telfonos de Android.
Volver arriba

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 ) );
DROP TABLE IF EXISTS moves;
CREATE TABLE moves(
id INT NOT NULL AUTO_INCREMENT,
game INT NOT NULL,
x INT NOT NULL,
y INT NOT NULL,
color INT NOT NULL,
primary key ( id ) );
La primera de las dos tablas es la tabla de los juegos, que slo tiene el ID exclusivo del
juego. En una aplicacin de produccin, 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 comunicacin entre el cliente y el servidor y la construccin 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.
Despus 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 despus use el
comando mysql para ejecutar el script db.sql como se muestra aqu:
% mysqladmin --user=root --password=foo create ttt
% mysql --user=root --password=foo ttt < db.sql
Esta etapa crea una nueva base de datos llamada "ttt", que tiene el esquema del juego de
tres en lnea.
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 elListado 2.
Listado 2. start.php

<?php
header( 'Content-Type:text/xml' );
$dd = new PDO('mysql:host=localhost;dbname=ttt', 'root', '');
$sql = 'INSERT INTO games VALUES ( 0 )';
$sth = $dd->prepare($sql);
$sth->execute( array() );
$qid = $dd->lastInsertId();
$doc = new DOMDocument();
$r = $doc->createElement( "game" );
$r->setAttribute( 'id', $qid );
$doc->appendChild( $r );
print $doc->saveXML();
?>
El script comienza por conectarse a la base de datos. Despus ejecuta una sentencia
INSERT en la tabla de juegos y recupera el ID que fue generado. Desde ah crea un
documento XML, aade 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
aplicacin de Android no tiene una interfaz para crear juegos. Este es el cdigo:
$ 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' );
$dbh = new PDO('mysql:host=localhost;dbname=ttt', 'root', '');
$sql = 'SELECT * FROM games';
$q = $dbh->prepare( $sql );
$q->execute( array() );
$doc = new DOMDocument();
$r = $doc->createElement( "games" );
$doc->appendChild( $r );
foreach ( $q->fetchAll() as $row) {
$e = $doc->createElement( "game" );
$e->setAttribute( 'id', $row['id'] );
$r->appendChild( $e );
}
print $doc->saveXML();
?>
Este script, igual que el script.php, comienza por conectarse a la base de datos. Despus
de eso, consulta la tabla de juegos para ver qu est disponible. Y desde ah crea un
nuevo documento XML, aade una etiqueta de juegos, despus aade etiquetas de juego
para cada uno de los juegos disponibles.
Cuando ejecuta este script desde la lnea de comandos, ve algo como esto:
$ php games.php
<?xml version="1.0"?>

<games><game id="1"/></games>
$
Tambin 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 cdigo de
servidor para manejar los movimientos. Este cdigo inicia con la construccin 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 cdigo PHP para esta funcin 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 ) );
$doc = new DOMDocument();
$r = $doc->createElement( "moves" );
$doc->appendChild( $r );
foreach ( $q->fetchAll() as $row) {
$e = $doc->createElement( "move" );
$e->setAttribute( 'x', $row['x'] );
$e->setAttribute( 'y', $row['y'] );
$e->setAttribute( 'color', $row['color'] );
$r->appendChild( $e );
}
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. Despus crea un documento XML con los
movimientos para el juego dado.

Usted cre esta funcin 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' );
$dbh = new PDO('mysql:host=localhost;dbname=ttt', 'root', '');
show_moves( $dbh, $_REQUEST['game'] );
?>
Este simple script incluye el cdigo de la funcin de ayudante, se conecta a la base de
datos y despus invoca la funcin show_moves con el ID del juego especificado. Para
probar este cdigo, use el comando curl para invocar el script en el servidor desde la lnea
de comandos:
$ curl "http://localhost/ttt/moves.php?game=1"
<?xml version="1.0"?>
<moves/>
$
Desgraciadamente, an no ha hecho ningn movimiento, as que no es una salida
particularmente interesante. Para remediar eso necesita aadir 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' );
$dbh = new PDO('mysql:host=localhost;dbname=ttt', 'root', '');
$sql = 'DELETE FROM moves WHERE game=? AND x=? AND y=?';
$sth = $dbh->prepare($sql);

$sth->execute( array(
$_REQUEST['game'],
$_REQUEST['x'],
$_REQUEST['y']
) );
$sql = 'INSERT INTO moves VALUES ( 0, ?, ?, ?, ? )';
$sth = $dbh->prepare($sql);
$sth->execute( array(
$_REQUEST['game'],
$_REQUEST['x'],
$_REQUEST['y'],
$_REQUEST['color']
) );
show_moves( $dbh, $_REQUEST['game'] );
?>
Este script comienza por incluir la funcin de ayudante y conectarse a la base de datos.
Despus 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 despus 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.
Para probar que todo esto funciona, puede hacer un movimiento:
$ 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 cdigo del servidor del juego completo, puede construir la parte frontal de Android
para este juego en red de multijugador.
Volver arriba

Construyendo la parte frontal de Android

Primero, instale el SDK de Android, as como algunas versiones de la plataforma de


Android, y despus finalmente Eclipse y el plug-in de Eclipse de Android. Para nuestra
suerte, todo esto est bien documentado en el sitio de Android (vea Recursos para
obtener enlaces). Una cobertura a profundidad sobre cmo configurar su entorno de
desarrollo requerira todo este artculo y ms.
Despus de que configure el entorno de desarrollo, lance Eclipse e inicie un nuevo
proyecto de Android. Debe ver algo similar a la Figura 1.
Figura 1. Creando la aplicacin de Android en Eclipse

La Figura 1 muestra el asistente de proyecto para aplicaciones de Android. Ingrese el


nombre de un proyecto, seleccione el botn de seleccinCreate new project in
workspace y especifique la ubicacin para el cdigo con los elementos de UI. En la lista
de comprobacin Build Target, seleccione una plataforma de Android. Para este cdigo,
yo uso Android 2.3.1. El cdigo es muy simple, as que puede usar cualquier versin que
prefiera. Si no ve ninguna plataforma listada, entonces necesita descargar e instalar las
plataformas como se indica en las instrucciones de configuracin del SDK de Android.
Tenga en cuenta que descargar todas estas plataformas requiere mucho, mucho tiempo.

En la seccin Properties , llene el nombre de la aplicacin y el nombre del paquete. Yo


us "Tic Tac Toe" y "com.jherrington.tictactoe" en los campos respectivos. Despus,
marque el recuadro de seleccin 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.
Figura 2. Los archivos del proyecto TicTacToe

La Figura 2 muestra los directorios de alto nivel y los archivos para una aplicacin 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:

El directorio res, que contiene recursos


El directorio src, que tiene el origen de Java
El archivo manifest, que contiene la informacin biogrfica sobre la
aplicacin
Su primera edicin es en el archivo manifest. La mayora del archivo ya est correcto,
pero necesita aadir el permiso de Internet, de forma que la aplicacin 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" />
<uses-sdk android:minSdkVersion="5" />
<application android:icon="@drawable/icon"
android:label="@string/app_name">
<activity android:name="TicTacToeActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
El nico cambio fue aadir la etiqueta uses-permission en la parte superior del archivo.
Su siguiente tarea es disear 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 diseo sencillo. La parte superior es un conjunto de dos botones envueltos en
un diseo lineal con una orientacin horizontal. Estos dos botones son los botones X y O
que el usuario usa para especificar qu color est jugando.
El resto del cdigo est llenado con una clase BoardView, que muestra el tablero de tres
en lnea con el juego actual. El cdigo para la clase BoardView est en el Listado 11.
Con el diseo a la mano, es momento de escribir algo de cdigo de Java para la
aplicacin. Esta codificacin comienza con la clase TicTacToeActivity en el Listado 9. Las
actividades son los componentes bsicos de aplicaciones de Android. Cada aplicacin
tiene una o ms actividades que representan los diversos estados de la aplicacin. A
medida que navega a travs de la aplicacin construye una pila de actividades que puede
despus sacar al usar el botn de retroceso en el telfono. La aplicacin 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;
public class TicTacToeActivity extends Activity implements OnClickListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button playx = (Button)this.findViewById(R.id.playx);
playx.setOnClickListener( this );
Button playo = (Button)this.findViewById(R.id.playo);
playo.setOnClickListener( this );
Timer timer = new Timer();
UpdateTimer ut = new UpdateTimer();
ut.boardView = (BoardView)this.findViewById(R.id.bview);
timer.schedule( ut, 200, 200 );
}
public void onClick(View v) {
BoardView board = (BoardView)this.findViewById(R.id.bview);
if ( v.getId() == R.id.playx ) {
board.setColor( 2 );
}
if ( v.getId() == R.id.playo ) {
board.setColor( 1 );
}
}
}
La actividad tiene dos mtodos. El primero es el mtodo onCreate, que construye la
interfaz de usuario, conecta al manejador onClick a los botones X y O e inicia el

temporizador de actualizacin. El temporizador de actualizacin 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 botn X o en el botn 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.
Listado 10. GameService.java

package com.jherrington.tictactoe;
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;
public class GameService {
private static GameService _instance = new GameService();
public int[][] positions = new int[][] {
{ 0, 0, 0 },

{ 0, 0, 0 },
{ 0, 0, 0 }
};
public static GameService getInstance() {
return _instance;
}
private void updatePositions( Document doc ) {
for( int x = 0; x < 3; x++ ) {
for( int y = 0; y < 3; y++ ) {
positions[x][y] = 0;
}
}
doc.getDocumentElement().normalize();
NodeList items = doc.getElementsByTagName("move");
for (int i=0;i<items.getLength();i++){
Element me = (Element)items.item(i);
int x = Integer.parseInt( me.getAttribute("x") );
int y = Integer.parseInt( me.getAttribute("y") );
int color = Integer.parseInt( me.getAttribute("color") );
positions[x][y] = color;
}
}
public void startGame( int game ) {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://10.0.2.2/ttt/moves.php");
try {
List<NameValuePair> nameValuePairs = new
ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("game",
Integer.toString(game)));

httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
updatePositions( db.parse(response.getEntity().getContent()) );
} catch (Exception e) {
Log.v("ioexception", e.toString());
}
}
public void setPosition( int game, int x, int y, int color ) {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://10.0.2.2/ttt/move.php");
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));
HttpResponse response = httpclient.execute(httppost);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
updatePositions( db.parse(response.getEntity().getContent()) );
} catch (Exception e) {
Log.v("ioexception", e.toString());

}
}
}
Este cdigo es algo del cdigo ms interesante en la aplicacin. Primero, tiene el mtodo
updatePositions, que toma el XML retornado del servidor y busca los elementos de
movimiento, despus actualiza la matriz de posiciones con el conjunto de movimientos
actual. La matriz de posiciones tiene un valor para cada posicin en el tablero; cero indica
un espacio vaco, 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 mtodo startGame solicita el conjunto de movimientos actual del servidor y
actualiza la lista de posiciones. El mtodo setPosition publica el movimiento en el servidor
al crear una solicitud de publicacin HTTP y configurar los datos para la publicacin
usando una matriz de pares de valores de nombre, los cuales son despus son
codificados para transporte. Despus analiza el XML de respuesta para actualizar la lista
de posiciones.
Si observa detenidamente, el IP usado para conectarse al servidor es realmente
interesante. No es "localhost" o "127.0.0.1"; es "10.0.2.2", que es un alias para la mquina
en la que se ejecuta el emulador. Ya que el telfono de Android es en s mismo un sistema
de UNIX , tiene sus propios servicios en localhost. Fascinante, verdad? No es
frecuente que sea tan claro que el telfono no es en realidad un telfono per se, sino una
computadora en toda regla que se ajusta a la palma de su mano y sucede que tiene un
telfono integrado en l.
Entonces, dnde estamos? Usted tiene la actividad, que es el componente principal para
la aplicacin; tiene la configuracin del diseo de IU; tiene el cdigo de Java para
conectarse al servidor. Ahora necesita dibujar el tablero del juego. Esto es realizado por la
clase BoardView en elListado 11.
Listado 11. BoardView.java

package com.jherrington.tictactoe;
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;
public class BoardView extends View {
private int _color = 1;
public void setColor( int c ) {
_color = c;
}
public BoardView(Context context) {
super(context);
GameService.getInstance().startGame(0);
}
public BoardView(Context context, AttributeSet attrs) {
super(context,attrs);
GameService.getInstance().startGame(0);
}
public BoardView(Context context, AttributeSet attrs, int defStyle) {
super(context,attrs,defStyle);
GameService.getInstance().startGame(0);
}
public boolean onTouchEvent( MotionEvent event ) {
if ( event.getAction() != MotionEvent.ACTION_UP )
return true;
int offsetX = getOffsetX();
int offsetY = getOffsetY();
int lineSize = getLineSize();
for( int x = 0; x < 3; x++ ) {
for( int y = 0; y < 3; y++ ) {

Rect r = new Rect( ( offsetX + ( x * lineSize ) ),


( offsetY + ( y * lineSize ) ),
( ( offsetX + ( x * lineSize ) ) + lineSize ),
( ( offsetY + ( y * lineSize ) ) + lineSize ) );
if ( r.contains( (int)event.getX(), (int)event.getY() ) ) {
GameService.getInstance().setPosition(0, x, y, _color);
invalidate();
return true;
}
}
}
return true;
}
private int getSize() {
return (int) ( (float)
( ( getWidth() < getHeight() ) ? getWidth() : getHeight() ) * 0.8 );
}
private int getOffsetX() {
return ( getWidth() / 2 ) - ( getSize( ) / 2 );
}
private int getOffsetY() {
return ( getHeight() / 2 ) - ( getSize() / 2 );
}
private int getLineSize() {
return ( getSize() / 3 );
}
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setAntiAlias(true);

paint.setColor(Color.BLACK);
canvas.drawRect(0,0,canvas.getWidth(),canvas.getHeight(), paint);
int size = getSize();
int offsetX = getOffsetX();
int offsetY = getOffsetY();
int lineSize = getLineSize();
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++ ) {
for( int y = 0; y < 3; y++ ) {
Rect r = new Rect( ( offsetX + ( x * lineSize ) ) + inset,
( offsetY + ( y * lineSize ) ) + inset,
( ( offsetX + ( x * lineSize ) ) + lineSize ) - inset,
( ( offsetY + ( y * lineSize ) ) + lineSize ) - inset );
if ( GameService.getInstance().positions[ x ][ y ] == 1 ) {
canvas.drawCircle( ( r.right + r.left ) / 2,
( r.bottom + r.top ) / 2,
( r.right - r.left ) / 2, paint);
}

if ( GameService.getInstance().positions[ x ][ y ] == 2 ) {
canvas.drawLine( r.left, r.top, r.right, r.bottom, paint);
canvas.drawLine( r.left, r.bottom, r.right, r.top, paint);
}
}
}
}
}
La mayora del trabajo aqu es realizado en el mtodo onTouch, que responde al usuario
tocando una clula particular en el tablero del juego, y el mtodo onDraw, que pinta el
tablero del juego usando el mecanismo de pintura de Android.
El mtodo onTouch usa las funciones de tamao para definir un rectngulo para cada
posicin de clula. Despus usa el mtodo contains en el rectngulo para ver si el usuario
hizo clic dentro de la clula. Si lo hizo, ejecuta una solicitud al servicio del juego para que
haga un movimiento.
La funcin onDraw usa las funciones de tamao para dibujar las lneas 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 cdigo para el
temporizador.
Listado 12. UpdateTimer.java

package com.jherrington.tictactoe;
import java.util.TimerTask;
public class UpdateTimer extends TimerTask {
public BoardView boardView;
@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 aplicacin se inicia.
Este temporizador es un mecanismo de sondeo. Esta no es la forma ms eficiente para la
comunicacin entre el cliente y el servidor, pero es la ms simple y confiable. La forma
ms eficiente es usar la versin 1.1 del protocolo de HTTP para mantener la conexin
abierta y para que el servidor enve actualizaciones al cliente cuando se hagan los
movimientos. Este enfoque es mucho ms complejo; requiere que el cliente y el servidor
soporten el protocolo 1.1 y tiene problemas de escalabilidad con el nmero de
conexiones. Ese enfoque est fuera del mbito de este artculo. Para juegos simples de
demostracin como este, un mecanismo de sondeo funciona bien.
Con el cdigo hecho, puede probar la aplicacin. Eso significa iniciar el emulador. Debe
ver algo como la Figura 3 despus de inicializar.
Figura 3. Lanzando el emulador de Android

Este es el emulador cargando una fantstica interfaz "A N D R O I D". Despus de ser
cargada, ve la pantalla power-on en la Figura 4.
Figura 4. El emulador lanzado y listo para usarse

Para entrar al telfono, deslice el icono de bloqueo hacia la derecha. Esa accin lo lleva a
la pantalla de inicio y generalmente lanza la aplicacin que est depurando. En este caso,
esta accin muestra la pantalla del juego en la Figura 5.
Figura 5. El juego antes de que se hagan movimientos

Dependiendo del estado de su servidor, puede ver o no ningn movimiento. En este caso,
el juego estaba vaco. Los botones Play X y Play O estn en la parte superior con el

tablero del juego de lnea de tres en el centro de la visualizacin. A continuacin, haga clic
en Play X, despus haga clic en el cuadro del centro para ver algo como la Figura 6.
Figura 6. X toma el cuadro del centro, por supuesto

La Figura 6 muestra la visualizacin 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 ms 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.
Figura 7. O toma el cuadro de una esquina

Puede jugar con Xs y Os. La aplicacin se conecta al servidor para alojar el estado del
juego en una ubicacin compartida. Y debido al temporizador de actualizacin, cada
usuario puede ver los movimientos realizados por el otro.

Conclusin
Es este un juego completo? No realmente. No hay verificacin de condicin de victoria,
los jugadores pueden sobrescribir posiciones y no hay verificacin de turno. Pero las
piezas de tecnologa bsicas estn presentes: un servidor de juego con el estado
almacenado compartido entre los jugadores y una aplicacin grfica nativa en un
dispositivo mvil 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. Slo recuerde mantenerlo casual y divertido, y tal vez sea el creador del
siguiente Words With Friends o multijugador de Angry Birds.

Anda mungkin juga menyukai