Está en la página 1de 53

Universidad Autónoma de Baja California

Facultad de Ciencias Quı́micas e Ingenierı́a


Ingenierı́a en Computación

StreetChase

Documento técnico
Programación Orientada a Objetos II

Presenta:
Roberto Alonso Renteria Cuevas
Profesora de POO II: Profesor de EDT:
Dra. Dora Luz Flores M.C. David Cerón

Tijuana, Baja California, México Abril 2010


Resumen

Este proyecto busca desarrollar un videojuego el cual podrá ejecutarse en celulares con
compatibilidad de aplicaciones MIDlet, estas son aplicaciones desarrolladas para la platafor-
ma java ME, esta es una tecnologı́a que está incluida en la mayorı́a de los teléfonos móviles
de nueva generación.

En particular este proyecto reúne las caracterı́sticas de un video juego de carreras y per-
secución en el que estarán conduciendo un auto a alta velocidad a través de una calle muy
transitada y tendrán que esquivar a los demás autos y obstáculos que se atraviesen en el
camino como baches y otro tipo de cosas. Para hacer más fácil el juego se podrán recoger
objetos en el camino estos pueden ser bonos, vidas, objetos para regenerar los daños del auto
y armas que podrán utilizarse para abrirse paso a través de las calles ası́ como también para
evitar a la policı́a.

El principal objetivo de este juego será conducir el auto a la meta sin destruirlo o sin ser
atrapado por la policı́a.
El juego constara de tres modos de juego en cuanto a dificultad en los cuales incrementara
la velocidad del juego y los daños recibidos, también tendrá tres diferentes niveles en los que
cambiara el diseño del las calles y la dificultad del juego, esto para hacerlo menos monótono.
Abstract

This project seeks to develop a video game which can run on phones with MIDlet ap-
plication compatibility, which are applications developed for the Java ME platform, this is a
technology that is included in most new generation mobile phones.

In particular this project has the characteristics of a pursuit racing videogame in which
they’ll drive a car at high speed through a busy street and have to dodge other cars and
obstacles on the road. To make easier the game will pick up objects in the way these bonus
can be, lives, objects to regenerate the damage to the car, and weapons that may be used to
fight their way through the streets as well as to avoid the police.

The main objective of this game is drive the car to the finish line without destroys it or
be caught by police.
The game has three play modes of difficulty, which they will change the speed of play and
the possibility of be damage, also have three different levels they’ll which change the design
of streets and the difficulty of the game, this to make it less bored.
Índice general

1. Introducción II

1.1. Descripción del proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v

1.2. Objetivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vi

1.3. Requerimientos del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . vi

1.4. Organización del documento . . . . . . . . . . . . . . . . . . . . . . . . . . . vi

2. MIDlets 1

2.1. Mi primer MIDlet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

2.2. Imágenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.3. Pantallas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.3.1. Métodos de Canvas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3. Ambiente Grafico 13

3.1. Sprites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

3.2. Mapas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3.3. Sprites y Colisiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24


ÍNDICE GENERAL 4

3.4. Primer nivel del Juego . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

4. RMS(Record Manegment System) 31

4.1. Registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

5. Proyecto Terminado 36

5.1. Agregar Niveles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36


Índice de figuras

2.1. Mostrando el menú en ejecución. . . . . . . . . . . . . . . . . . . . . . . . . 8

2.2. Aquı́ se muestra los diferentes puntos de ancla. . . . . . . . . . . . . . . . . . 11

3.1. Mensaje de colisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

3.2. Imágenes de elementos gráficos . . . . . . . . . . . . . . . . . . . . . . . . . 20

3.3. Mapa del Juego . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3.4. La segunda hilera de frames corresponde a los frames de colisión . . . . . . 26

3.5. Antes y después de colisión . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

3.6. Imagen del Primer nivel del juego . . . . . . . . . . . . . . . . . . . . . . . . 30

5.1. Imágenes utilizadas en el mapa del nivel 2 . . . . . . . . . . . . . . . . . . . 37

5.2. Imagen que muestra los dos niveles uno y dos. . . . . . . . . . . . . . . . . . 40


Índice de cuadros
Capı́tulo 1

Introducción

En esta sección se describirán los conceptos básicos de la programación de MIDlets estas


son aplicaciones desarrolladas para dispositivos móviles con tecnologı́a Java ME. Comen-
zaremos por definir algunos conceptos:
MIDlet: es un programa en escrito en lenguaje de programación Java para dispositivos
móviles, especı́ficamente para la plataforma Java MicroEdition (Java ME). Generalmente
son juegos y aplicaciones que corren en un teléfono móvil. Un MIDlet consta de dos archivos
el archivo .jar que es el que contiene todo el código, y el otro archivo es .jad este contiene
una descripción del contenido del archivo .jar
Un MIDlet debe de cumplir con los siguientes requisitos:
-La clase principal necesita ser una subclase de javax.microedition.midlet.MIDlet.
-El MIDlet necesita ser empacado dentro de un archivo .jar.
-El archivo .jar necesita ser preverificado.

JVM: (máquina virtual de java) es un programa que funciona como plataforma para
interpretar el bytecode (código maquina de bajo nivel) generado por el compilador de java
1. Introducción iii

la principal ventaja de JVM es que el mismo código escrito en Java puede ejecutarse en
cualquier plataforma ya sea Windows, Linux u otro sistema operativo con el simple hecho de
tener instalada la Màquina virtual de Java.

JAR: (Archivo Java) este es un tipo de archivo de compresión que contiene en su interior
archivos pertenecientes a una aplicación de Java, como pueden ser clases, librerı́as y archivos
como imágenes y sonido que forman parte de la aplicación.

MIDlet Suite: esto se refiere a un grupo de MIDlets empacados en un solo JAR.

CLDC: (Connected Limited Device Configuration) describe el conjunto básico de bib-


