3.283 cursos gratis
6.261.122 alumnos
Publica tu curso gratis
Busca cursos gratis:
Estás aquí: mailxmail > Cursos de Informática > Programación > Programación de juegos para móviles con J2ME > Control de sprites

Programación de juegos para móviles con J2ME

Autor: Alberto García Serrano
Curso:  4,52/5 4,52/5 (83 opiniones) |12480 alumnos|Fecha publicación: 07/09/2004

Capítulo 16:

 Control de sprites

Vamos a realizar una pequeña librería (y cuando digo pequeña, quiero decir realmente pequeña) para el manejo de los sprites. Luego utilizaremos esta librería en nuestro juego, por supuesto, también puedes utilizarla en tus propios juegos, así como ampliarla, ya que cubrirá sólo los aspectos básicos en lo referente a sprites.

Dotaremos a nuestra librería con capacidad para movimiento de sprites, animación (un soporte básico) y detección de colisiones.

Para almacenar el estado de los Sprites utilizaremos las siguientes variables.

 private int posx,posy;
 private boolean active;
 private int frame,nframes;
 private Image[] sprites;

Necesitamos la coordenada en pantalla del sprite (que almacenamos en posx y posy. La variable active nos servirá para saber si el sprite está activo. La variable frame almacena el frame actual del sprite, y nframes el número total de frames de los que está compuesto. Por último, tenemos un array de objetos Image que contendrá cada uno de los frames del juego.

Como puedes observar no indicamos el tamaño del array, ya que aún no sabemos cuantos frames tendrá el sprite. Indicaremos este valor en el constructor del sprite.

 // constructor. 'nframes' es el número de frames del Sprite.
 public Sprite(int nframes) {
  // El Sprite no está activo por defecto.
  active=false;
  frame=1;
  this.nframes=nframes;
  sprites=new Image[nframes+1];
 }


El constructor se encarga de crear tantos elementos de tipo Image como frames tenga el sprite. También asignamos el estado inicial del sprite.

La operación más importante de un sprite es el movimiento por la pantalla. Veamos los métodos que nos permitirán moverlo.

 public void setX(int x) {
  posx=x;
 }

 public void setY(int y) {
  posy=y;
 }

 int getX() {
  return posx;
 }

 int getY() {
  return posy;
 }


Como puedes observar, el código para posicionar el sprite en la pantalla no puede ser más simple. Los métodos setX() y setY() actualizan las variables de estado del sprite (posx,posy). Los métodos getX() y getY() realizan la operación contraria, es decir, nos devuelve la posición del sprite. Además de la posición del sprite, nos va a interesar en determinadas condiciones conocer el tamaño del mismo.

 int getW() {
  return sprites[nframes].getWidth();
 }

 int getH() {
  return sprites[nframes].getHeight();
 }
Los métodos getW() y getH() nos devuelven el ancho y el alto del sprite en píxeles. Para ello recurrimos a los métodos getWidth() y getHeigth() de la clase Image.

Otro dato importante del sprite es si está activo en un momento determinado.

 public void on() {
  active=true;
 }

 public void off() {
  active=false;
 }

 public boolean isActive() {
  return active;
 }

Necesitaremos un método que active el sprite, al que llamaremos on(), y otro para desactivarlo, que como podrás imaginar, llamaremos off(). Nos resta un método para conocer el estado del sprite. Hemos llamado al método isActive().

En lo referente al estado necesitamos algún método para el control de frames, o lo que es lo mismo, de la animación interna del sprite.

 public void selFrame(int frameno) {
  frame=frameno;
 }

 public int frames() {
  return nframes;
 }

 public void addFrame(int frameno, String path) {
  try {
   sprites[frameno]=Image.createImage(path);
  } catch (IOException e) {
   System.err.println("Can`t load the image " + path + ": " + e.toString());
  }
 }

El método selFrame() fija el frame actual del sprite, mientras que el método frame() nos devolverá el número de frames del sprite.

El método addFrame() nos permite añadir frames al sprite. Necesita dos parámetros. El parámetro frameno, indica el número de frame, mientras que el parámetro path indica el camino y el nombre del gráfico que conformará dicho frame.

Para dibujar el sprite, vamos a crear el método draw(). Lo único que hace este método es dibujar el frame actual del sprite en la pantalla.

public void draw(Graphics g) {
 g.drawImage (sprites[frame], posx, posy, Graphics.HCENTER|Graphics.VCENTER);
}

Nos resta dotar a nuestra librería con la capacidad de detectar colisiones entre sprites. La detección de colisiones entre sprites puede enfocarse desde varios puntos de vista. Imaginemos dos sprites, nuestro avión y un disparo enemigo. En cada vuelta del game loop tendremos que comprobar si el disparo ha colisionado con nuestro avión. Podríamos considerar que dos sprites colisionan cuando alguno de sus píxeles visibles (es decir, no transparentes) toca con un píxel cualquiera del otro sprite. Esto es cierto al 100%, sin embargo, la única forma de hacerlo es comprobando uno por uno los píxeles de ambos sprites. Evidentemente esto requiere un gran tiempo de computación, y es inviable en la práctica. En nuestra librería hemos asumido que la parte visible de nuestro sprite coincide más o menos con las dimensiones de la superficie que lo contiene. Si aceptamos esto, y teniendo en cuenta que una superficie tiene forma cuadrangular, la detección de una colisión entre dos sprites se simplifica bastante. Sólo hemos de detectar el caso en el que dos cuadrados se solapen.

  Control de sprites

En la primera figura no existe colisión, ya que no se solapan las superficies (las superficies están representadas por el cuadrado que rodea al gráfico). La segunda figura muestra el principal problema de este método, ya que nuestra librería considerará que ha habido colisión cuando realmente no ha sido así. A pesar de este pequeño inconveniente, este método de detección de colisiones es el más rápido. Es importante que la superficie tenga el tamaño justo para albergar el gráfico. Este es el aspecto que tiene nuestro método de detección de colisiones.


 boolean collide(Sprite sp) {
  int w1,h1,w2,h2,x1,y1,x2,y2;

  w1=getW();  // ancho del sprite1
  h1=getH();  // altura del sprite1
  w2=sp.getW(); // ancho del sprite2
  h2=sp.getH(); // alto del sprite2
  x1=getX();  // pos. X del sprite1
  y1=getY();  // pos. Y del sprite1
  x2=sp.getX(); // pos. X del sprite2
  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;
  }
 }

