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