31
Primeros pasos
En esta minimalística versión no trataremos de crear un clon exacto de Asteroids, simplemente intentaremos haceros conocer las virtudes de wxHaskell.
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 |