Se trata de comprobar si el cuadrado (superficie) que contiene el primer sprite, se solapa con el cuadrado que contiene al segundo.

Hay otros métodos más precisos que nos permiten detectar colisiones. Consiste en dividir el sprite en pequeñas superficies rectangulares tal y como muestra la próxima figura.

Control de sprites

 Se puede observar la mayor precisión de este método. El proceso de detección consiste en comprobar si hay colisión de alguno de los cuadros del primer sprite con alguno de los cuadrados del segundo utilizando la misma comprobación que hemos utilizado en el primer método para detectar si se solapan dos rectangulos. Se deja como ejercicio al lector la implementación de este método de detección de colisiones. A continuación se muestra el listado completo de nuestra librería.


import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;
import java.io.*;

class Sprite {

 private int posx,posy;
 private boolean active;
 private int frame,nframes;
 private Image[] sprites;

 // constructor. 'nframes' es el número de frames del Sprite.
 public Sprite(int nframes) {
  // El Sprite no está activo por defecto.
  active=false;
  frame=1;
  this.nframes=nframes;
  sprites=new Image[nframes+1];
 }


 public void setX(int x) {
  posx=x;
 }

 public void setY(int y) {
  posy=y;
 }

 int getX() {
  return posx;
 }

 int getY() {
  return posy;
 }

 int getW() {
  return sprites[nframes].getWidth();
 }

 int getH() {
  return sprites[nframes].getHeight();
 }

 public void on() {
  active=true;
 }

 public void off() {
  active=false;
 }

 public boolean isActive() {
  return active;
 }