liotecas y caracterı́sticas de la máquina virtual, que debe estar presente en una aplicación. La
CLDC está combinado con uno o más perfiles para dar a los desarrolladores una plataforma
para construir sus aplicaciones para dispositivos cuyo poder de procesamiento, memoria y
capacidad grafica se encuentra limitado, es decir, va dirigido principalmente a dispositivos
con cierta capacidad como teléfonos celulares, sistema de navegación GPS, entre otros.
La CLDC define las siguientes caracterı́sticas:
-Cuáles son las caracterı́sticas del lenguaje Java incluidas.
-Qué funcionalidad será incluida en la máquina virtual Java.
-Las APIs necesarias para el desarrollo de aplicaciones.
-Los requerimientos Hardware de los dispositivos.

La clase StringItem: Su función es añadir etiquetas de texto al formulario.


La sintaxis del constructor StringItem es el siguiente:

StringItem (String etiqueta, String texto)

La clase ImageItem: Con esta clase podemos añadir imágenes a un formulario.


1. Introducción iv

Su sintaxis es la siguiente:

ImageItem (String etiqueta, Image img, int layout, String texto_alternativo)

El parámetro texto alternativo es un texto que se mostrará en el caso en el que no sea posible
mostrar el gráfico. El parámetro layout indica cómo se posicionará el gráfico en la pantalla.
Sus posibles valores son:

LAYOUT_DEFAULT
LAYOUT_LEFT
LAYOUT_RIGHT
LAYOUT_CENTER
LAYOUT_NEWLINE_BEFORE
LAYOUT_NEWLINE_AFTER

La clase DateField: Con DateField tenemos una herramienta que permite la entrada de
datos de tipo fecha o tipo hora. Su sintaxis es la siguiente:

DateField (String etiqueta, int modo)

El parámetro modo puede tomar cualquiera de los siguientes valores:

DATE: para seleccionar una fecha


TIME:para seleccionar hora
DATE_TIME :Para seleccionar la entrada de una fecha o una hora.

La clase ChoiceGroup: este elemento permite seleccionar un valor de una lista de opciones.
Su sintaxis es la siguiente:

ChoiceGroup (String etiqueta, int tipo_lista, String[] elementos, image[] imagenes)

Los posibles tipos de lista son:

EXCLUSIVE - Solo se puede seleccionar un elemento


IMPLICIT - Se selecciona el elemento que tiene el foco
MULTIPLE - Permite la seleccion m\’ultiple
1. Introducción v

1.1. Descripción del proyecto

StreetChase

En Este proyecto se desarrollara un video juego para dispositivos móviles que implementen
la tecnologı́a Java ME (Java Micro Edition). Este video juego es un juego de carreras y
persecución en el que el jugador estará conduciendo un auto a través de una calle muy tran-
sitada en la que el reto será llegar a la meta sin sufrir mayores daños, el jugador tendrá que
evadir a otros autos y obstáculos que se atraviesen en el camino para hacer más fácil el juego
se podrá capturar objetos en el camino estos objetos podrán ser:
-Vidas.
-Armas.
-objetos para regeneración de daños.
-objetos.

Controles:
Las teclas con las que se utilizara el juego serán las siguientes:
2 = Arriba
4= Izquierda
6 = Derecha
8 = Abajo
0 = Disparo
5 = Utilización de objetos encontrados en el camino.
1. Introducción vi

1.2. Objetivo

El principal objetivo de este juego es conducir un auto hasta la lı́nea de meta sin recibir
suficientes daños, para esto el jugador deberá esquivar obstáculos en el camino y a los demás
autos que circulan en el camino.
El jugador tiene como meta terminar los tres niveles del juego, en los que se incrementara
sucesivamente la velocidad y dificultad del juego.

Para esto el jugador no deberá:


-Agotar la cantidad de vidas del juego.
-Salirse de la carretera.
-Chocar con los demás autos y objetos en el camino.

1.3. Requerimientos del sistema

Compatibilidad para aplicaciones java


Java CLDC 1.1
MIDP 2.0
Conexión bluetooth o cable para transferencia de datos
Resolución de pantalla de 176 X 220

1.4. Organización del documento


Capı́tulo 2

MIDlets

2.1. Mi primer MIDlet

El objetivo de Esta práctica es mostrar en la pantalla del celular el nombre del proyecto
y además tiene que aparecer justo en el centro de la pantalla.
Para realizar esta prácticas se utiliza una Clase de Java microedition llamada “Canvas” o
Lienzo en español esta es una subclase de la clase Displayable que forma parte del paquete
“lcdui”.

1- El primer paso es crear el proyecto con la estructura básica que debe llevar un MIDlet,
esto es incluir los paquetes lcdui y midlet, hacer una clase que herede directamente de mi-
dle y en este caso implementamos la interface CommandListener para poder introducir un
comando para salir de la aplicación, asi como también los métodos básicos del MIDlet estos
son: el constructor, el método startApp(), pauseApp() y destroyApp(boolean unconditional).

2- El siguiente paso es crear los campos de nuestra clase en este caso fueron dos:
2. MIDlets 2

private Command exitCommand;


private Displayable d;

3.- El siguiente paso es crear otra clase que heredara de la Clase Canvas. Esta clase no llevara
campos solo el método paint(Graphics g). este método desplegara el mensaje en pantalla;
Este método lo primero que hace es obtener la anchura y altura de la pantalla mediante los
métodos: getWidth() y getHeight().
Para desplegar el nombre del proyecto en pantalla se utiliza un método llamado drwString();

class TextoCentrado extends Canvas {


public void paint(Graphics g) {
int anchura = getWidth(); //obtiene el ancho de la pantalla
int altura = getHeight(); //obtiene la altura de la pantalla
/*
*Esta parte es la que despliega el mensaje en pantalla y para centrarlo se divide
*la altura y anchura entre dos , los últimos parámetros BASELINE Y HCENTER son
*para anclar el texto justo en el centro
*/
g.drawString("STREET CHASE",anchura/2,altura/2,Graphics.BASELINE|Graphics.HCENTER);
}
}

4. El siguiente paso es hacer el constructor de la clase principal.

public Practica2() {
//crea el commando Salir
exitCommand = new Command("Salir", Command.EXIT, 2);
d = new TextoCentrado();
//esta parte agrega el commando y un titulo a nuestro objeto Displayable
d.addCommand(exitCommand);
d.setTitle("Nombre Proyecto");
d.setCommandListener(this);
}

5. Por último se crea el método startApp().

