Captulo 8 Juegos Recuerda los 80s? Haga un juego de pelota con muy pocas lneas Quizs algunos de ustedes aun no nacan, pero en los ochenta el juego de la pelotita nos volvi locos. De hecho cuentan que este fue el primer juego desarrollado para una computadora en los aos 60s. Mucho despus, uno de los primeros virus para PCs, de una pelotita en nuestras pantallas ASCII, tambin nos volva locos. En fin, ahora es fa- cilsimo hacer un juego similar con muy pocas lneas gracias a ActionScript. Para ello necesitamos conocer el comando onClipEvent, ya que con pequeas variaciones, este comando nos permitir hacer juegos de disparos, o de evasin de ob- jetos. Empecemos con un simple movimiento horizontal. Para ello cree una pelotita pe- quea. Seleccinela con el cursor y pulse F8, para hacer un smbolo nuevo. Llmelo Pelotita (o como usted desee). Sin dejar de seleccionarla, pulse CTRL+I, y nombre la instancia como pelota. Este es un punto crtico. Tenemos dos opciones: 1) cargar de cdigo los objetos o 2) poner todo el cdigo en unos cuantos objetos. Despus de tres o cuatro objetos, cinco escenas y varias capas con cdigo, casi cualquiera se vuelve loco (a excepcin de los que ya lo estn). Yo prefiero crear un objeto en el escenario y ah car- garlo con todo el cdigo para controlar a los dems objetos. As que escriba las letras Scripts en el escenario, y hgalos un clip de pelcula (MovieClips, MC). Ah estar el siguiente cdigo: 292 Programacin en Flash MX 2004 Figura 8-1 onClipEvent(load){ _root.attachMovie(Pelotita,pelota,1); _root[pelota]._x = 100; _root[pelota]._y = 100; dx = 5; dy = 0; } onClipEvent(enterFrame){ _root.pelota._x += dx; _root.pelota._y += dy; } Expliquemos: con tan poco cdigo, usted hace que la pelotita se mueva de izquierda a derecha. La funcin onClipEven(enterFrame) es evaluada dependiendo de la veloci- dad de su pelcula, es decir, si tiene una velocidad de 12 cuadros por segundo, la fun- cin es evaluada 12 veces cada segundo. Esto lo que hace es que la pelotita se mueve en forma horizontal hasta desaparecer de la pantalla. Esto es bastante bonito (se ima- gina hacerlo en C?), pero poco til. Si usted ama la aventura y el riesgo, modifique la variable dy a 5 y dx a cero. Exacto!, el movimiento ahora es vertical! Hagamos que la pelotita bote de izquierda a derecha y viceversa. Slo necesitamos dos sentencias if y multiplicar la variable de direccin (dx) por menos uno, es decir, en lugar de sumar, restaremos 5 a la posicin. (Nota: de preferencia meta las coordena- das mxima y mnima en variables). Juegos 293 onClipEvent(load){ _root.attachMovie(Pelotita,pelota,1); _root[pelota]._x = 100; _root[pelota]._y = 100; dx = 5; dy = 0; } onClipEvent(enterFrame){ if(_root.pelota._x>400) dx *= -1; if(_root.pelota._x<100) dx *= -1; _root.pelota._x += dx; _root.pelota._y += dy; } onClipEvent(load){ _root.attachMovie(Pelotita,pelota,1); _root[pelota]._x = 100; _root[pelota]._y = 100; dx = 5; dy = 0; } onClipEvent(enterFrame){ if(_root.pelota._x>300) dx *= -1; if(_root.pelota._x<100) dx *= -1; if(_root.pelota._y>50) dy *= -1; if(_root.pelota._y<300) dy *= -1; _root.pelota._x += dx; _root.pelota._y += dy; } Ahora cambie la relacin de variables (incremente y y deje en cero las x) y obten- dr un movimiento vertical. Incluya tambin las otras condiciones, para tener una fun- cin parecida a la siguiente: Ya estamos listos para el pingponeo, pero necesitamos los movimientos diagonales: co- mo usted debe sospechar, slo es necesario que ambas variables de direccin tengan va- lor, por ejemplo el nmero cinco, y listo, tenemos una pelota que rebota en la pantalla, pero para tener un juego de ping pong hacen falta dos cosas: 1. Una raqueta que se mueva de alguna manera y que golpee de alguna manera a la pelotita, y 2. Detectar cuando la pelota se pasa y NO es golpeada por la raqueta. 294 Programacin en Flash MX 2004 Figura 8-2 NOTA: Tambin se puede hacer un marcador, ponerle sonido y decorarlo segn sus capacidades artsticas (las mas son muy pocas). 1. Una raqueta: Haga un rectngulo delgado (no muy largo, ni muy ancho). Ubi- que la raqueta en la posicin 100, 100 dentro del escenario y nombre la instan- cia como raqueta. Lo siguiente es incluir una instruccin en nuestra rutina motor: _root.raqueta._y = _ymouse; Con esto hacemos que la raqueta su- ba y baje con el movimiento del ratn, pero aun no golpea a la pelota. 2. Golpeando a la pelotita: Ya tenemos los dos movimientos. Podramos utilizar a nuestra querida funcin hitTest. Como puede observar, la pelota tiene un comportamiento un tanto extrao, ya que la funcin hitTest evala los centros de los objetos. Puede haber muchas maneras de hacerlo, una es mover el dibujo de los clips de pelcula de la raqueta y de la pelota a la derecha e izquierda de sus centros, pero los movimientos se ven poco naturales. Otra forma es mejor evaluar los anchos de los objetos y ajustar el golpe. Esta solucin es un poco ms compleja: Necesitamos dos variables de trabajo, algo as como x e y para almacenar la coor- denada de la bolita, y otras dos variables para los medios anchos: Juegos 295 if (_root.raqueta.hitTest(_root.pelota._x, _root.pelota._y)){ dy *= -1; } anchoPelota = (_root.pelota._width/2); anchoRaqueta = (_root.raqueta._width/2) x = _root.pelota._x; y = _root.pelota._y; Ya sabemos las fronteras de ambos objetos. Ya no necesitamos a nuestra vieja amiga hitTest, aunque aumentamos un poco la complejidad. Ahora sabemos que la lnea del centro de la raqueta, ms la mitad de la raqueta, ms la mitad de la pelotita, es la dis- tancia en la que tiene que rebotar la pelota, es decir: if (_root.pelota._x<=100+anchoPelota+anchoRaqueta){ dx *= -1; } AnchoRaqueta=10/2=5 AnchoPelota=10/2=5 CentroRaqueta = 100 CentroPelota = 110 Rebota si: CentroRaqueta+AnchoPaleta+AnchoRaqueta 100 110 Figura 8-3 296 Programacin en Flash MX 2004 Listo, ya tenemos un juegito de pelota, aunque sencillo, nos servir para desarrollar cosas ms interesantes usted puede llevarlo hasta donde guste. NOTA: Las coordenadas deben de ir en variables y no en hardcode StarGate, un juego de disparos y naves espaciales Este es un juego clsico de los aos ochenta. Se tiene una nave que aparenta avanzar en la pantalla mientras que pequeas naves enemigas la atacan. Obviamente este es un ejemplo simplificado, pero se puede hacer tan complejo como se guste. En este tutorial explicaremos primero el escenario del juego, despus cada uno de los smbolos y objetos grficos, y por ltimo las funciones. Ah detallaremos a las na- ves, al disparo de la nave y al escenario que se repite dando la sensacin de continui- dad (scroll). El escenario El escenario en s mismo es bastante sencillo: tenemos tres capas: La primera para el cdigo, la segunda para los sonidos y la tercera para los clips de pelcula como las na- ves, el paisaje y el tiro. Asimismo, se tienen tres fotogramas en la lnea de tiempo: El primero para las instrucciones (el cual no explicaremos). El segundo es el del juego. El tercero es para sealar el fin del juego. Como en otros tutoriales, la idea es mostrar el cascarn del juego, y sobre l se pueden detallar y aumentar las funciones. Los smbolos y objetos grficos Este juego cuenta con pocos smbolos: Juegos 297 Figura 8-4 Descripcin Tipo Nombre Instancia Nave Amiga MC Amiga Naves Enemigas MC Enemiga Tiro de la nave Amiga MC Tiro Tiro Codigo ActionScripts MC ActionScripts Paisaje de fondo MC Paisaje Sonido inicio disparo Sonido Disparo SonidoTiro En realidad todos los clips de pelcula son bastante sencillos y no vale la pena detener- nos en ellos. Si llega a cambiarlos, tome en cuenta copiar el cdigo dentro de ellos a sus nuevas creaciones. Los sonidos tambin son estndar, a excepcin del loop que lo ba- j de una de las pantallas de recursos (www.flashkit.com). Pasemos mejor a ver a deta- lle el cdigo de cada objeto. ActionScript 298 Programacin en Flash MX 2004 Loop de fondo Sonido Loop Explota nave Amiga Sonido Explota Amiga Explota nave Enemiga Sonido Explota Enemiga NOTA: Por regla general, es mejor tener todo el cdigo en la lnea de tiem- po principal, y sta dentro de una capa llamada actionScript. Sin embargo, cuando se hacen juegos en lnea, donde hay que verificar muchos objetos, es mejor tener el cdigo en cada uno de ellos. Al menos as me paso con el cdigo del tiro, ya que si lo desplazaba con las dems rutinas, el juego empezaba a perder velocidad. Usted puede hacer la prueba moviendo el cdigo de lugar y viendo si no afecta en la velocidad del juego. Aunque la mayora de las rutinas estn ubicadas en la lnea de tiempo principal (_root) analizaremos cada una de ellas, dependiendo del objeto al que estn relacionadas. As, primero explicaremos la estructura del MC y luego a la rutina en _root. Variables globales y constantes Las variables globales son realmente pocas: necesitamos dos arreglos para el estado de cada nave y su velocidad, ya que cambia de forma aleatoria, como ms adelante se ob- servar. Esta informacin podra almacenarse dentro del mismo objeto. La variable naveNueva es en realidad un reloj que nos indica con qu pausa de tiempo las naves son creadas. La funcin getTimer() es en realidad un cronmetro en milsimas de segundo. Si le sumamos 1000, pues le estamos diciendo a Flash que espere un segundo para el lanzamiento de la siguiente nave. Como ms adelante se ver, po- demos variar el tiempo de forma aleatoria para que el juego no sea tan montono. Las variables inicioNaves indican el punto de las xs (fuera de la pantalla) de don- de nacen las naves enemigas. La variable Velocidad Mxima es el tope de pixeles que puede avanzar una nave, lo cual determina su velocidad. La variable maximoNaves es el nmero mximo de naves enemigas que pueden ser creadas de forma simultnea. Si gusta hacer un juego ms complicado (es muy recomendable), aumentando ni- veles con mayor dificultad, slo tendra que cambiar algunas de estas variables (entre otras cosas, como el paisaje). Juegos 299 /*********************************************************************** Variables globales y constantes ***********************************************************************/ maximoNaves = 20; inicioNaves = 660; largoPantalla = 400; naveNueva = getTimer() + 1000; velocidadMaxima = 20; velocidad = new Array(maximoNaves); estado = new Array(maximoNaves); /*********************************************************************** Crea las naves enemigas Con este ciclo creamos fuera de la pantalla, y a alturas aleatorias, a odiadas naves enemigas. Como puede observar, las naves se crean slo una vez, y jugaremos con la variable estado[i] para reciclarlas. /*********************************************************************** Crea las naves enemigas ***********************************************************************/ for(i=0;i<maximoNaves;i++){ attachMovie(enemiga,enemiga+i,100+i); mc = _root[enemiga+i]; mc._x = inicioNaves; mc._y = random(largoPantalla); velocidad[i] = 0; estado[i] = 0; } Nave Amiga La estructura bsica del cdigo dentro de esta nave es: Como puede observar, la rutina onClipEvent(keyDown) verifica si las flechas Arriba y Abajo fueron pulsadas. En su caso suben o bajan la nave 5 pixeles. La siguiente ru- tina, con la opcin enterFrame, por cada fotograma que Flash recorra, verificar esta rutina. Su intencin es cerciorarse que ninguna nave enemiga ha colisionado con la na- ve amiga. 300 Programacin en Flash MX 2004 /*********************************************************************** Verifica el teclado para subir y bajar la nave AMIGA ***********************************************************************/ onClipEvent(keyDown){ if(Key.getCode()==Key.UP) _y -=5; if(Key.getCode()==Key.DOWN) _y +=5; } /*********************************************************************** Verifica si la nave AMIGA no ha chocado con alguna nave ENEMIGA ***********************************************************************/ onClipEvent(enterFrame){ _root.colisionEnemigas(this._x, this._y); } /*********************************************************************** FIN DEL CODIGO EN EL MC NAVE-AMIGA ***********************************************************************/ /*********************************************************************** Verifica Colisin con naves Enemigas ***********************************************************************/ function colisionEnemigas(x1, y1){ for(i=0;i<_root.maximoNaves;i++){ if(_root.estado[i] == 1){ mc = _root[enemiga+i]; x2 = mc._x; y2 = mc._y; if(Math.abs(x1-x2)<15 and Math.abs(y1-y2)<10){ _root.gotoAndStop(3); } } } } /*********************************************************************** Esta rutina est formada por un ciclo que barre a todas las naves enemigas y efecta el clculo de aquellas que estn activas, o con estado igual a uno. Para saber si hubo o no una colisin de nuestra nave contra las del enemigo, verificamos las distancias entre ambas, y si esta distancia es pequea (en pixeles), determinamos que hubo un choque y que nuestra nave fue destruida (y mandamos el control a la pantalla de fin de juego). Nave enemiga Esta nave en realidad no tiene cdigo. El cdigo que la maneja est en el MC que se llama ActionScipts, el cual se encuentra fuera de la pantalla, pero que es evaluado por cada cuadro que se despliega (doce veces cada segundo). Para controlar las naves nece- sitamos dos funciones: Lanza las naves al escenario y la funcin que las hace avanzar. Juegos 301 /*********************************************************************** Lanza a las naves ENEMIGAS y las mueve a lo largo del escenario ***********************************************************************/ onClipEvent(enterFrame){ if(getTimer()>_root.naveNueva){ _root.lanzaNaveNueva(); } _root.avanzaNaves(); } /*********************************************************************** /*********************************************************************** Lanza Nave Nueva ***********************************************************************/ function lanzaNaveNueva(){ indice = -1; for(i=0;i<_root.maximoNaves;i++){ if(_root.estado[i] == 0){ indice=i; break; } } if(indice>-1){ _root.velocidad[indice] = random(velocidadMaxima); _root.estado[indice] = 1; } naveNueva = getTimer() + 1000*random(3); } Lanza las naves enemigas Se verifica cul de las naves no est ya en el escenario por medio de la variable estado. Una vez encontrada la nave disponible, se le calcula aleatoriamente una velocidad y una altura, y se cambia su estado para que la siguiente funcin la mueva. Se calcula el tiempo que saldr la siguiente nave (puede variar el nmero aleatorio a su gusto). La siguiente funcin sirve para mover cada una de las naves: 302 Programacin en Flash MX 2004 /*********************************************************************** Avanza Naves ***********************************************************************/ function avanzaNaves(){ for(i=0;i<_root.maximoNaves;i++){ if(_root.estado[i] == 1){ signo = 1; if(random(10)<4) signo = -1; mc = _root[enemiga+i]; mc._x-=_root.velocidad[i]; mc._y -=signo*random(3); if(mc._x<0){ _root.estado[i] = 0; _root.velocidad[i] = random(velocidadMaxima); mc._x = inicioNaves; mc._y = random(largoPantalla); } } } } /*********************************************************************** Nuevamente recorremos todas las naves con estado igual a uno. Como puede ver hay varias funciones aleatorias (random), para darle variedad al juego. Por ejemplo, tene- mos una variable vertical que cambiamos segn el signo, lo que hace que la nave enemi- ga zigzaguee arriba y abajo. Si la ubicacin de la nave es menor a cero, quiere decir que ya sali de la pantalla, por lo que el estado regresa a cero, se calcula aleatoriamente la velocidad y la altura de la nave en la pantalla, y regresa a la posicin inicial. El disparo Este es un punto muy importante, pues tiene cdigo esencial en el juego. Como se men- cion anteriormente, se tuvo que colocar directamente el cdigo dentro del objeto para que el sistema no se fremeara, es decir, se detuviera y avanzara irregularmente. Tiene tres rutinas: 1) Iniciar la variable y hacer el MC invisible, 2) para detectar la barra espaciadora, y 3) Para avanzar el disparo o tiro, y determinar si colisiona con al- guna nave enemiga. La variable tirito indica si el tiro es disparado o no. Juegos 303 /*********************************************************************** Oculta el MC del tiro hasta que el jugador pulse SPACE ***********************************************************************/ onClipEvent(load){ this._visible = false; tirito = false; } /*********************************************************************** /*********************************************************************** Verifica el teclado para interceptar la tecla SPACE y lanzar el tiro de la nave AMIGA ***********************************************************************/ onClipEvent(keyDown){ if(Key.getCode()==Key.SPACE){ this._visible = true; y = _root.amiga._y; tirito = true; sonido = new Sound(); sonido.attachSound(SonidoTiro); sonido.start(); } } /*********************************************************************** En esta rutina se leen las teclas y se verifica si pulsaron la Barra Espaciadora. Hace visible el propio MC en la altura de la Nave Amiga. Tambin se activa un sonido de disparo. /*********************************************************************** Verifica si el tiro de la nave AMIGA colisiona con las naves ENEMIGAS Si el tiro sale de la pantalla lo ubica nuevamente junto a la nave AMIGA Nota: por cuestin del tiempo de ejecucin, este cdigo se dej dentro del MC ***********************************************************************/ onClipEvent(enterFrame){ if(tirito){ this._x += 20; for(i=0;i<_root.maximoNaves;i++){ if(_root.estado[i] == 1){ mc = _root[enemiga+i]; x1 = this._x; Aqu nuevamente barremos a todas las naves y verificamos el tiro de la nave amiga con- tra las enemigas. Si el tiro sale de la pantalla (la X es mayor a 600). Hacemos invisible el MC y lo colocamos en un punto determinado. La variable tirito vuelve a falso. El paisaje Finalmente nos falta el paisaje que se mueve a lo largo de la batalla. Este es un truco bastante sencillo. Digmoslo en forma de receta de cocina: 1. Haga un dibujo que abarque a lo largo el escenario. (Algo as como montaas). 2. Duplique el dibujo, saliendo del escenario. 3. Convirtalo en un MC. 4. Incluya el siguiente cdigo en el clip de pelcula. 304 Programacin en Flash MX 2004 y1 = this._y; x2 = mc._x; y2 = mc._y; if(Math.abs(x1-x2)<15 and Math.abs(y1-y2)<10){ mc._x = 660; mc._y = random(240); _root.estado[i] = 0; _root.velocidad[i] = random(15); mc.gotoAndPlay(2); } } } if(this._x>600){ this._visible = false; tirito = false; _x=144; _y=129; } } } /*********************************************************************** /*********************************************************************** Delimita el ancho del paisaje del SCROLL ***********************************************************************/ onClipEvent(load){ _x = 550; } Al cargarlo, lo ubicamos en un punto inicial. Con la segunda funcin hacemos que el paisaje avance (o retroceda). Cuando el clip de pelcula en su variable x llegue a ce- ro, regresa el paisaje al punto original. Flash efecta este cambio tan rpido que es im- perceptible al ojo humano (si est bien hecho). Juegos 305 Figura 8-5 /*********************************************************************** Mueve el paisaje y lo reinicia de ser necesario ***********************************************************************/ onClipEvent(enterFrame){ this._x-=10; if(this._x<0) this._x = 550; } /*********************************************************************** Mas all del juego Este es un buen ejercicio para mejorar este cascarn. Puede aadirle un marca- dor, o ponerle diferentes valores a las naves enemigas (quizs dependiendo de la velo- cidad). Se pueden hacer diferentes niveles, cambiando el paisaje, o creando diferentes tipos de naves enemigas, inclusive pueden disparar. La nave amiga puede avanzar y retroceder , o incluso cambiar de direccin. 306 Programacin en Flash MX 2004