 public void selFrame(int frameno) {
  frame=frameno;
 }

 public int frames() {
  return nframes;
 }

 // Carga un archivo tipo .PNG y lo añade al sprite en
 // el frame indicado por 'frameno'
 public void addFrame(int frameno, String path) {
  try {
   sprites[frameno]=Image.createImage(path);
  } catch (IOException e) {
   System.err.println("Can`t load the image " + path + ": " + e.toString());
  }
 }


 boolean collide(Sprite sp) {
  int w1,h1,w2,h2,x1,y1,x2,y2;

  w1=getW();  // ancho del sprite1
  h1=getH();  // altura del sprite1
  w2=sp.getW(); // ancho del sprite2
  h2=sp.getH(); // alto del sprite2
  x1=getX();  // pos. X del sprite1
  y1=getY();  // pos. Y del sprite1
  x2=sp.getX(); // pos. X del sprite2
  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;
  }
 }


 // Dibujamos el Sprite
 public void draw(Graphics g) {
  g.drawImage(sprites[frame],posx,posy,Graphics.HCENTER|Graphics.VCENTER);
 }

Veamos un ejemplo práctico de uso de nuestra librería. Crea un nuevo proyecto en KToolBar, y añade el programa siguiente en el directorio `src´, junto con la librería Sprite.java. Por supuesto necesitarás incluir el gráfico hero.png en el directorio `res´.

En los siguientes capítulos vamos a basarnos en esta librería para el control de los Sprites del juego que vamos a crear.

Control de sprites

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class SpriteTest extends MIDlet implements CommandListener {

 private Command exitCommand, playCommand, endCommand;
 private Display display;
 private SSCanvas screen;

 public SpriteTest() {
 display=Display.getDisplay(this);
 exitCommand = new Command("Salir",Command.SCREEN,2);

 screen=new SSCanvas();

 screen.addCommand(exitCommand);
 screen.setCommandListener(this);
 }

 public void startApp() throws MIDletStateChangeException {
 display.setCurrent(screen);
 }

 public void pauseApp() {}

 public void destroyApp(boolean unconditional) {}

 public void commandAction(Command c, Displayable s) {

 if (c == exitCommand) {
  destroyApp(false);
  notifyDestroyed();
 }
 }
}


class SSCanvas extends Canvas {

 private Sprite miSprite=new Sprite(1);

 public SSCanvas() {
 // Cargamos los sprites
 miSprite.addFrame(1,"/hero.png");

 // Iniciamos los Sprites
 miSprite.on();
 }


 public void paint(Graphics g) {

 //  Borrar pantalla
 g.setColor(255,255,255);
 g.fillRect(0,0,getWidth(),getHeight());

 // situar y dibujar sprite
 miSprite.setX(50);
 miSprite.setY(50);
 miSprite.draw(g);
 }
}

Capítulo siguiente - Un Universo en tu móvil
Capítulo anterior - Sprites
Recibe nuestras novedades
Al presionar "Recibir" estás dándote de alta y aceptas las condiciones legales de mailxmail

Hay 83 opiniones. Opina sobre este curso.


Cursos similares a Programación de juegos para móviles con J2ME


Cursos Valoración Alumnos Vídeo
Funciones en C (primera parte)
Curso de programacíon informática sobre Funciones en C en el orden de los fundamentos de la programación. Comprende el desarrollo de un software utilizando funciones y a ... [17/10/08]
 4,50/5 2.816  
Procesos en C. Sincronización (primera parte)
Curso de informática sobre sincronización de procesos en C y señales en linux que te ofrece la posibilidad de comprender los mecanismos de comunicación entre procesos inf... [21/10/08]
5/5 993  
Java
Java nació con el deseo por parte de Sun de buscar un lenguaje de programación enfocado a electrodomésticos. Se necesitaba alg&uacu... [23/04/04]
 4,45/5 49.291  


Publicar en   del.icio.us    digg    meneame

¿Qué es mailxmail.com?|ISSN: 1699-4914|Recomiéndanos|Ayuda
Condiciones legales de mailxmail