public void startApp() {


Display.getDisplay(this).setCurrent(d);
}
2. MIDlets 3

2.2. Imágenes

Objetivo:

Esta práctica trata de realizar un programa que implemente imágenes en un MIDlet, este
deberá ser un programa que desplegué en la pantalla del teléfono celular una imagen referente
al proyecto a realizar para esto se utilizara una subclase de la clase Item llamada ImageItem.

Procedimiento:

1) Primero se crea o escoge una imagen de preferencia con formato .PNG, es importante
que la imagen no sobrepase a la resolución del dispositivo utilizado.

2) Se crea un nuevo proyecto, al crear un nuevo proyecto se genera el directorio /res en


este directorio se depositan todos los archivos como imágenes, audio, etc. En este directorio
se deberá colocar la imagen a utilizar.

3) El siguiente paso es crear su clase principal con sus métodos correspondientes y como
capos un objeto de tipo Display.

4) Una vez creada la clase queda solamente queda crear el método startApp este es el
método principal de la clase el cual deberá contener el siguiente código:

public void startApp() {


display = Display.getDisplay(this);
2. MIDlets 4

//se crea un Nuevo formulario y se agrega el encabezado


Form form = new Form("Practica 3 Imagenes");
try {
//crea un objeto de tipo Image e indicamos la ruta de nuestra imagen
Image img = Image.createImage("/img.png");
//se agrega la imagen a nuestro Form con el constructor de ImageItem
form.append(new ImageItem("img", domo, ImageItem.LAYOUT_CENTER, null));
} catch (IOException ex) {
form.append("Fallo al cargar la imagen");
}
// Hace que se despliegue el Form creado anteriormente
display.setCurrent(form);
}

5) Por último se crean los paquetes JAR y JAD para después ejecutarlos en su dispositivo
móvil.
2. MIDlets 5

2.3. Pantallas

Objetivo:
Crear el menú principal del video juego el cual debe de incluir las siguientes opciones:
-Jugar
-Reglas
-Mejores puntuacuiones
-Creditos
Además crear las pantallas para las reglas del juego y los créditos.

Introducción:
Para esta práctica se utilizaros Screens de tipo List y Form. Para realizar el menú principal
se utilizo una Lista de tipo IMPLICIT, estas despliegan una listas de elementos en las que se
puede seleccionar solo un elemento a la vez. Para obtener el elemento seleccionado o verificar
si un elemento fue seleccionado en el menú se puede utilizar el método getSelectedIndex()
o también el método isSelected(int NUM ELEMENTO), la diferencia es que el primero
regresa el numero del elemento seleccionado y el otro es un método booleano que te dice si
un elemento en especifico fue seleccionado.
Para desplegar las reglas del juego y los créditos se utilizaron objetos de tipo StringItem.

Procedimiento:
1- Crear un nuevo MIDlet.

2- Hacer una clase con el nombre Menú la cual contendrá los siguientes campos:

private Display display;


private List menu;
2. MIDlets 6

private Command exit;


private Command ok;
private Command back;

3- Crear el constructor.

public Menu() {
display = Display.getDisplay(this);
// Crea los comandos
exit = new Command("Salir", Command.EXIT, 1);
ok = new Command("OK", Command.OK, 1);
regresar = new Command("Regresar", Command.BACK, 1);
// genera un vector con los nombres de las opciones
String[] opciones = new String[]{"JUGAR", "REGLAS", "MEJORES PUNTUACIONES", "CRÉDITOS"};
// crea la Lista para el Menu
menu = new List("OPCIONES", List.IMPLICIT, opciones, null);
// Agrega los comandos al menu
menu.addCommand(exit);
menu.addCommand(ok);
menu.setCommandListener(this);
}

4- Después se crea un método para manejar las selecciones que se hagan en el menú prin-
cipal.

private void choose() {


if (menu.isSelected(0))
jugar();
else if (menu.isSelected(1))
reglas();
else if (menu.isSelected(2))
records();
else if (menu.isSelected(3))
2. MIDlets 7

creditos();
}

5- Después se crean cada uno de los métodos que serán llamados cada que se seleccione
una opción en el menú principal en esta práctica solo se crearon los métodos que despliega
las reglas del juego y los créditos. Las dos métodos tienen el siguiente formato:

//método que despliega los créditos del proyecto


private void creditos() {
//se crea un Nuevo Form
Form creditos = new Form("CREDITOS");
//se a~
nade el comando para regresar al menú principal.
creditos.addCommand(regresar);
//se activa el commanListener
creditos.setCommandListener(this);
//se a~
nade un StringItem con el texto a desplegar
creditos.append(new StringItem("Aquı́ va el texto a imprimir", Item.BUTTON));
// hace visible al Form creado
display.setCurrent(creditos);
}
}

6- Se crea el método commandAction.

//en este metodo se asignan las acciones a cada camando


public void commandAction(Command c, Displayable displayable) {
//si se captura el comando ok o el comando de selección
//se manda a llamar a la opción seleccionada
if (c == List.SELECT_COMMAND || c == ok) {
choose();
} else if (c == exit) {
destroyApp(false);
notifyDestroyed();
2. MIDlets 8

} else if (c == regresar) {
display = Display.getDisplay(this);
display.setCurrent(menu);
}
}

7- Por último se crea el startApp().

public void startApp() { // Hace visible el menú


display.setCurrent(menu);
}

Resultados

Figura 2.1: Mostrando el menú en ejecución.


2. MIDlets 9

2.3.1. Métodos de Canvas

setColor()
Este método establece el color a utilizar al dibujar un objeto en pantalla.
Sintaxis:
void setColor(int rojo, int verde, int azul)
Los parámetros de color tienen un rango de 0 a 255.

setGrayScale()
Este método se utiliza para escoger la tonalidad de grises para dibujar un objeto en pantalla,
este puede utilizar para dispositivos que no tienen pantalla a color.
Sintaxis:
void setGrayScale(int tono)
El parámetro tono puede tomar un valor entre 0 y 255.

drawLine()
Este método dibuja una lı́nea de una coordenada inicial a una final.
Sintaxis:
void drawLine (int x1, int y1, int x2, int y2)
dibuja una lı́nea que une el punto (x1, y1) con (x2, y2).

