Curso - Programación de un Space Invaders en Java

  Página Anterior - Fotogramas Página Actual - 15 - Fotogramas - II   Página Siguiente - El Jugador
  Índice del curso  

Fotogramas - II

(c) Alexander Hristov

Si tenemos un ordenador suficientemente rápido, los fotogramas del programa anterior avanzan a una velocidad excesiva y apenas da tiempo a verlos como fotogramas diferenciados. Sin embargo, la frecuencia con la que se llama al método act() es algo que es general para todo el juego y no podemos variarlo para cada caso individual

La solución la tomamos prestada de la electrónica mediante lo que se llama una base de tiempos. El bucle principal duerme durante un tiempo que queda determinado por el máximo común divisor de los tiempos del resto de objetos. Por ejemplo imaginemos que estamos haciendo un videojuego en el cual los monstruos se actúan a la velocidad de una vez por segundo, mientras que el jugador actúa a una velocidad de 2 veces por segundo (o dicho de otra forma, queremos que tenga un "turno" para hacer cosas dos veces por segundo, o una vez cada medio segundo). Tenemos también un volcán que hace erupción cada 10 segundos. El máximo común divisor entre 1, 0.5 y 10 es 0.5. Este MCD recibe el nombre de unidad de tiempo o base de tiempos y es el tiempo que dormirá en general el bucle principal.

Dentro del bucle principal, cada vez que salgamos del Thread.sleep, se incrementa un contador secuencial que hace las veces de "instante del tiempo". Cuando este contador sea divisible por la cantidad apropiada, entonces es cuando se realiza la actualización del objeto en cuestión. Esta "cantidad apropiada" es el resultado de dividir el intervalo en segundos entres dos movimientos sucesivos del objeto por el MCD calculado anteriormente. Como en nuestro ejemplo la unidad de tiempo es de 0.5 segundos, el esquema sería:

El mismo criterio podemos aplicar a los fotogramas : Podemos mantener dentro de la clase Actor un contador de tiempos y actualizar el fotograma sólo cuando este contador sea divisible por una cantidad que llamaremos "velocidad de los fotogramas". Con este razonamiento, la clase "Actor" quedaría como sigue:


1     /**
2      * Curso Básico de desarrollo de Juegos en Java - Invaders
3      * 
4      * (c) 2004 Planetalia S.L. - Todos los derechos reservados. Prohibida su reproducción
5      * 
6      * http://www.planetalia.com
7      * 
8      */
9     package version15;
10    
11    import java.awt.Graphics2D;
12    import java.awt.image.BufferedImage;
13    
14    public class Actor {
15      protected int x,y;
16      protected int width, height;
17      protected String[] spriteNames;
18      protected int currentFrame;
19 protected int frameSpeed; 20 protected int t;
21 protected Stage stage; 22 protected SpriteCache spriteCache; 23 24 public Actor(Stage stage) { 25 this.stage = stage; 26 spriteCache = stage.getSpriteCache(); 27 currentFrame = 0; 28 frameSpeed = 1; 29 t=0; 30 } 31 32 public void paint(Graphics2D g){ 33 g.drawImage( spriteCache.getSprite(spriteNames[currentFrame]), x,y, stage ); 34 } 35 36 public int getX() { return x; } 37 public void setX(int i) { x = i; } 38 39 public int getY() { return y; } 40 public void setY(int i) { y = i; } 41 42 public int getFrameSpeed() {return frameSpeed; } 43 public void setFrameSpeed(int i) {frameSpeed = i; } 44 45 46 public void setSpriteNames(String[] names) { 47 spriteNames = names; 48 height = 0; 49 width = 0; 50 for (int i = 0; i < names.length; i++ ) { 51 BufferedImage image = spriteCache.getSprite(spriteNames[i]); 52 height = Math.max(height,image.getHeight()); 53 width = Math.max(width,image.getWidth()); 54 } 55 } 56 57 public int getHeight() { return height; } 58 public int getWidth() { return width; } 59 public void setHeight(int i) {height = i; } 60 public void setWidth(int i) { width = i; } 61 62 public void act() {
63 t++; 64 if (t % frameSpeed == 0){ 65 t=0; 66 currentFrame = (currentFrame + 1) % spriteNames.length; 67 }
68 } 69 } 70

Los descendientes de esta clase tendrían que preocuparse cada uno de establecer su propia velocidad de fotogramas. Por ejemplo la clase Monster quedaría así:


1     /**
2      * Curso Básico de desarrollo de Juegos en Java - Invaders
3      * 
4      * (c) 2004 Planetalia S.L. - Todos los derechos reservados. Prohibida su reproducción
5      * 
6      * http://www.planetalia.com
7      * 
8      */
9     package version15;
10    
11    public class Monster extends Actor {
12      protected int vx;
13      
14      public Monster(Stage stage) {
15        super(stage);
16        setSpriteNames( new String[] {"bicho0.gif","bicho1.gif"});
17 setFrameSpeed(35);
18 } 19 20 public void act() { 21 super.act(); 22 x+=vx; 23 if (x < 0 || x > Stage.WIDTH) 24 vx = -vx; 25 } 26 27 public int getVx() { return vx; } 28 public void setVx(int i) {vx = i; }} 29

Haber declarado la variable t como protegida permitirá a los descendientes utilizar la misma variable para hacer otros cálculos basados en la base de tiempos común (por ejemplo, determinar cuando hay que disparar, cuando debe "mutar" un monstruo, etc...



Lista de archivos Java del programa en este paso

Actor.java Invaders.java Monster.java SpriteCache.java
Stage.java      

Lista de recursos

bicho.gif bicho0.gif bicho1.gif bicho2.gif
bombD.gif bombDL.gif bombDR.gif bombL.gif
bombR.gif bombU.gif bombUL.gif bombUR.gif
disparo.gif disparo0.gif disparo1.gif disparo2.gif
explosion.wav misil.gif missile.wav musica.wav
nave.gif oceano.gif photon.wav Thumbs.db

  Página Anterior - Fotogramas Página Actual - 15 - Fotogramas - II   Página Siguiente - El Jugador
  Índice del curso  

(c) 2004 Planetalia S.L. Todos los derechos reservados. Prohibida su reproducción