jueves, 18 de octubre de 2012

UCBLogo: videojuego del coche



En este videojuego el coche se sitúa siempre en el medio de la pantalla y se simula el movimiento haciendo que todos los demás elementos estén en permanente movimiento respecto del mismo en función de la dirección en la que se mueva el coche.



Comentarios:

1.- para que simule movimiento generaremos unas 20 piedras (letras “o”), una recarga de Fuel (F) y un objeto para acumular puntos ($). Nuestro coche gira pero permanece siempre en el medio de la pantalla, por lo que todos los demás elementos deben moverse. Para eso haremos uso de relaciones trigonométricas.

2.- Orientación del coche: observemos el siguiente diagrama:



O es el centro de la pantalla y donde estará siempre nuestro coche. El coche debe estar orientado hacia la posición del ratón que está indicada por R. En realidad no tenemos más que calcular el ángulo a y ya sabemos la orientación del coche. Por trigonometría a es el arco cuya tangente es rx/ry:

a = arc tan (rx/ry)

Usaremos un comando muy útil: setheading que nos permite orientar la tortuga en función de un ángulo (que en nuestro caso será el valor de a).

En código:

make "rx first mousepos
make "ry last mousepos
if [ry=0][make "ry 1]  ;evitamos la singularidad de division por 0
make "tangente rx/ry
make "angulo arctan tangente
if [ry<0][make "angulo angulo+180] ;ajustando orientacion en caso ry negativo
setheading angulo ;orienta la tortuga según a

En realidad UCBLogo trae un procedimiento para conocer este ángulo a: el comando heading, que devuelve el valor del ángulo en grados al que “mira” la tortuga, así que en el código se hará uso de a o de heading. Importante: el ángulo heading es el complementario de a en el primer cuadrante, pues como la tortuga inicialmente mira hacia arriba, se toma como cero la vertical y aumenta en el sentido de las agujas del reloj y no a la inversa.

3.- Usando un vector para guardar las coordenadas de todos los “pedruscos”: en el juego se generan 18 pedruscos. Podríamos ir uno a uno creando variables para guardar el valor de sus coordenadas, pero este proceso sería muy laborioso y, como todos son equivalentes y se comportan igual, lo haremos usando un vector (comando array) para guardas las coordenadas. Un vector no es más que un conjunto ordenado de números, de tal forma que un vector de 40 elementos nos permite guardar las coordenadas de 20 objetos en 2 dimensiones, de tal manera que los 2 primeros elementos serán las coordenadas x e y del primer pedrusco, los 2 siguientes las coordenadas x e y del segundo y así sucesivamente. De esta forma, los elementos impares contendrán las coordenadas en x y las pares las coordenadas en y. El siguiente código inicia el vector:

make "vector array 40 ;definimos un vector llamado vector de 40 elementos
make "longitud count vector ;define variable longitud igual al nº de elementos                  
                                              ; que contiene vector
make "longmedio (longitud/2)-2
for [i 1 longitud][setitem i vector ((random 1000)-500)] ;asignamos valores

La lectura dentro del juego del valor de las coordenadas para cada pedrusco se hace así:

for [i 0 longmedio][make "yo (item (2*i+1) vector) make "tu (item (2*i+2) vector) setxy yo tu label "o]

usando (2*i+1) para la lectura de las coordenadas en x (los impares) y (2*i+2) para la lectura de las coordenadas en y (los pares) y usando el comando item que es el encargado de extraer precisamente el valor correspondiente del vector. Los resultados se guardan en unas variables temporales que llamé yo y tu.

4.- Generación del movimiento: todos los objetos de la pantalla se moverán salvo el coche, para simular que este último es el que se mueve. Si miramos al diagrama, podemos ver que (usando la trigonometría) el coche avanzaría en proporción a cos(a) en el eje x y a sen(a) en el eje y o bien a sen(heading) y a cos(heading) respectivamente. Que avance el coche viene a ser lo mismo que lo demás retroceda, y esto es lo que programamos. Programado y como ejemplo para las coordenadas del fuel, estas se actualizan así:

make "fx fx-4*sin(heading)
make "fy fy-4*cos(heading)

siendo 4 un valor arbitrario para la velocidad.

Código del juego

;
; juego del coche
; Raultecnologia
; ejemplo de aplicacion de programacion en LOGO con el programa UCBLogo
;

clearscreen
hideturtle

to rectangulo
setpencolor 4
penup
fd 10
pendown
rt 90
fd 5
setpencolor 7
rt 90
fd 20
rt 90
fd 10
rt 90
fd 20
rt 90
setpencolor 4
fd 5
penup
rt 90
fd 10
rt 180
setpencolor 7
end

to borrarectangulo
setpencolor 0
penup
fd 10
pendown
rt 90
fd 5
rt 90
fd 20
rt 90
fd 10
rt 90
fd 20
rt 90
fd 5
penup
rt 90
fd 10
rt 180
end



to tele
penup
setxy 0 0
setheading angulo

borrarectangulo
make "rx first mousepos
make "ry last mousepos
if [ry=0][make "ry 1]
make "tangente rx/ry

make "angulo arctan tangente
if [ry<0][make "angulo angulo+180]

setheading angulo
for [i 0 perdertiempo] [setxy 0 0 rectangulo]

penup
setpencolor 0
for [i 0 longmedio][make "yo (item (2*i+1) vector) make "tu (item (2*i+2) vector) setxy yo tu label "o]
setpencolor 4
for [i 0 longmedio][make "yo (item (2*i+1) vector) setitem (2*i+1) vector yo-4*sin(heading)]
for [i 0 longmedio][make "tu (item (2*i+2) vector) setitem (2*i+2) vector tu-4*cos(heading)]
for [i 0 longmedio][make "yo (item (2*i+1) vector) make "tu (item (2*i+2) vector) setxy yo tu label "o ~
  make "dd yo*yo+tu*tu if [dd<100][colision]]

penup
setxy 200 200
setpencolor 2
label "FUEL
setxy 260 200
setpencolor 0
label fuel
make "fuel fuel-1
setxy 260 200
setpencolor 2
label fuel

setxy 200 180
label "PUNTOS
setxy 260 180
label puntos

setpencolor 0
setxy fx fy
label "F
setpencolor 6
make "fx fx-4*sin(heading)
make "fy fy-4*cos(heading)
setxy fx fy
label "F
make "ff fx*fx+fy*fy
if [ff<100][cojofuel]
if [fuel<=0] [sinfuel]

setpencolor 0
setxy pux puy
label "$
setpencolor 5
make "pux pux-4*sin(heading)
make "puy puy-4*cos(heading)
setxy pux puy
label "$
make "pp pux*pux+puy*puy
if [pp<100][cojopuntos]

make "origenx origenx-4*sin(heading)
make "origeny origeny-4*cos(heading)


tele
end


to inicio
clearscreen
setpensize 1
penup
setxy -200 140
setpencolor 4
label "|Videojuego TranzXix|
setxy -200 110
setpencolor 7
label "|Maneja al coche con el ratón|
setxy -200 80
setpencolor 6
label "|Evita que se te agote el FUEL -- F|
setxy -200 50
setpencolor 5
label "|Haz el mayor número de puntos -- $|
setxy -200 -20
label "|Pulsa cualquier tecla para empezar|
wait 120
make "tecla rc
clearscreen
setpencolor 7
make "angulo 0
make "vector array 40
make "longitud count vector
make "longmedio (longitud/2)-2
for [i 1 longitud][setitem i vector ((random 1000)-500)]
make "perdertiempo 50
make "fuel 1500
make "puntos 0
make "fx (random 1000)-500
make "fy (random 1000)-500
make "pux (random 1000)-500
make "puy (random 1000)-500
make "origenx 0
make "origeny 0
penup
setpencolor 2
setxy 200 200
label "FUEL
setxy 200 180
label "PUNTOS
setpencolor 6
setxy fx fy
label "F
setxy pux puy
setpencolor 5
label "$
window
tele
end

to cojofuel
make "fuel fuel+100
penup
setxy fx fy
setpencolor 0
label "F
make "fx (random 1000)-500+origenx
make "fy (random 1000)-500+origeny
penup
setpencolor 6
setxy fx fy
label "F
end

to cojopuntos
make "puntos puntos+10
penup
setxy pux puy
setpencolor 0
label "$
make "pux (random 1000)-500+origenx
make "puy (random 1000)-500+origeny
penup
setpencolor 5
setxy pux puy
label "$
end

to sinfuel
setpencolor 3
penup
setxy -40 15
label "|!!SIN FUEL!!|
setxy -100 -100
label "|pulsa cualquier tecla para empezar|
wait 120
make "tecla rc
inicio
end

to colision
penup
setxy 0 0
borrarectangulo
pendown

setpencolor 1
arc 360 8
arc 360 16
setpencolor 3
arc 360 32
setpencolor 7
setpencolor 4
penup
setxy -40 -5
label "!!!CRASH!!!
setxy -100 -100
label "|pulsa cualquier tecla para empezar|
wait 120
make "tecla rc
inicio
end

UCBLogo: videojuego del muro



El videojuego del muro (o Arkanoid) es un videojuego clásico en el que aparece un muro hecho con ladrillos que debemos derribar usando una bola a la que golpeamos con una raqueta (o una nave).



Consideraciones sobre el juego:

1.- vamos a manejar la raqueta con el ratón. Para ello la raqueta se moverá de izquierda a derecha siguiendo el ratón y hacemos que no pueda sobrepasar las paredes del terreno de juego:

make "rx first mousepos   ;variable rx vale la posicion en x del raton
if [rx < -176] [make "rx -176]
if [rx > 275] [make "rx 275]
penup
setxy rx ry  ;ry es una constante
nave ;el procedimiento nave dibuja la raqueta

2.- para saber qué ladrillos quedan usaremos de nuevo una tabla (10 columnas y 4 filas) en la que guardaremos con el valor de 1 si hay ladrillo y con el valor de 0 si no lo hay. Además, de vez en cuando habrá que repintar los ladrillos.  Para ello:

to dibujaladrillos
for [i 1 10 1] [for [j 1 4 1] [make "dentro mditem (list :i :j) :tabla ~
 if [dentro = 1] [penup setxy i*41-200 j*21+50 ladrillo]]]
end

3.- Programando si hay o no hay colisión: de nuevo (como en casos anteriores en que manejamos tablas para los cálculos del programa) vamos a manejar dos sistemas de coordenadas (bolax y bolay para las coordenadas de la bola en la parte gráfica y varx y vary para las coordenadas en la tabla):

make "varx int((bolax+200)/41)  ;int devuelve la parte entera
make "vary int((bolay-50)/21)

definiremos también una variable llamada posible, que conceptualmente vale para mirar si hay posibilidad (posible valdrá 1) o no (vale 0) de que haya colisión con los ladrillos (está claro que si la bola está alejada del muro no puede chocar con los ladrillos, sólo miraremos si está cerca o no del muro).

if [varx <= 10][if [varx>=1][if [vary<=4][if [vary>=1][make "posible 1]]]]

Si está en una posición en la que hay muro, la bola chocará si hay ladrillo, si no, no lo hace.

if [posible=1] [make "dentro mditem (list :varx :vary) :tabla ~
 if [dentro = 1] [make "vely -vely penup setxy varx*41-200 vary*21+50 borraladrillo ~
mdsetitem (list :varx :vary) :tabla 0 dibujaladrillos make "aciertos aciertos+1]]


Código del juego

;
; Videojuego Arkanoid
; Raultecnologia
; el programa esta en LOGO para usar directamente en el UCBLogo
; para empezar el juego teclea el procedimiento inicio
;



clearscreen
hideturtle

to campo
penup
setxy -200 -120
pendown
setpencolor 7
setpensize 8
fd 300
rt 90
fd 500
rt 90
fd 300
rt 90
fd 500
rt 90
setpensize 1
end


to ladrillo
setpencolor 4
pendown
fd 20
rt 90
fd 40
rt 90
fd 20
rt 90
fd 40
rt 90
end

to borraladrillo
setpencolor 0
pendown
fd 20
rt 90
fd 40
rt 90
fd 20
rt 90
fd 40
rt 90
end

to nave
setpencolor 5
penup
lt 90
fd 20
rt 90
pendown
fd 10
rt 90
fd 40
rt 90
fd 10
rt 90
fd 40
rt 90
penup
rt 90
fd 20
lt 90
end

to borranave
setpencolor 0
penup
lt 90
fd 20
rt 90
pendown
fd 10
rt 90
fd 40
rt 90
fd 10
rt 90
fd 40
rt 90
penup
rt 90
fd 20
lt 90
end

to bola
pendown
setpencolor 7
arc 360 8
end

to borrabola
pendown
setpencolor 0
arc 360 8
end


to tele


make "posible 0
if [bolay <= -80][colision]
if [bolay >= 170][make "vely -vely]
if [bolax <= -190][make "velx -velx]
if [bolax >= 290][make "velx -velx]

make "varx int((bolax+200)/41)
make "vary int((bolay-50)/21)
if [varx <= 10][if [varx>=1][if [vary<=4][if [vary>=1][make "posible 1]]]]

if [posible=1] [make "dentro mditem (list :varx :vary) :tabla ~
 if [dentro = 1] [make "vely -vely penup setxy varx*41-200 vary*21+50 borraladrillo ~
mdsetitem (list :varx :vary) :tabla 0 dibujaladrillos make "aciertos aciertos+1]]
if [aciertos=40][fin]
penup
setxy bolax bolay
borrabola
penup
setxy rx ry
borranave
make "bolax bolax+velx
make "bolay bolay+vely
make "rx first mousepos
if [rx < -176] [make "rx -176]
if [rx > 275] [make "rx 275]
penup
setxy rx ry
nave
penup
setxy bolax bolay
bola
for [i 0 perdertiempo] [penup setxy 0 0 campo]
tele
end


to inicio
clearscreen
setpensize 1
penup
setxy -200 140
setpencolor 4
label "|Videojuego Arkanoid|
setxy -200 110
setpencolor 7
label "|Maneja la nave con el ratón|
setxy -200 80
setpencolor 6
label "|Acierta a los ladrillos|
setxy -200 -20
label "|Pulsa cualquier tecla para empezar|
wait 120
make "tecla rc
clearscreen
setpencolor 7

make "size_x 11
make "size_y 5
make "tabla (mdarray (list :size_x :size_y) 1)

for [i 1 10 1] [for [j 1 4 1] [mdsetitem (list :i :j) :tabla 1]]

dibujaladrillos

make "perdertiempo 30

make "puntos 0

make "ry -100
make "rx 0
make "bolax 0
make "bolay 0
make "velx 1
make "vely -1
make "aciertos 0


window
tele
end

to dibujaladrillos
for [i 1 10 1] [for [j 1 4 1] [make "dentro mditem (list :i :j) :tabla ~
 if [dentro = 1] [penup setxy i*41-200 j*21+50 ladrillo]]]
end






to fin
penup


setpencolor 4
penup
setxy -40 -5
label "!!!fin!!!
setxy -100 -100
label "|pulsa cualquier tecla para empezar|
wait 120
make "tecla rc
inicio
end


to colision
make "distancia ((rx-bolax))
if [distancia<0][make "distancia -distancia]
if [velx>0][make "signovelx 1]
if [velx<0][make "signovelx -1]

if [distancia<25][make "vely -vely make "velx signovelx+distancia/10]
if [distancia >=25][destruyenave]
end

to destruyenave
penup
setxy rx ry
borranave
pendown
setpencolor 2
lt 45
arc 90 20
arc 90 40
rt 180
arc 90 20
arc 90 40
rt 180
rt 45
penup
setxy -40 -5
label "!!!Perdiste!!!
setxy -100 -100
label "|pulsa cualquier tecla para empezar|
wait 120
make "tecla rc
inicio
end

UCBLogo: videojuego Tron



Tron es un videojuego clásico en el que dos jugadores manejan dos motos y pierde aquel que choca contras las paredes del campo de juego o bien contra la estela de cualquiera de las dos motos.



Consideraciones generales: el código de este videojuego es muy fácil de hacer si partimos del código del videojuego de la serpiente anterior, por lo que de nuevo definimos una tabla que es sobre la que controlamos el juego (en este caso más grande). En realidad es más fácil de programar que el videojuego de la serpiente, pues en este caso no tenemos que ir borrando la serpiente según va pasando, pues las estelas permanecen en el sitio donde pasó la moto. Como tenemos dos motos (una llamada serpiente y otra culebra) definimos dos finales.

Código del juego

;
; Videojuego TRON
; Raultecnologia
; El código es funcional para el UCBLogo versión 5.5
; y evidentemente está para que puedas mejorarlo...
; en este juego usaremos los procedimientos MDARRAY, MDITEM y MDSETITEM
; para trabajar con vectores que tienen la informacion de que hay en cada celda
;

;
; el procedimiento inicio establece la pantalla de presentacion
;
to inicio
clearscreen
hideturtle
setpencolor 7
penup
setxy -200 140
setpencolor 4
label "|Videojuego de TRON|
setxy -200 110
setpencolor 7
label "|teclas de moto blanca: w s a d|
setxy -200 80
setpencolor 6
label "|teclas de moto amarilla: i k j l|
setxy -200 0
setpencolor 3
label "|Pulsa cualquier tecla para empezar|
wait 120
make "tecla rc
setpencolor 7
comienzo
end



; el procedimiento comienzo establece las condiciones iniciales
;
to comienzo
clearscreen
campo
penup
make "x -80
make "y -80
make "xx ((x/8)+30)
make "yy ((y/8)+16)
make "a 80
make "b -72
make "aa ((x/8)+30)
make "bb ((y/8)+16)
  ;manejamos dos tipos de coordenadas. x, y son las de la pantalla para dibujar
  ;xx, yy son las de las celdas correspondientes
make "vx -8
make "vy 0
make "va 8
make "vb 0
 ;vx, vy son las velocidades iniciales
make "size_x 50
make "size_y 40
make "tabla (mdarray (list :size_x :size_y) 1)
  ;definimos el tamanio de la tabla
for [i 1 50 1] [for [j 1 40 1] [mdsetitem (list :i :j) :tabla 0]]
serpiente
culebra
juego
end



;
; el procedimiento campo sencillamente dibuja el campo de juego
;
to campo
setpencolor 4
penup
setxy -228 -117
setpensize 8
pendown
fd 320
rt 90
fd 400
rt 90
fd 320
rt 90
fd 400
rt 90
penup
end

;
; el procedimiento serpiente dibuja la cabeza de la serpiente
;
to serpiente
penup
setxy x y
mdsetitem (list :xx :yy) :tabla 1
pendown
setpensize 1
setpencolor 7
for [i 1 8 1] [fd i rt 90 fd i rt 90 fd i rt 90 fd i rt 90]
end

;
; el procedimiento culebra dibuja la cabeza de la otra serpiente
;
to culebra
penup
setxy a b
mdsetitem (list :aa :bb) :tabla 2
pendown
setpensize 1
setpencolor 6
for [i 1 8 1] [fd i rt 90 fd i rt 90 fd i rt 90 fd i rt 90]
end




;
; el procedimiento juego controla las condiciones del juego
;
to juego
mdsetitem (list :xx :yy) :tabla 1
mdsetitem (list :xx :yy) :tabla 2
if keyp [make "tecla rc]
if tecla = "w [make "vx 0 make "vy 8]
if tecla = "s [make "vx 0 make "vy -8]
if tecla = "d [make "vx 8 make "vy 0]
if tecla = "a [make "vx -8 make "vy 0]
if tecla = "i [make "va 0 make "vb 8]
if tecla = "k [make "va 0 make "vb -8]
if tecla = "l [make "va 8 make "vb 0]
if tecla = "j [make "va -8 make "vb 0]
if x >= 160 [fins]
if x <= -230 [fins]
if y >= 192 [fins]
if y <= -116 [fins]
if a >= 160 [finc]
if a <= -230 [finc]
if b >= 192 [finc]
if b <= -116 [finc]
make "x x+vx
make "y y+vy
make "xx ((x/8)+30)
make "yy ((y/8)+16)
make "a a+va
make "b b+vb
make "aa ((a/8)+30)
make "bb ((b/8)+16)
make "contenidos mditem (list :xx :yy) :tabla
make "contenidoc mditem (list :aa :bb) :tabla
if contenidos >= 1 [fins]
if contenidoc >= 1 [finc]
serpiente
culebra
for [i 1 1000][make "pierdotiempo i+i]
juego
end



;
; el procedimiento fins establece el final de la partida
; si pierde la serpiente
;
to fins
penup
setxy x y
pendown
setpencolor 1
arc 360 8
arc 360 16
setpencolor 3
arc 360 32
setpencolor 7
penup
setxy x-40 y-5
label "!!!CRASH!!!
setxy -250 -180
label "|perdio la moto blanca, pulsa cualquier tecla para empezar|
wait 120
make "tecla rc
inicio
end

;
; el procedimiento finc establece el final de la partida
; si pierde la culebra
;
to finc
penup
setxy a b
pendown
setpencolor 1
arc 360 8
arc 360 16
setpencolor 3
arc 360 32
setpencolor 6
penup
setxy a-40 b-5
label "!!!CRASH!!!
setxy -250 -180
label "|perdio la moto amarilla, pulsa cualquier tecla para empezar|
wait 120
make "tecla rc
inicio
end