drawRect()
Este método dibuja un rectángulo en pantalla.
Sintaxis:
void drawRect (int x, int y, int ancho, int alto)
Los parámetros (x , y) indican cual será la esquina superior izquierda del rectángulo.
2. MIDlets 10

Los siguientes dos parámetros nos indican el ancho y el alto que tendrá el rectángulo en
pı́xeles.

-El método que despliega un rectángulo con relleno es el siguiente:


void fillRect (int x, int y, int ancho, int alto)

drawRoundRect()
Este método también sirve para dibujar rectángulos pero con sus esquinas redondeadas.
Sintaxis:
void drawRoundRect (int x, int y, int ancho, int alto, int ancho arco, int al-
to arco)
Los parámetros (x,y) son las coordenadas de la esquina superior izquierda.
Los dos siguientes parámetros establecen el alto y ancho del rectángulo.
Los otros dos parámetros son al ancho y el alto del arco de las esquinas.

-El método que despliega un rectángulo con esquinas redondeadas con relleno es el sigu-
iente:
void fillRoundRect (int x, int y, int ancho, int alto, int ancho arco, int al-
to arco)

drawArc()
Con este método se pueden dibujar secciones de arco.
void drawArc(int x, int y, int ancho, int alto, int ángulo inicial, int ángulo)
Los parámetros (x,y) son las coordenadas en donde se anclara el arco.
Los siguientes dos parámetros establecen el alto y ancho.
2. MIDlets 11

Los siguientes parámetros establecen el ángulo inicial y el ángulo del arco (longitud del arco).

-El método que despliega un arco con relleno es el siguiente:


void fillArc(int x, int y, int ancho, int alto, int ángulo inicial, int ángulo)

drawString()
Este método permite desplegar texto en pantalla en modo grafico.
Sintaxis:
void drawString (String texto, int x, int y, int ancla)
El primer parámetro es el texto que queremos mostrar.
Los parámetros (x, y) indican la posición donde se situara el texto dentro de la pantalla.
El cuarto parámetro indica cuál es el punto de referencia para situar el texto en las coorde-
nadas.
Los valores posibles son:
TOP, BASELINE y BUTTOM para la posición vertical del texto.
LEFT, HCENTER y RIGHT para la posición horizontal del texto.

Figura 2.2: Aquı́ se muestra los diferentes puntos de ancla.

setFont()
2. MIDlets 12

Método que se utiliza para establecer el tipo de fuente.


Sintaxis:
void setFont(Font fuente)
Esta función selecciona la fuente a utilizar.
El método getFont() de la clase Font nos devuelve un objeto de tipo Font que se puede uti-
lizar con setFont().
static Font getFont (int espaciado, int estilo, int tamaño)
Los valores posibles para estos parámetros son:
Tamaño : SIZE SMALL, SIZE MEDIUM, SIZE LARGE
Estilo: STYLE PLAIN, STYLE ITALICS, STYLE BOLD, STYLE UNDERLINED
Espaciado: FACE SYSTEM, FACE MONOSPACE, FACE PROPORTIONAL

drawImage()
Este método se utiliza para desplegar imágenes en una posición determinada.
Sintaxis:
boolean drawImage(Image img, int x, int y, int ancla)
Los parámetros (x,y) son las coordenadas donde se situara la imagen.
El último parámetro es donde se anclara el texto en las coordenadas, sus posibles valores son:
TOP, VCENTER y BUTTON determinan el posicionamiento vertical (superior, cento verti-
cal, base).
LEFT, HCENTER, RIGHT para la posición horizontal (lado izquierdo, centro horizontal,
lado derecho).
Capı́tulo 3

Ambiente Grafico

3.1. Sprites

Introducción:
En esta sección se creara un MIDlet en el que se utilizaran “Sprites”, esto es un elemento
grafico con identidad propia al cual se pude cambiar su aspecto y posición en pantalla entre
otras cosas, este puede ser un auto, avión, pelota, etc.
Se utilizara el método “boolean collide(Sprite sp)” para determinar si dos “Sprites” están
utilizando el mismo espacio en pantalla.

Objetivo:
Desarrollar un MIDlet en el que se empleen dos o más “Sprites” y desplegué un mensaje si
hay colisión entre los dos Sprites.

Desarrollo:
1- Crear la clase Sprite con los siguientes campos y constructor.
3. Ambiente Grafico 14

class Sprite {
private int posx, posy; //indicaran las coordenadas del Sprite
private boolean active; //indica si esta activo el Sprite
private int frame, nframes; //frame actual y num total de frames
private Image[] sprites; // vector que contiene a los frames

public Sprite(int nframes) { //constructor que recibe el total de frames


active = false; //comienza el Sprite como inactivo
frame = 1; // establece al frame 1 como frame actual
this.nframes = nframes; //establece la cantidad de frames
sprites = new Image[nframes + 1]; //crea vector de frames
}

//modificadores
public void setX(int x) {
posx = x;
}
public void setY(int y) {
posy = y;
}
// accesadores.

public int getX() {


return posx;
}
public int getY() {
return posy;
}
public int getW() {
return sprites[nframes].getWidth();
}
3. Ambiente Grafico 15

public int getH() {


return sprites[nframes].getHeight();
}
//método que establece como activo o inactivo al Sprite
public void setActive(boolean active) {
this.active = active;
}
//método que verifica si es o no activo
public boolean isActive() {
return active;
}
//método que establece al frame actual
public void selFrame(int frameno) {
frame = frameno;
}
//método que agrega un frame al Sprite
public void addFrame(int frameno, String path) {
try {
sprites[frameno] = Image.createImage(path);
} catch (IOException e) {
System.out.println("Error: " + e.toString());
}
}
//método que verifica si hay colisión entre dos Sprites
public boolean collide(Sprite sp) {

int w1 = getW(); // ancho del sprite1


int h1 = getH(); // altura del sprite1
int w2 = sp.getW(); // ancho del sprite2
int h2 = sp.getH(); // alto del sprite2
int x1 = getX(); // pos. X del sprite1
3. Ambiente Grafico 16

int y1 = getY(); // pos. Y del sprite1


int x2 = sp.getX(); // pos. X del sprite2
int y2 = sp.getY(); // pos. Y del sprite2

if (((x1 + w1) > x2) && ((y1 + h1) > y2) && ((x2 + w2) > x1) && ((y2 + h2) > y1)) {
return true;
} else {
return false;
}
}
//método que despliega al Sprite en pantalla
public void draw(Graphics g) {
g.drawImage(sprites[frame], posx, posy, Graphics.HCENTER | Graphics.VCENTER);
}
}

