Vamos
a realizar ya nuestro primer videojuego, algo sencillo. Para ello programaremos
el videojuego del frontón. Como una imagen vale más que mil palabras, pongamos
una captura del juego ya realizado para entender de qué va el juego.
Básicamente
el juego consta de una pelota (el círculo que vemos), que se va moviendo en una
dirección y rebota cuando choca con las pareces del campo. Por un lado el campo
está abierto y nosotros controlamos la raqueta (el rectángulo dibujado a la
izquierda) con un par de teclas (en nuestro caso q arriba y a abajo). Si
la pelota sobrepasa a la raqueta por la izquierda, se pierde, y si acertamos a
dar a la pelota, esta rebotará. Además, para que el videojuego sea más ameno,
la velocidad de la pelota irá en aumento a medida que la golpeemos.
Para
realizar un videojuego de este tipo, nos va a facilitar mucho las cosas definir
procedimientos adecuados, uno que dibuje la raqueta, otro que dibuje la pelota,
una de fin, etc.
El
campo podemos dibujarlo una sola vez, pues nunca se altera. Sin embargo,
elementos como la pelota o la raqueta están en movimiento. Simularemos el movimiento
borrando el elemento dibujado en una posición y dibujándolo en la posición
siguiente.
Definiremos
también procedimientos de comienzo (una presentación con información sobre el
videojuego y las teclas, tal y como podemos ver en esta captura):
Y
de finalización (ver esta otra captura de pantalla):
Los
procedimientos que se definen en el juego (como veremos luego en el código) son
los siguientes: inicio, presentacion, campo, raqueta, frontón y final. Cada uno ellos sólo se ejecutan una única vez, salvo frontón (que es el procedimiento que
presenta recursividad y por lo tanto el alma del juego) y raqueta (que será llamado desde el procedimiento frontón tanto para
dibujar la raqueta como para borrarla). Si los representamos en un diagrama de
flujo:
Analicemos
el código de alguno de ellos:
Procedimiento campo
;
; el procedimiento campo
sencillamente dibuja los limites del fronton
;
to campo
penup
setxy -250 -100
pendown
rt 90
fd 500
lt 90
fd 280
lt 90
fd 500
lt 90
fd 10
lt 90
fd 490
rt 90
fd 260
rt 90
fd 490
lt 90
fd 10
rt 180
penup
end
Las
tres primeras líneas empiezas por el símbolo ; que significa que son comentarios y por lo tanto no son
interpretados por el compilador. Nos
sirven para reutilizar el código y para que otras personas puedan entender
mejor qué hace cada parte del código.
El
comando to y el comando end sirven para iniciar y terminar un
procedimiento que estamos definiendo (tal y como vimos en el ejemplo del
telesketch), en este caso el procedimiento campo.
Los
comandos lt, rt y fd también han sido
vistos y sirven para girar a la izquierda, girar a la derecha y avanzar
respectivamente y, en definitiva, son los que dibujan el campo.
Usamos,
no obstante, 3 comandos nuevos: penup,
setxy y pendown que explicaremos
a continuación.
El
comando setxy -250 -100 sirve para
situar la tortuga en la posición de pantalla -250 -100, utilizando referenciar
absolutas, es decir, el punto -250, -100 es siempre el mismo independientemente
de la posición de la tortuga en ese momento.
Los
comandos penup y pendown sirve para indicar, respectivamente, que la tortuga no va a
dejar rastro (penup) o que sí lo va a
dejar (pendown) en su desplazamiento.
Procedimiento presentacion:
to presentacion
penup
setxy -100 110
setpencolor 4
label "Juego_del_Fronton
setxy -100 80
label
"Teclas:_q_arriba_a_abajo
setxy -100 50
setpencolor 7
label
"Evita_que_la_bola_salga_del_campo_de_juego
setxy -100 20
label
"Con_cada_golpe_la_bola_aumenta_de_velocidad
setxy -100 -10
label "Pulsa_cualquier_tecla_para_empezar
make "var2 rc
end
Esta
pantalla no hace más que mostrar texto y esperar a que el usuario pulse
cualquier tecla para seguir. Para ello evitamos que la tortuga trace líneas al
desplazarse (usando penup) y
escribimos texto con diferentes colores. Para escribir en rojo usamos setpencolor 4 (que sirve para indicar
que a partir de ahora todo irá en rojo) y para escribir en blanco escribimos setpencolor 7 (que sirve para indicar
que a partir de ahora todo se dibuje en blanco). Para conocer los colores no
tenemos más que hacer help “setpencolor
en el compilador LOGO y nos da la asociación entre el número y el color.
Para
escribir texto usamos el comando label,
de tal forma que label “Juego_del_Fronton
nos escribe Juego_del_Fronton en la
posición de pantalla en la que la tortuga está.
La
última línea, make “var2 rc,
sencillamente crea una variable de nombre var2 que lo único que hace es dar un
valor al carácter pulsado que no usaremos, sencillamente lo ponemos porque
espera a que el usuario pulse cualquier tecla para continuar.
Procedimiento final
to final
clearscreen
penup
setxy -100 50
label
"Has_perdido_la_partida
setxy -100 30
label
"Escribe_inicio_para_volver_a_jugar
end
El
procedimiento final nos escribe la
pantalla final. En este caso está programado para que acabe, por lo que el
control volvería a la línea de comandos del compilador. Para volver a jugar
habría que teclear el procedimiento de comienzo del juego: inicio.
Procedimiento inicio
El
procedimiento inicio es un procedimiento que se ejecuta una sola vez y es el
encargado de ejecutar las instrucciones precisas antes de empezar el
procedimiento principal: llama a ciertos procedimientos y establece las
condiciones iniciales para las variables del juego.
Para
este juego vamos a manejar varias variables que deberán tener un valor inicial
antes de entrar en el procedimiento principal del juego fronton. Ahora es el momento de hacerlo. Las variables que vamos a
manejar son las siguientes:
·
yraqueta:
posición en el eje cartesiano “y” de la raqueta (a qué altura está). En este
caso como sólo se mueve arriba y abajo y no se mueve izquierda-derecha, una
sola variable marca la posición de la raqueta.
·
xbola:
posición en el eje cartesiano “x” de la bola.
·
ybola:
posición en el eje cartesiano “y” de la bola, pues la bola puede moverse en
cualquier parte de la pantalla, siempre que no sobresalga del campo de juego.
·
xvelbola:
velocidad en el eje cartesiano “x” de la velocidad de la bola.
·
yvelbola:
velocidad en el eje cartesiano “y” de la velocidad de la bola.
·
velocidad:
variable que sirve para perder tiempo (a menor tiempo perdido, más rápido irá
el juego). Nos sirve para dos cosas: un valor inicial para ajustar a la
velocidad del ordenador (no todos los ordenadores compilan igual de rápido) y
por otro lado, para cambiar la velocidad del juego durante el transcurso del
mismo).
·
tecla:
memoriza la última tecla pulsada.
El
código en concreto del procedimiento inicio
(incluidos algunos comentarios, que son los que van detrás del punto y coma),
es el siguiente (llegados a este punto creo que todo debiera ser comprensible):
to inicio
clearscreen
hideturtle
presentacion ; llama al procedimiento de la
pantalla de presentacion
clearscreen
pendown
penpaint
campo ; llama el procedimiento
de dibujar el campo
make "yraqueta 0 ; posicion inicial de la raqueta
make "xbola 0 ; xbola, ybola son las coordenadas
iniciales de la pelota
make "ybola 0
make "xvelbola 1 ; xvelbola, yvelbola son las velocidades
iniciales
make "yvelbola 1
make "velocidad 200 ; velocidad sirve para perder tiempo
penup
setxy xbola ybola
pendown
arc 360 5 ; dibujamos la bola
arc 360 4
arc 360 3
penup
setxy -250 yraqueta
pendown
raqueta ; dibujamos la raqueta
make "tecla 0
fronton
end
Aparece
un comando nuevo penpaint que sirve
para que la tortuga dibuje al desplazarse (y no borre, algo que se puede hacer
con penerase, como veremos
posteriormente).
Hay
una llamada al procedimiento raqueta
que sencillamente dibuja la “raqueta” que no es otra cosa que un rectángulo:
to raqueta
fd 20
rt 90
fd 5
rt 90
fd 20
rt 90
fd 5
rt 90
end
Procedimiento fronton
Este
procedimiento es el alma del juego. Para entenderlo, haremos unas pocas
consideraciones:
1.-
Usando el teclado para poder jugar: hasta ahora hemos usado el teclado
de una manera que no nos permitirá realizar muchos videojuegos, pues a con la
instrucción make “tecla rc, el compilador no hace nada hasta que no pulsemos
una tecla. Para un telesketch, esto está bien porque no hay nada que hacer,
pero en este caso (y en general en el resto), sí suceden cosas aunque no haya
teclas pulsadas (por ejemplo, la bola debe moverse y rebotar con las paredes
tanto si pulso una tecla para mover la raqueta como si no). Para ello añadiremos
esta línea de código: if keyp [make "tecla rc], que
quiere decir, que sólo actualizaremos la variable tecla (que es la que almacena
qué tecla estamos pulsando) si hay alguna tecla pulsada. keyp es un comando que mira si hay o no alguna tecla pulsada. Si no
la hay devuelve FALSE, por lo que lo que hay dentro de los corchetes no se lee.
Si hay alguna tecla pulsada, devuelve TRUE, por lo que entonces ejecutará lo
que hay dentro del paréntesis. La usamos combinada con el condicional if, comando que nos permite introducir
condiciones y es la que decidirá si ejecutar el código entre corchetes o no en
función de que la condición inicial se cumpla (si se cumple lo ejecuta y si no
se cumple no se ejecuta).
2.-
Movimiento de la raqueta: la raqueta es controlada por el teclado.
Inicialmente está quieta. Una vez que pulsamos una tecla (arriba o abajo) se
moverá en la dirección adecuada hasta que cambiemos la tecla pulsada. Esto lo
conseguimos usando condiciones y cambiando la variable yraqueta (posición de la raqueta) en función de qué tecla haya sido
pulsada. Lo que haremos será fácil: miramos dónde está la raqueta, la borramos,
añadimos (o disminuimos si es para descender) un píxel a la posición de la
raqueta y la volvemos a dibujar.
Veamos
este código:
if tecla = "q [penup setxy -250
yraqueta penerase raqueta make "yraqueta yraqueta+1 setxy -250 yraqueta
penpaint raqueta]
la
primera parte, if tecla = “q, es la
que establece la condición (es decir, si pulsamos la tecla “q”). La segunda
parte, la que va entre corchetes, es el código que debe cumplir si la tecla “q”
es la tecla pulsada. Pues si la tecla “q” es pulsada, lo que debe ocurrir es
que la raqueta se mueva hacia arriba. Para ello debemos ir en primer lugar al
punto en el que se encuentra la raqueta, así que hacemos penup (que se mueva la tortuga pero que no pinte), luego setxy -250 yraqueta (es decir, que se
mueva a la coordenada en “x” -250 que es la coordenada “x” en la que vamos a
dibujar siempre la raqueta y a la coordenada en “y” yraqueta, que es la variable que contiene la coordenada en la que
actualmente está la raqueta). Si después hacemos seguido penerase y el procedimiento raqueta,
lo que hacemos es poner en modo borrado la tortuga y como obligamos a trazar la
raqueta, lo que hace es borrarla. Después aumentamos la coordenada en “y” de la
raqueta con make “yraqueta yraqueta+1
(aumenta el valor de la variable yraqueta), luego nos vamos a la nueva posición
con setxy -250 yraqueta y finalmente
dibujamos la raqueta, para ello debemos decir que vuelva a pintar al mover la
tortuga con penpaint y finalmente el
procedimiento raqueta dibuja la
raqueta.
En
resumen, y a modo de esquema si dividimos este código:
if
tecla = "q à si pulsamos la tecla “q” entonces…
[ à abrimos condicional
penup
à levanta la tortuga
setxy
-250 yraqueta à veta a la posición actual de la raqueta
penerase
à modo borrar
raqueta à traza (y borra) la raqueta donde estaba
make
"yraqueta yraqueta+1 à el valor de yraqueta aumenta en uno
setxy
-250 yraqueta à vete a la nueva posición de la raqueta
penpaint à modo dibujar
raqueta à traza (y dibuja) la raqueta
] à fin del condicional
3.-
Movimiento de la bola: la bola va a estar moviéndose en cada ciclo de
ejecución del procedimiento frontón. Para ello seguimos las ecuaciones del
movimiento lineal, es decir, r = r0 + v∙t. En esta ecuación, r
es el vector de posición en un momento determinado, r0 el vector de posición en un momento anterior, v el vector de velocidades y t el tiempo transcurrido desde que se
pasó de la posición r0 a r. Al ser vectores contemplamos la posibilidad
de desplazamientos en varias dimensiones. En nuestro caso tenemos una pantalla
plana y los movimientos serán en el plano, por lo que la dimensión de los
vectores de posición y velocidades será dos y, por tanto, podemos reducir la
ecuación vectorial a dos ecuaciones sencillas, una para el eje de cartesianas
“x” y otra para el eje “y” de esta forma:
x
= x0 + vx∙ t
y
= y0 + vy∙t
en
nuestro caso la variable de las coordenadas de la bola son, respectivamente, xbola e ybola y las de las velocidades de la bola xvelbola e yvelbola, por
lo que estas ecuaciones anteriores adoptan este código:
make "xbola xbola+xvelbola
make "ybola ybola+yvelbola
En
resumen, asignamos a la variable xbola
(o ybola) el valor que tenía
anteriormente y le sumamos la velocidad (el tiempo adoptamos el criterio de
incrementos de uno en uno, por lo que al multiplicar por uno sencillamente no aparece
en el código).
Para
simular el movimiento de la bola no tenemos más que hacer lo mismo que hicimos
para la raqueta, es decir, borrar la bola en la posición actual y dibujarla en
la posición nueva. Se podría haber diseñado un procedimiento para el dibujo de
la bola, pero en este caso no se hizo, así que esta simulación del movimiento
de la bola sería así:
penup
setxy xbola ybola ;voy a la posición de la bola
pendown
penerase ;borrar
arc 360 5
arc 360 4
arc 360 3
make "xbola xbola+xvelbola ;asignación de nueva posicion
make "ybola ybola+yvelbola
penpaint ;volver a pintar
setxy xbola ybola
arc 360 5
arc 360 4
arc 360 3
Nos
aparece un comando nuevo que es el comando arc
que sirve para dibujar arcos indicando grados y radio. Lo usamos para dibujar
la pelota con 3 circunferencias (360 grados hacen una circunferencia) de radios
3, 4 y 5 píxeles.
4.-
Rebote de la bola: para hacer que la bola rebote no tenemos más que
hacer uso de las ecuaciones de velocidad. Si una pelota se mueve hacia la
derecha y llega a la pared de la derecha, debe rebotar. Esto podemos hacerlo
cambiando el signo de la velocidad en el eje “x”, pues si iba hacia la derecha,
era una velocidad positiva y como al rebotar se mueve hacia la izquierda, ahora
la velocidad en el eje “x” debe ser negativa. Algo tan sencillo como cambiar el
signo de las velocidades aplicando este razonamiento al resto de paredes, nos
permite simular el rebote de la bola:
if xbola = 234 [make
"xvelbola -xvelbola] ;rebote en la pared de la derecha
if ybola = 164 [make
"yvelbola -yvelbola] ;rebote en la pared de arriba
if ybola = -83 [make
"yvelbola -yvelbola] ; rebote en la pared de abajo
los
valores 234, 164 y -83 son valores que se acomodan al dibujo del campo para simular
que precisamente en estos valores deben rebotar (si cambiáramos el tamaño del
campo estos valores deberían ajustarse).
5.-
Ajustar la velocidad de juego antes y durante el mismo: una cuestión
importante a tener en cuenta con el compilador es que el videojuego no irá
exactamente a la misma velocidad en un ordenador o en otro, pues dependerá de
la capacidad de proceso del mismo. Para poder ajustar la jugabilidad podemos
definir una variable (en nuestro caso la variable velocidad) que servirá en primer lugar para dar un valor de inicio
y así ajustar la velocidad a lo que queremos y, además, para poder ir variando
el valor durante el juego y así hacerlo más rápido según transcurra para
aumentar la dificultad.
En
nuestro ejemplo, en el procedimiento inicio
definimos make "velocidad 200,
con lo que inicialmente la variable velocidad
(que no es más que una indicación de pérdida de tiempo) vale 200.
El
código para perder tiempo usado es el siguiente:
for
[i 0 velocidad 1] [arc 360 5]
este
código está justo en el momento en el que dibuja la bola. arc 360 5 es una parte de dibujar la bola (tal y como vimos). En
este caso vamos a perder tiempo inicialmente dibujando 201 veces una parte de
la bola. Para ello usamos un bucle for que indica cuántas veces se
ejecutará una instrucción. El primer corchete indica las veces y el modo en que
se ejecutará la instrucción, ya que [i 0
velocidad 1] significa que defino una variable que se llama i que va a tomar valores desde 0 hasta el valor de la variable velocidad (que inicialmente valía 200) y
que se va a ir incrementando de 1 en 1. La segunda parte [arc 360 5] indica el código que se va a repetir hasta que acabe el
bucle for.
6.-
Cuándo pierde el jugador: en el caso del frontón el código para que
termine el juego es fácil: if xbola = -280 [final
stop].
Este código lo único que mira es que si en cualquier momento la coordenada en x
de la bola es -280 (la raqueta se dibujaba en -250), entonces es que algo ha
pasado para que la bola esté demasiado a la izquierda del campo (en resumen no
le habremos dado con la raqueta), por lo que sencillamente llama al
procedimiento final (que ejecuta las
instrucciones ya vistas en su procedimiento)
y para la ejecución del programa con la instrucción stop.
7.- Calculando si la raqueta acierta a dar a la
bola: existen varios procedimientos para discernir si la raqueta acierta a
la bola. Como la raqueta sólo tiene movimiento en el eje “y”, su coordenada en
“x” es fija, por lo que podemos hacer el cálculo cuando la coordenada en “x” de
la bola sea la adecuada para que se pueda producir o no el acierto (en nuestro
caso, por cuestiones de geometría lo haremos cuando la coordenada “x” de la
bola valga -240). Establecido esto, como
la raqueta es un rectángulo y la bola una circunferencia, no tenemos más que
calcular una distancia entre las componentes “y” de coordenadas del origen del
rectángulo (variable yraqueta) y el
centro de la circunferencia (variable ybola),
y si esta diferencia es menor que un determinado valor (que la longitud de la
raqueta, por ejemplo), establecer el rebote. Esta diferencia la elevaremos al
cuadrado para garantizar que siempre comparamos números positivos. Veamos la
siguiente figura:
Podemos usar la distancia (siempre sólo para la
coordenada cartesiana “y”) entre el centro de la bola (azul) y el centro de la
raqueta (rojo). Como el origen desde el que se dibuja la raqueta es el punto
verde, esta distancia sería (ybola-(yraqueta+10)), que en el dibujo y para tres
bolas distintas sería, respectivamente, d1, d2 y d3. Pues bien, una manera de
calcular si la raqueta golpea a la bola sería calcular esta diferencia y si es
menor que un cierto valor, la raqueta golpea, algo como if (ybola-(yraqueta+10)) < 15 [comandos]. Sin embargo, este
ejemplo daría un falso positivo en el caso de la bola de la figura etiquetada
con el número 1, pues d1 que es (ybola-(yraqueta+10)) sería un número negativo
(d2 y d3 de la figura serían números positivos). Para evitar este problema
elevamos esta distancia al cuadrado, pues al cuadrado cualquier número entero
será mayor o igual que cero. Obviamente, habría que elevar al cuadrado también
la distancia a comparar, por lo que 15 sería 225.
En resumen, el código escrito para decidir si la
bola rebota o no es este:
if xbola =
-240 [if ((ybola-(yraqueta+10))*(ybola-(yraqueta+10))) < 225 [make
"xvelbola -xvelbola make "velocidad velocidad/1.5]]
en el que recogemos las explicaciones dadas y lo
que hace en caso de rebote es cambiar el signo de la velocidad de la bola en la
coordenada en “x” para que rebote (make
“xvelbola –xvelbola) y aumentar la velocidad de juego al hacer que la
pérdida de tiempo (que venía en la variable velocidad)
disminuya al dividirlo por un número mayor que uno (make “velocidad
velocidad/1.5).
8.- Evitando que la raqueta sobrepase el campo:
para evitar que la raqueta sobrepase la altura del campo no tenemos más que
incorporar un condicional a la forma en que la raqueta se mueve (visto en el
punto 2). Veamos este código:
if
yraqueta < 149 [if tecla = "q [penup setxy -250 yraqueta penerase
raqueta make "yraqueta yraqueta+1 setxy -250 yraqueta penpaint raqueta]]
tenemos dos condicionales anidados, por lo que,
como vemos, la tecla “q” sólo hará ascender la raqueta (todo el código a partir
de if tecla... es el visto en el
punto 2) si el valor de la coordenada “y” de la raqueta es menor que un cierto
número (que obviamente se corresponde con el límite superior del campo).
Código final del Juego
;
; juego del fronton
; Raultecnologia
; ejemplo de aplicacion de
programacion en LOGO con el programa UCBLogo
;
;
; el procedimiento campo
sencillamente dibuja los limites del fronton
;
to campo
penup
setxy -250 -100
pendown
rt 90
fd 500
lt 90
fd 280
lt 90
fd 500
lt 90
fd 10
lt 90
fd 490
rt 90
fd 260
rt 90
fd 490
lt 90
fd 10
rt 180
penup
end
;
; el procedimiento raqueta dibuja
la "raqueta", es decir, el rectangulo que movemos
;
to raqueta
fd 20
rt 90
fd 5
rt 90
fd 20
rt 90
fd 5
rt 90
end
;
; el procedimiento inicio
establece una serie de parametros iniciales para el juego
;
to inicio
clearscreen
hideturtle
presentacion ; llama al procedimiento de la pantalla de
presentacion
clearscreen
pendown
penpaint
campo ; llama el procedimiento
de dibujar el campo
make "yraqueta 0 ; posicion inicial de la raqueta
make "xbola 0 ; xbola, ybola son las coordenadas
iniciales de la pelota
make "ybola 0
make "xvelbola 1 ; xvelbola, yvelbola son las velocidades
iniciales de la pelota
make "yvelbola 1
make "velocidad 200 ; velocidad es una variable que usaremos para
"perder tiempo"
penup
setxy xbola ybola
pendown
arc 360 5 ; dibujamos la bola
arc 360 4
arc 360 3
penup
setxy -250 yraqueta
pendown
raqueta ; dibujamos la raqueta
make "tecla 0
fronton
end
;
; este procedimiento no es mas
que una pantalla inicial con la informacion del juego
;
to presentacion
penup
setxy -100 110
setpencolor 4
label "Juego_del_Fronton
setxy -100 80
label
"Teclas:_q_arriba_a_abajo
setxy -100 50
setpencolor 7
label
"Evita_que_la_bola_salga_del_campo_de_juego
setxy -100 20
label
"Con_cada_golpe_la_bola_aumenta_de_velocidad
setxy -100 -10
label
"Pulsa_cualquier_tecla_para_empezar
make "var2 rc
end
;
; en el procedimiento fronton
esta el alma del juego
;
to fronton
if keyp [make "tecla rc] ;
si hay tecla pulsada, lee el teclado
;
; las siguientes instrucciones miran
si podemos mover la raqueta y como lo hacemos
;
if yraqueta < 149 [if tecla =
"q [penup setxy -250 yraqueta penerase raqueta make "yraqueta
yraqueta+1 setxy -250 yraqueta penpaint raqueta]]
if yraqueta > -89 [if tecla =
"a [penup setxy -250 yraqueta penerase raqueta make "yraqueta
yraqueta-1 setxy -250 yraqueta penpaint raqueta]]
penup
setxy xbola ybola
pendown
penerase
arc 360 5
arc 360 4
arc 360 3
;
; ahora vienen las condiciones
del choque con las paredes y la raqueta
;
if xbola = 234 [make "xvelbola -xvelbola]
if ybola = 164 [make "yvelbola -yvelbola]
if ybola = -83 [make "yvelbola -yvelbola]
if xbola = -240 [if ((ybola-(yraqueta+10))*(ybola-(yraqueta+10))) < 225
[make "xvelbola -xvelbola make "velocidad velocidad/1.5]]
if xbola = -280 [final stop]
make "xbola xbola+xvelbola
make "ybola ybola+yvelbola
penpaint
setxy xbola ybola
arc 360 5
arc 360 4
arc 360 3
for [i 0 velocidad 1] [arc 360
5] ; esto sirve para perder tiempo
fronton
end
;
; el procedimiento final controla
lo que ocurre cuando el juego termina
;
to final
clearscreen
penup
setxy -100 50
label
"Has_perdido_la_partida
setxy -100 30
label
"Escribe_inicio_para_volver_a_jugar
end