Para comenzar definiremos las siguientes constantes
height = 300 width = 300 (Definición del espacio del frame) Diameter = 24 (Diámetro del asteroide) chance = 0.1 :: Double (Probabilidad de aparecer un asteroide)
32 Creación de la base del juego asteroids :: IO () asteroids = do g <- getStdGen vrocks <- variable [value := randomRocks g] vship <- variable [value := div width 2]
f <- frame [resizeable := False] t <- timer f [interval := 50, on command := advance vrocks f ]
set f [text := "Asteroids", bgcolor := white, layout := space width height, on paint := draw vrocks vship, on leftKey := set vship [value :» nx!x¡5], on rightKey := set vship [value :» nx!x+5]] Definimos la variable asteroids como IO() Creamos una variable para generar números aleatorios Vrock es una lista de las futuras posiciones de los asteroides Vship contiene la posición del eje X de la nave F la ventana T es un temporizador para actualizar eventos Establecemos los atributos de la variable 'f', color de fondo, tamaño, función de dibujado, y asignar funciones a las pulsaciones de teclas
33 Creación de la base del juego En lugar de la asignación usual de haskell := hemos usado :~ Esto no realiza una asignación a la variable, sino que le aplica una función.
En el caso de on LeftKey, podríamos usar: on leftKey := set vship [value :~ x->max 0 (x-5)]
Lo que nos permitiría implementar los bordes de la ventana (frame). Para el caso de on Rightkey, análogamente sería: on rightKey := set vship [value :~ x->min width (x+5)]
34 Función de generado y avancede los Asteroides randomRocks :: RandomGen g => g ? [[Point ]] randomRocks g = flatten [ ] (map fresh (randoms g)) flatten rocks (t : ts) = let now = map head rocks later = filter (not o null) (map tail rocks) in now : flatten (t++later) ts fresh r | r>chance = [ ] | otherwise = [track (floor (fromIntegral width*r = chance))] track x = [point x (y – diameter) | y ? [0,6… height +2 *diameter]] Tenemos un generador de números aleatorios, que con él generamos asteroides aleatoriamente. Cuando generamos un asteroide, lo metemos en una lista, siendo un asteroide una lista de posiciones dentro de la ventana, que va desde arriba, hasta abajo.
35 Función de generado y avancede los Asteroides advance vrocks f = do set vrocks [value :~ tail] repaint f
draw vrocks vship dc view = do rocks ? get vrocks value x ? get vship value let ship = point x (height – 2*diameter) positions = head rocks collisions = map (collide ship) positions drawShip dc ship mapM (drawRock dc) (zip positions collisions) when (or collisions) (play explode) La función advance coge el estado actual de la situación de los asteroides y la representa en pantalla. La función draw especifica lo que hacer en la ventana. Ésta llama a drawShip y drawRock. Es llamada cada 50ms. dc indica el contexto donde dibujar, puede ser un mapa de bits o una impresora, pero en este caso, es la ventana. Collide es la función que comprueba que un asteroide choca con la nave
36 Función de dibujado de primitivas La nave puede ser representada como una primitiva, al igual que los asteroides:
drawShip dc pos = circle dc pos (div diameter 2) [brush := brushSolid red]
drawRock dc (pos; collides) = |collides == true = circle dc pos (div diameter 2) [brush := brushSolid black] |collides == false = circle dc pos (div diameter 2) [brush := brushSolid yellow]
37 Función de dibujado de mapa de bits
La nave puede ser representada con un mapa de bits, al igual que los asteroides:
drawShip dc pos = drawBitmap dc ship pos True [ ] drawRock dc (pos; collides) = let picture = if collides then burning else rock in drawBitmap dc picture pos True [ ]
collide pos0 pos1 = let distance = vecLength (vecBetween pos0 pos1) in distance = fromIntegral diameter
rock = bitmap "rock.ico" burning = bitmap "burning.ico" ship = bitmap "ship.ico" explode = sound "explode.wav"
38 Generación de la barra de menú
Con el símbolo '&' indicamos que la letra J del teclado, tendrá asociada la función de expandir el menú Juego El campo help, indica qué texto poner en la barra de ayuda de la ventana
game ? menuPane [text := "&Juego"] new ? menuItem game [text := "&NuevotCtrl+N" , help := "Empezar nuevo juego"] pause ? menuItem game [text := "&PausatCtrl+P" , help := "Pausar el juego" ,checkable := True] menuLine game quit ? menuQuit game [help := "Salir del juego"]
set new [on command := asteroids] set pause [on command := set t [enabled :~ not]] set quit [on command := close f ]
La opción 'checkable' añade una marca de selección.
Con el comando 'on command', añadimos una funcionalidad a cada botón. 'new' crea una nueva ventana de juego Para pausar el juego, tan solo hay que desactivar el temporizador Por último close f, cierra la ventana
39 Juego finalizado
Página anterior | Volver al principio del trabajo | Página siguiente |