2- Generar una clase que herede de Canvas. En esta clase se crearan los Sprites
y contendrá el método que desplegara un mensaje en pantalla si hay colisión entre
los Sprites.

class SSCanvas extends Canvas {


//se generan dos Sprites distintos
private Sprite miSprite1 = new Sprite(1);
private Sprite miSprite2 = new Sprite(1);

public SSCanvas() {
//agregar las imágenes para los Sprites
miSprite1.addFrame(1, "/fig.png");
miSprite2.addFrame(1, "/fig2.png");
//establecer las coordenadas de los Sprites
miSprite1.setX(getWidth() / 2);
miSprite1.setY(getHeight() / 2 + 50);
3. Ambiente Grafico 17

miSprite2.setX(60);
miSprite2.setY(50);
//activar a los dos Sprites
miSprite1.setActive(true);
miSprite2.setActive(true);
}
public void paint(Graphics g) { //método para dibujar la pantalla
g.setColor(0, 0, 0);
g.fillRect(0, 0, getWidth(), getHeight()); //limpia la pantalla
//despliega los Sprites
miSprite1.draw(g);
miSprite2.draw(g);
//si el Sprite1 colisiona con Sprite2 despliega el String ‘‘Colisión’’
g.setColor(250, 1, 1);
if (miSprite1.collide(miSprite2))
g.drawString("Colisión", getWidth() / 2, 20, Graphics.BASELINE | Graphics.HCENTER);
}
}

3- Generar la clase de prueba.

public class SpriteTest extends MIDlet {


private Display display;
private SSCanvas screen;

public SpriteTest() {
display = Display.getDisplay(this);
screen = new SSCanvas();
}
public void startApp() throws MIDletStateChangeException {
display.setCurrent(screen);
}
3. Ambiente Grafico 18

public void pauseApp() { }


public void destroyApp(boolean b) { }
}

Resultados:

Figura 3.1: Mensaje de colisión


3. Ambiente Grafico 19

3.2. Mapas

Introducción:
En esta sección se desarrollara una aplicación MIDlet la cual contendrá el mapa del proyecto
elegido, un mapa es el grafico principal de un videojuego que contiene todos los elementos
gráficos como Sprites y Layers (capas), que pueden estar conformado de pequeños cuadros
que juntos forman las capas del juego. Los elementos pueden ser estáticos (sin animación) o
dinamicos.

Objetivo:
Crear el mapa del proyecto utilizando las clases de Java GameCanvas, TiledLayer y Lay-
erManager para definir el fondo de la pantalla. Debe contener el menor número de imágenes
con las cuales se formará el fondo completo del proyecto.

Procedimiento:

1- Crear una clase que herede de GameCanvas e implemente la interface


Runnable, esta clase deberá contener los siguientes campos:

public class StreetChase extends GameCanvas implements Runnable {


// CAMPOS DE LA CLASE
int coordX = 16; //coordenada de pixel de referencia X de mapa
int coordY = 550; //coordenada de pixel de referencia y de mapa
int coordXSprite; //coordenada X de Sprite
int coordYSprite; //coordenada Y de Sprite
final static int WIDTH_VW = 176; //ancho de ventana visible
final static int HEIGHT_VW = 220; //alto de ventana visible
Image tiled = null; //imágenes del mapa
3. Ambiente Grafico 20

Image sprited = null; //imágenes del Sprite


Image arboles = null; //imágenes de los arboles
LayerManager lm; //ordenador de capas
TiledLayer tl; //cuadros que conforman el mapa
Sprite carro; //Sprite principal
Sprite arbol[] = new Sprite[6]; //Sprites arboles del mapa
Graphics g; //objeto Graphics

2- Crear las imágenes que contendrán los cuadros que conforman los elementos
visuales del video juego.

Figura 3.2: Imágenes de elementos gráficos

3- Crear el constructor de la case, en este se asignan las imágenes creadas en


el punto anterior a objetos de tipo Image, para luego ser divididos en cuadros en
el TiledLayer y ası́ crear el mapa.

// CONSTRUCTOR
public StreetChase(boolean b) {
super(b);
int y = coordY + 160;

// Inicializacion de variables
g = getGraphics();
// Layer manager en el que colocar los distintos
// elementos visuales que componen la aplicacion
lm = new LayerManager();
//se asignan las imagenes
try {
tiled = Image.createImage("/tiledLayer.png");
3. Ambiente Grafico 21

sprited = Image.createImage("/carro1.png");
} catch (java.io.IOException e) { }
// Inicializacion del TiledLayer
tl = new TiledLayer(13, 48, tiled, 16, 16);
//continua en el siguiente paso

4- Después en el mismo constructor se crea un vector o una matriz la cual se


debe llenar con los números referentes a cada cuadro de la imagen Tiled para
después crear el mapa de fondo con un ciclo for.

//creacion del vector con las posiciones de


//los elementos del mapa
int[] map = {
1, 1, 2, 3, 3, 3, 3, 3, 3, 5, 1, 1, 1,
1, 1, 2, 3, 3, 3, 4, 3, 3, 5, 1, 1, 1,
1, 1, 2, 3, 3, 3, 3, 3, 3, 5, 1, 1, 1,
1, 1, 2, 3, 3, 3, 4, 3, 3, 5, 1, 1, 1,
1, 1, 2, 3, 3, 3, 3, 3, 3, 5, 1, 1, 1,
... ETC.
};

//rellena la capa de fondo del mapa con los elementos del vector map[]
for (int i = 0; i < map.length; i++) {
int column = i % 13;
int row = (i - column) / 13;
tl.setCell(column, row, map[i]);
}
// hacemos visible el TiledLayer que dibuja el fondo
tl.setVisible(true);

5- Una vez creado el mapa de fondo se crean los demás elementos que conforman
el juego como pueden ser Sprites, capas y demás elementos visuales, para después
ser añadidos al objeto LayerManager.
3. Ambiente Grafico 22

// Sprite que representa la animacion


carro = new Sprite(sprited, 18, 30);
//asignacion de pocision inicial del Sprite
coordXSprite = getWidth() / 2;
coordYSprite = coordY + 150;
carro.defineReferencePixel(0, 25);
carro.setRefPixelPosition(coordXSprite, coordYSprite);
// a~
nadimos los distintos Layers al LayerManager
carro.setVisible(true);
lm.append(carro);
lm.append(tl);

6- En el constructor se define la región del mapa que será visible con setViewWin-
dow().

// Definimos la ventana visible y la dibujamos


lm.setViewWindow(coordX, coordY, WIDTH_VW, HEIGHT_VW);
lm.paint(g, 0, 0);
flushGraphics();
}

7- Por último se implementa el método run() de la interface Runnable, en este


método se realiza el repintado ası́ como también el movimiento de los Sprites y
de la región visible del mapa.

public void run() {


int keyState;
while (true) {
try {
// Actualizar el estado del juego.
keyState = this.getKeyStates();
if (keyState != 0) {
//actualiza la posicion con respecto a la tecla pulsada
3. Ambiente Grafico 23

this.actualizaPosicion(keyState);
lm.setViewWindow(coordX, coordY, WIDTH_VW, HEIGHT_VW);
carro.setRefPixelPosition(coordXSprite, coordYSprite);
// Responder a la pulsacion de teclas,
// repintando
lm.paint(g, 0, 0);
flushGraphics();
// Esperamos.
Thread.sleep(50);
}
} catch (Exception e) {
System.out.println(e);
} } }

Resultados:

Figura 3.3: Mapa del Juego


3. Ambiente Grafico 24

3.3. Sprites y Colisiones

Introducción:

En esta sección se desarrollara la parte del proyecto en la cual se implementa el manejo


de Colisiones de Sprites, Un Sprite es una elemento grafico con identidad propia al cual se
puede cambiar su aspecto y posición en pantalla entre otras cosas, este puede ser un auto,
avión, pelota, etc. Para manejar las colisiones entre Sprites existen cuatro métodos de la clase
Sprite los cuales se definirán a continuación:

- collidesWith(Sprite s, boolean pixelLevel)


Determina si existe una colision entre un Sprite y otro Sprite.

Parametros:
* s = Sprite con el cual se revisara si hay collision.
* pixelLevel = true prueba si existe colisión tomando en cuenta solo los pixeles opacos,
false para detectar colisión tomando en cuenta los bordes.

Retorno: true si los dos Sprites colisionan o false si no hay colisión.

- collidesWith(Image image, int x, int y, boolean pixelLevel)


Determina si existe una colisión entre un Sprite y un Objeto de tipo Image.

Parámetros:
*Image= es el Objeto Image que establecerá si este colisiona con el Sprite.
*X =coordenada X de esquina superior izquierda.
*Y =coordenada Y de esquina superior izquierda.
*pixelLevel = true prueba si existe colisión tomando en cuenta solo los pixeles opacos ,
false para detectar colisión tomando en cuenta los bordes.
3. Ambiente Grafico 25

Retorno: true si los dos colisionan false si no hay colisión.

-collidesWith(TiledLayer t, boolean pixelLevel)


Este método se utiliza para determinar si un Sprite colisiona con una capa.

Parámetros:
*t= es la capa con la cual se determinara si existe colisión.
*pixelLevel = true prueba si existe colisión tomando en cuenta solo los pixeles opacos ,
false para detectar colisión tomando en cuenta los bordes.

Retorno: true si los dos colisionan false si no hay colisión.

-defineCollisionRectangle(int x, int y, int width, int height)


define el área de un Sprite que será utilizada para la detección de colision.

Parámetros:
* X =coordenada X de esquina superior izquierda del rectángulo.
* Y =coordenada Y de esquina superior izquierda del rectángulo.
* width = longitud horizontal del rectángulo.
* height = longitud vertical del rectángulo.

Objetivo:
Realizar la parte del proyecto que involucra la utilización de Sprites y Colisiones.

Procedimiento:

1- Realizar las imágenes de los Frames de los Sprites que representaran la


colisión.
3. Ambiente Grafico 26

Figura 3.4: La segunda hilera de frames corresponde a los frames de colisión

2- Crear los Sprites con los cuales se podrá colisionar.

public void posicionarArboles() {


int y = coordY + 162;
//a~
nadiendo los arboles al LayerManager
for (int i = 0; i < 6; i++) {
arbol[i] = new Sprite(arboles, 23, 30);
if (i % 2 == 0) {
arbol[i].setRefPixelPosition(coordX, y);
} else {
arbol[i].setRefPixelPosition(coordX + 140, y);
}
arbol[i].setFrame(i);
arbol[i].setVisible(true);
lm.append(arbol[i]);
y -= 54;
}
}

3- Crear un método que revise en cada momento si existe alguna colisión, este
método deberá invocarse desde el método run().

public void manejoColisiones() {


for (int i = 0; i < 6; i++)
3. Ambiente Grafico 27

if (carro.collidesWith(arbol[i], true)) { // revisa si existe colisión


//Si existe colisión se establecen los Frames referentes a colisiones
arbol[i].setFrame(i+6);
carro.setFrame(carro.getFrame()+4);
}
}

Resultados:

Figura 3.5: Antes y después de colisión


3. Ambiente Grafico 28

3.4. Primer nivel del Juego

Introducción:
En esta sección se desarrollara el primer nivel del juego, esto incluye el movimiento de los
enemigos y del Sprite que representa al jugador, ası́ como también el manejo de colisiones;
en esta sección también se establecen los daños que aumentaran cada vez que el jugador coli-
sione con algo y en el caso de las vidas se descontara una cada vez que los daños lleguen a 100.

Procedimiento:

1- El primer paso fue agregar los campos a la clase del juago para representar
a los enemigos, balas, jugador y las vidas.

// CAMPOS DE LA CLASE
int vidas; //contador de Vidas
Sprite[] arbol = new Sprite[6]; //Sprites arboles del mapa
Sprite[] bala = new Sprite[6]; //Sprites para las balas
Auto player; //Sprite del Jugador
Auto auto[] = new Auto[6]; //Sprites para el trafico

2- Después se crearon los siguientes métodos para inicializar todos los Sprites
del Juego:

public void inicializarAutos(); //crea y asigna valores iniciales a los autos del juego
public void inicializarBalas(); //utiliza un ciclo para inicializar las balas

3- Después se creó un método para realizar el movimiento de todos los Sprites


en el Juego.

public void desplazamiento() {


for (int i = 0; i < 6; i++) {
auto[i].move(0, -2); //movimiento de los autos
3. Ambiente Grafico 29

if (auto[i].getRefPixelY() > coordY + HEIGHT_VW) { //verifica si algun auto salio de la pantalla


auto[i].setRefPixelPosition(new Random(i + Thread.activeCount() + coordY).nextInt(133 - 45 + 1) +
45, auto[i].getRefPixelY() - 340);
auto[i].setFrame(i % 2);
auto[i].setDeterioro(0);
}
if (arbol[i].getRefPixelY() > coordY + HEIGHT_VW) { //verifica si algun arbol salio de la pantalla
arbol[i].move(0, - 320);
arbol[i].setFrame(i);
}
if (recorrioMapa) { //verifica si se cumplio un ciclo del mapa
arbol[i].setRefPixelPosition(arbol[i].getRefPixelX(), player.getRefPixelY() + arbol[i].getRefPixelY() -
coordYAnterior - player.getdY());
auto[i].setRefPixelPosition(auto[i].getRefPixelX(), player.getRefPixelY() + auto[i].getRefPixelY() -
coordYAnterior - player.getdY());
}
colisiones(i); //verifica si existe alguna colision
}
recorrioMapa = false;
}

4- El siguiente paso es crear un método que administrara las colisiones, en este


método se administraran los daños que sufra el jugador y descontara las vidas.

void colisiones(int i) {
if (player.collidesWith(auto[i], true) && auto[i].getDeterioro() == 0) {
auto[i].setFrame(auto[i].getFrame() + 2);
auto[i].setDeterioro(auto[i].getDeterioro() + 30);
if (player.getDeterioro() == 0) {
player.setImage(playerCollideImg, 18, 33);
}
player.setDeterioro(player.getDeterioro() + 30);
} else if (player.collidesWith(arbol[i], true)) {
arbol[i].setFrame(i + 6);
if (player.getDeterioro() == 0) {
3. Ambiente Grafico 30

player.setImage(playerCollideImg, 18, 33);


}
player.setDeterioro(player.getDeterioro() + 20);
}
//el sig if descuenta una vida cada que los da~
nos llegan a 100%
if (player.getDeterioro() >= 100) {
vidas--;
player.setDeterioro(0);
}
}

Resultados:

Figura 3.6: Imagen del Primer nivel del juego


Capı́tulo 4

RMS(Record Manegment System)

4.1. Registros

Introducción:

En esta práctica se realizara la parte del proyecto que almacenara los records del juego,
para esto se utilizaran las clases del paquete RMS(Record Manegment System); Este
paquete contiene todo lo necesario para crear, manipular, comparar y modificar registros.

Objetivo:

Realizar la opción para capturar el nombre del jugador e implementar el puntaje que el
jugador va adquiriendo en el juego, además ya debe mostrar cuando se termina el primer
nivel o en su caso cuando el jugador no alcance a terminarlo. El juego deberá tener la opción
para mostrar los mejores 5 puntajes, incluyendo el nombre de jugador en orden descendente.

Procedimiento:
4. RMS(Record Manegment System) 32

1- Realizar una clase que se encargue del manejo de registros, esta clase debe
de implementar la interface RecordComparator para ordenar los registros; la
clase debe contener los siguientes campos y constructor :

public class Registros implements RecordComparator {


// El RecordStore usado para almacenar los Scores.
private RecordStore recordStore = null;
//constructor
public Registros() {
try {
recordStore = RecordStore.openRecordStore("scores", true);
} catch (RecordStoreException rse) {}
}
}

2- Después en la misma clase se crea un método para agregar registros, este


método recibe como parámetros el score y el nombre del jugador.

public void addScore(int score, String playerName) {


ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream outputStream = new DataOutputStream(baos);
try {
// agrega el score al Byte Array.
outputStream.writeInt(score);
// tambien agrega el nombre del jugador.
outputStream.writeUTF(playerName);
} catch (IOException ioe) { }

// extrae el Byte Array


byte[] b = baos.toByteArray();
// y lo agrega al recordStore
try {
recordStore.addRecord(b, 0, b.length);
4. RMS(Record Manegment System) 33

} catch (RecordStoreException rse) {}


}

3- Luego se debe implementar el método “compare” de la interface Record-


Comparator, este método compara dos registros y se utilizar para ordenar los
registros.

public int compare(byte[] rec1, byte[] rec2) {


// Constructor DataInputStreams para extraer los scores.
ByteArrayInputStream bais1 = new ByteArrayInputStream(rec1);
DataInputStream inputStream1 = new DataInputStream(bais1);
ByteArrayInputStream bais2 = new ByteArrayInputStream(rec2);
DataInputStream inputStream2 = new DataInputStream(bais2);
int score1 = 0;
int score2 = 0;
try {// Extrae los scores.
score1 = inputStream1.readInt();
score2 = inputStream2.readInt();
} catch (EOFException eofe) {}

// Ordena de Mayor a Menor los Scores


if (score1 < score2) {
return RecordComparator.EQUIVALENT;
} else if (score1 > score2) {
return RecordComparator.PRECEDES;
} else {
return RecordComparator.EQUIVALENT;
}
}

4- El siguiente paso es crear un método que regrese una lista de scores ordena-
da de mayor a menor, este método podrá ser llamado para desplegar los records
en pantalla.
4. RMS(Record Manegment System) 34

public String toString() {


RecordEnumeration re = null;
String lista = new String();
try {//Enumera los records utilizando la implementación compare de RecordComparator
re = recordStore.enumerateRecords(null, this, true);
while (re.hasNextElement()) {
int id = re.nextRecordId();
ByteArrayInputStream bais = new ByteArrayInputStream(
recordStore.getRecord(id));
DataInputStream inputStream = new DataInputStream(bais);
try {
int score = inputStream.readInt();
String playerName = inputStream.readUTF();
lista += "\n" + score + " ---- " + playerName;
} catch (EOFException eofe) { }
}
} catch (RecordStoreException rse) {}
return lista;
}

5- Después de esto el siguiente paso es implementar la clase creada anterior-


mente para almacenar los records del juego, para esto en la clase del juego se
agregan los siguientes campos y métodos:

Registros registros = new Registros();


String nick = new String("Anonimo");
int score;

//modificador para el nombre del jugador


public void setNick(String nick) {
this.nick = nick;
}
4. RMS(Record Manegment System) 35

6- En la parte en donde termina el juego se agrega la siguiente lı́nea para


guardar el registro del score obtenido por el jugador.

registros.addScore(score, nick);

7- Después se debe realizar un método que despliegue un “TextField”, este


es un objeto de tipo Item utilizado para introducir texto; esto para introducir el
nombre del jugador.

void addNick() {

formulario.addCommand(regresar);
formulario.addCommand(jugar);
formulario.setCommandListener(this);
//formulario.append(fondo);
formulario.append(nickInput);
}

-la siguiente line es utilizada para pasar el nombre del jugador al juego para
después crear el registro.

juego.setNick(nickInput.getString());

8- El último paso es realizar un método en la clase principal que se encargara


de desplegar en pantalla todos los scores en orden de mayor a menor.

private void records() {


Form records = new Form("REGLAS DEL JUEGO");
records.addCommand(regresar);
records.addCommand(exit);
records.setCommandListener(this);
records.append(new StringItem("", "Puntaje Nick\n" + registros.toString(), Item.BUTTON));
display.setCurrent(records);
}
Capı́tulo 5

Proyecto Terminado

5.1. Agregar Niveles

Introducción:

En esta práctica se verá como agregar más niveles al juego y además agregar dificultad a
cada nivel agregando mas enemigos, para esto se requiere crear un nuevo mapa e imágenes
de los sprites esto para cambiar el aspecto del escenario del juego al pasar al siguiente nivel
y también inicializar de nuevo todos los sprites y posiciones. También se agregara la parte
del proyecto que despliega el puntaje actual.

Objetivo:

Crear y agregar nuevos niveles del juego además implementar el puntaje actual y aumentar
la dificultad cada que se pase de nivel.
5. Proyecto Terminado 37

Procedimiento:

1- El primer paso para agregar otro nivel al juego es crear las imágenes que
serán utilizadas en el nuevo mapa y en los sprites que serán agregados.

Figura 5.1: Imágenes utilizadas en el mapa del nivel 2

2- Después se agrega una bandera a la clase del juego, esta bandera se activara
cuando se termine cada nivel. También debe agregarse una variable que almacene
el nivel en que se encuentre el juego.

boolean pasoNivel = false;


int level; //almacena el nivel actual del juego.

3- Después se agrega en el método run() un if que revise si termino el nivel o


llego a la meta.

//Revisar si llego a la meta


if (distancia <= 0) {
level++;//incrementa el nivel.
pasoNivel = true;//se activa la bandera
//despliega la imagen de fin Nivel
g.drawImage(finNivel, 95, HEIGHT_VW / 2, Graphics.HCENTER | Graphics.VCENTER);
}

4- Se crea un método que inicialicé el siguiente nivel este método debe hacer
lo siguiente: -cambiar las imágenes del mapa. -restablecer los valores por default
de sprite de jugador. -inicializar de nuevo los arboles con las nuevas imágenes.
-restablecer los autos a sus valores iniciales. -desaparecer explosiones activas.
5. Proyecto Terminado 38

public void inicializarNivel2() {


distancia = 5000;
//se asignan las nuevas imagenes
try {
tiled = Image.createImage("/tiledLayer2.png");
arboles = Image.createImage("/arbolesNivel2.png");
} catch (java.io.IOException e) {}
player.setDeterioro(0);//restablece el danio
player.setImage(playerImg, 18, 33);//restablece las imagenes antes de colision
player.setFrame(0);
medidor.setFrame(0);//vida al 100%

// Cambiando la imagen del TiledLayer


tl.setStaticTileSet(tiled, 16, 16);

//Cambiando la imagen de arboles


for (int i = 0; i < 6; i++) {
arbol[i].setImage(arboles, 23, 30);
arbol[i].setCollide(false);
arbol[i].setFrame(i);
//establece valores iniciales de los autos
if (i % 2 == 0) {
auto[i].setFrame(0);
} else {
auto[i].setFrame(1);
}
auto[i].setdY(-2);
auto[i].setVisible(true);
auto[i].setDeterioro(0);
auto[i].move(HEIGHT_VW, 0);
//quita las explosiones activas
5. Proyecto Terminado 39

explosion[i].setActive(false);
explosion[i].setVisible(false);
explosion[i].setFrame(0);
}
lm.paint(g, 0, 0);//repintar
flushGraphics();
try { //Hace una pequenia pausa antes de iniciar el siguiente nivel.
Thread.sleep(3000);
} catch (InterruptedException ex) {}
}

5- Por último se agrega el siguiente código en el método run() para revisar


cuando la bandera de nivel terminado se active y en ese caso inicialice el nivel
siguiente.

if (pasoNivel) { //si paso de nivel


if (level == 2) {//si nivel = 2 inicializa el nivel 2
inicializarNivel2();
} else {//sino termino el juego
gameover = true;
}
pasoNivel = false;//desactiva la bandera
}

Para desplegar el puntaje actual en pantalla se agrega la siguiente lı́nea al método run().

g.drawString("SCORE:" + score, 130, 20, Graphics.BASELINE | Graphics.HCENTER);

Resultados:
5. Proyecto Terminado 40

Figura 5.2: Imagen que muestra los dos niveles uno y dos.
5. Proyecto Terminado 41

Java a Tope: J2me (java 2 Micro Edition).


Sergio Gálvez Rojas, Lucas Ortega Dı́az
http://www.it.uc3m.es/celeste/docencia/j2me/tutoriales

También podría gustarte