diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..7111040
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,9 @@
+{
+ "cSpell.words": [
+ "compi",
+ "compis"
+ ],
+ "cSpell.enableFiletypes": [
+ "!wollok"
+ ]
+}
\ No newline at end of file
diff --git a/ConceptosTeoricos.md b/ConceptosTeoricos.md
new file mode 100644
index 0000000..ad71032
--- /dev/null
+++ b/ConceptosTeoricos.md
@@ -0,0 +1,34 @@
+# Conceptos Teóricos aplicados en el TP
+
+## ***Polimorfismo***
+>Capacidad de los objetos de diferentes clases de responder de manera distinta a un mismo mensaje. Esto permite que un mismo código interactúe con diferentes tipos de objetos de una manera uniforme y flexible.
+
+En este trabajo práctico, aplicamos en varias ocasiones el concepto de *polimorfismo*:
+
+### ¿Cómo se renderizan nuestros niveles?
+
+Una aplicacion clara de este concepto se observa en los objetos **"decoders"** *(v, p, _, m, z, g, l, x, o)*, que se encargan de generar los elementos dentro de cada nivel según su posición en el `Gridmap`. Cada uno de estos objetos implementa el método `decode()`, pero realiza una tarea diferente al ejecutarlo, permitiendo que cada objeto decodificador interprete su función específica de forma autónoma.
+
+### UnDo() y la posibilidad de retroceder acciones In Game
+
+Otro caso de aplicación de polimorfismo en el juego es el mensaje `undo()`, que es entendido por todos los **"Movimientos"** *(arriba, abajo, izquierda, derecha, StickyCompi, Agujero)*. Cada uno de estos movimientos ejecuta su propia lógica al deshacer la acción, adaptándose a su comportamiento específico.
+
+### Colisiones: ante un problema recurrente, una solución efectiva
+
+Para resolver el problema de las colisiones, aparece el método `interactuarConPersonaje()` . Este método es utilizado con frecuencia para que los distintos objetos identifiquen cómo comportarse en caso de que colisionen con el personaje principal. Por ejemplo: las **hitboxes** de los StickyCompis permiten acoplarse al personaje principal, la **meta** valida si el jugador ganó el nivel al colisionar con ella, entre otros casos.
+
+## ***Herencia***
+
+> Mecanismo que permite a una clase adquirir las propiedades y métodos de otra clase, estableciendo una relación jerárquica entre ellas. Esto facilita la reutilización de código, evitando que se repita la lógica, permitiendo crear estructuras de clases más organizadas y extensibles.
+
+### Nuestros personajes
+
+La *herencia* se aplica directamente en el diseño de `PersonajeInicial` y los `StickyCompis`, los cuales heredan las propiedades de los `stickyBlocks`. Esta herencia les permite moverse, colisionar, aparecer, desaparecer e interactuar con otros objetos, a la vez que conservan sus propias funcionalidades específicas, como la inicialización, creación y características únicas de sus hitboxes.
+
+### ¿Cómo validamos que un nivel haya sido completado exitosamente?
+
+La *herencia* aquí se observa en la implementación de `MetaValidadora`, que extiende las funcionalidades básicas de `Meta` para encargarse de validar la condición de victoria al colisionar con un elemento del cuerpo y permitir el avance al siguiente nivel. Se optó por hacer que solo una de las metas sea la validadora, evitando así que múltiples instancias ejecuten la misma lógica, lo que optimiza los tiempos de carga de nivel.
+
+# Diagrama de clases
+
+![alt text](ImageReadme/StickyBlockClassDiagram.svg)
\ No newline at end of file
diff --git a/ImageReadme/Flechas PopUp.png b/ImageReadme/Flechas PopUp.png
new file mode 100644
index 0000000..93687b8
Binary files /dev/null and b/ImageReadme/Flechas PopUp.png differ
diff --git a/ImageReadme/Reset.png b/ImageReadme/Reset.png
new file mode 100644
index 0000000..5dedb1c
Binary files /dev/null and b/ImageReadme/Reset.png differ
diff --git a/ImageReadme/StickyBlockClassDiagram.svg b/ImageReadme/StickyBlockClassDiagram.svg
new file mode 100644
index 0000000..43bbbfe
--- /dev/null
+++ b/ImageReadme/StickyBlockClassDiagram.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/ImageReadme/imagen1.png b/ImageReadme/imagen1.png
new file mode 100644
index 0000000..4782929
Binary files /dev/null and b/ImageReadme/imagen1.png differ
diff --git a/ImageReadme/imagen2.png b/ImageReadme/imagen2.png
new file mode 100644
index 0000000..b31e90f
Binary files /dev/null and b/ImageReadme/imagen2.png differ
diff --git a/ImageReadme/imagen3.png b/ImageReadme/imagen3.png
new file mode 100644
index 0000000..a5cf596
Binary files /dev/null and b/ImageReadme/imagen3.png differ
diff --git a/ImageReadme/imagen4.png b/ImageReadme/imagen4.png
new file mode 100644
index 0000000..0c61918
Binary files /dev/null and b/ImageReadme/imagen4.png differ
diff --git a/README.md b/README.md
index 4a885a1..8435f0b 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,58 @@
-# (reemplazar nombre de juego acá)
+> UTN - Facultad Regional Buenos Aires - Materia Paradigmas de Programación
-UTN - Facultad Regional Buenos Aires - Materia Paradigmas de Programación
+![STICKY BLOCKS logo](assets/Logo.png)
-## Equipo de desarrollo:
+## Introducción
-- completar...
-- completar...
-
+
+¡Preparate para un quilombo de bloques en STICKY BLOCK!
+
+
+Acá no solo tenés que mover los bloques, ¡sino que cuando se pegan, te armás un lío bárbaro! 😜
+Usá la cabeza para juntar los bloques mientras buscás la manera de llegar a la meta. 🧠
+
+¿Te animás a resolver este embrollo o te quedás pegado? 🧩 **¡Dale que va! 🚀**
+
+## Capturas
+
+
+
+
+
+
+
-## Capturas
-![pepita](assets/golondrina.png)
## Reglas de Juego / Instrucciones
-(completar...)
+### Instrucciones de *Sticky Block*
+
+1. **Uní los bloques**: ¡Mové los *stickyblocks* y hacelos pegarse entre sí! Cuanto más pegajosos, mejor. 💥
+
+2. **Esquivá los agujeros**: ⚠️Cuidado⚠️ En algunos niveles, ¡el piso tiene trampas! 🕳️
+
+3. **Formá la figura**: Tenés que llegar a la meta, pero ojo, ¡la forma importa! Acomodalos como en el objetivo. 🎯
+
+¡Dale que podés! 🚀
## Controles:
-- `W` para...
+![Controles Flechas]()
+
+![ctrl](ImageReadme/Reset.png)
+
+R para reiniciar el nivel
+
+M para abrir el menú
+
+## Equipo de desarrollo:
+
+- Devecchi Di Bella Lucas Nahuel
+- Diez Forradellas Facundo
+- Hernandez Mateo Nicolas
+- Osa Pochelu Valentin Rodrigo
+- Serrudo Jose Luis
+
+[Conceptos teóricos aplicados en el TP](ConceptosTeoricos.md)
diff --git a/assets/ArrowsPopUp.gif b/assets/ArrowsPopUp.gif
new file mode 100644
index 0000000..cc8c9fc
Binary files /dev/null and b/assets/ArrowsPopUp.gif differ
diff --git a/assets/ArrowsPopUp.png b/assets/ArrowsPopUp.png
new file mode 100644
index 0000000..22a4877
Binary files /dev/null and b/assets/ArrowsPopUp.png differ
diff --git a/assets/Azul.png b/assets/Azul.png
new file mode 100644
index 0000000..f8a4751
Binary files /dev/null and b/assets/Azul.png differ
diff --git a/assets/CloseMenu.png b/assets/CloseMenu.png
new file mode 100644
index 0000000..a5fc85c
Binary files /dev/null and b/assets/CloseMenu.png differ
diff --git a/assets/End.png b/assets/End.png
new file mode 100644
index 0000000..63337c8
Binary files /dev/null and b/assets/End.png differ
diff --git a/assets/Fondo.png b/assets/Fondo.png
new file mode 100644
index 0000000..8ba85e9
Binary files /dev/null and b/assets/Fondo.png differ
diff --git a/assets/InideGame.mp3 b/assets/InideGame.mp3
new file mode 100644
index 0000000..eb6adc4
Binary files /dev/null and b/assets/InideGame.mp3 differ
diff --git a/assets/Ladrillo1.png b/assets/Ladrillo1.png
new file mode 100644
index 0000000..a8b4c30
Binary files /dev/null and b/assets/Ladrillo1.png differ
diff --git a/assets/Ladrillo2.png b/assets/Ladrillo2.png
new file mode 100644
index 0000000..2992816
Binary files /dev/null and b/assets/Ladrillo2.png differ
diff --git a/assets/Ladrillo3.png b/assets/Ladrillo3.png
new file mode 100644
index 0000000..099ab6f
Binary files /dev/null and b/assets/Ladrillo3.png differ
diff --git a/assets/Ladrillo4.png b/assets/Ladrillo4.png
new file mode 100644
index 0000000..1122fd6
Binary files /dev/null and b/assets/Ladrillo4.png differ
diff --git a/assets/Lampara.png b/assets/Lampara.png
new file mode 100644
index 0000000..81a7e4f
Binary files /dev/null and b/assets/Lampara.png differ
diff --git a/assets/Logo.png b/assets/Logo.png
new file mode 100644
index 0000000..2cb5161
Binary files /dev/null and b/assets/Logo.png differ
diff --git a/assets/Menu.png b/assets/Menu.png
new file mode 100644
index 0000000..b7fc2a6
Binary files /dev/null and b/assets/Menu.png differ
diff --git a/assets/OpenMenu.png b/assets/OpenMenu.png
new file mode 100644
index 0000000..5294968
Binary files /dev/null and b/assets/OpenMenu.png differ
diff --git a/assets/Piso1.png b/assets/Piso1.png
new file mode 100644
index 0000000..dc12613
Binary files /dev/null and b/assets/Piso1.png differ
diff --git a/assets/Piso2.png b/assets/Piso2.png
new file mode 100644
index 0000000..cd9605e
Binary files /dev/null and b/assets/Piso2.png differ
diff --git a/assets/Piso3.png b/assets/Piso3.png
new file mode 100644
index 0000000..1c6ed9a
Binary files /dev/null and b/assets/Piso3.png differ
diff --git a/assets/Rojo.png b/assets/Rojo.png
new file mode 100644
index 0000000..b08f015
Binary files /dev/null and b/assets/Rojo.png differ
diff --git a/assets/RojoCerrado.png b/assets/RojoCerrado.png
new file mode 100644
index 0000000..7ad6d43
Binary files /dev/null and b/assets/RojoCerrado.png differ
diff --git a/assets/RojoParpadea.gif b/assets/RojoParpadea.gif
new file mode 100644
index 0000000..ce091af
Binary files /dev/null and b/assets/RojoParpadea.gif differ
diff --git a/assets/Salida.png b/assets/Salida.png
new file mode 100644
index 0000000..a137d0a
Binary files /dev/null and b/assets/Salida.png differ
diff --git a/assets/Trampa1.png b/assets/Trampa1.png
new file mode 100644
index 0000000..27a1ba7
Binary files /dev/null and b/assets/Trampa1.png differ
diff --git a/assets/Trampa2.png b/assets/Trampa2.png
new file mode 100644
index 0000000..72d65ab
Binary files /dev/null and b/assets/Trampa2.png differ
diff --git a/assets/Trampa3.png b/assets/Trampa3.png
new file mode 100644
index 0000000..a754d0f
Binary files /dev/null and b/assets/Trampa3.png differ
diff --git a/assets/Trampa4.png b/assets/Trampa4.png
new file mode 100644
index 0000000..5b7ba0b
Binary files /dev/null and b/assets/Trampa4.png differ
diff --git a/assets/Trampa5.png b/assets/Trampa5.png
new file mode 100644
index 0000000..82b42d4
Binary files /dev/null and b/assets/Trampa5.png differ
diff --git a/assets/Undo-Reset.png b/assets/Undo-Reset.png
new file mode 100644
index 0000000..48cb078
Binary files /dev/null and b/assets/Undo-Reset.png differ
diff --git a/assets/Victoria.mp3 b/assets/Victoria.mp3
new file mode 100644
index 0000000..b3c79de
Binary files /dev/null and b/assets/Victoria.mp3 differ
diff --git a/assets/drag1.mp3 b/assets/drag1.mp3
new file mode 100644
index 0000000..0178168
Binary files /dev/null and b/assets/drag1.mp3 differ
diff --git a/assets/golondrina.png b/assets/golondrina.png
deleted file mode 100644
index 1660f61..0000000
Binary files a/assets/golondrina.png and /dev/null differ
diff --git a/assets/pop1.mp3 b/assets/pop1.mp3
new file mode 100644
index 0000000..fb778b3
Binary files /dev/null and b/assets/pop1.mp3 differ
diff --git a/levels.wlk b/levels.wlk
new file mode 100644
index 0000000..55f1d37
--- /dev/null
+++ b/levels.wlk
@@ -0,0 +1,358 @@
+import stickyBlocks.*
+import menuYTeclado.*
+
+//*==========================| Creacion de Niveles |==========================
+//---------(Clase)--------
+ class Nivel {
+
+ const initialGridMap
+
+ const property siguienteNivel
+
+ //Goal
+ const goalPositions = []
+ var property firstGoal = true
+
+ //Personaje Principal
+ var property mainCharacterPosition = null
+
+ //StickyBlocks
+ const stickyBlockPositions = []
+
+ //Top Layer objects
+ const lampPosition = []
+
+ method iniciar(){
+ juegoStickyBlock.clear()
+
+ self.clearPositions()
+
+ //Dibujo UI
+ new OnlyVisual(image="Menu.png",position = game.at(0,11)).iniciar()
+ new OnlyVisual(image="Undo-Reset.png",position = game.origin()).iniciar()
+
+ //Dibujo el nivel
+ self.drawGridMap()
+ self.drawCharacters()
+ self.drawTopLayer()
+
+ // Seteo el Teclado para el nivel
+ configTeclado.gameOn()
+
+ //Seteo el nivel actual
+ juegoStickyBlock.nivelActual(self)
+ }
+
+ method clearPositions(){
+ firstGoal = true
+ goalPositions.clear()
+ stickyBlockPositions.clear()
+ lampPosition.clear()
+ }
+
+
+ method drawGridMap(){
+ var y = 10
+ var x = 2
+ initialGridMap.forEach({row =>
+ row.forEach({cell => cell.decode(x, y, self)
+ x+=1
+ })
+ y-=1
+ x=2
+ })
+ }
+
+ method addGoalPosition(x,y){
+ goalPositions.add(game.at(x, y))
+ }
+
+ method cuerpoSobreMeta() = goalPositions.all({goalPos => cuerpo.compis().any({compi => compi.position() == goalPos})})
+
+ method addStickyBlockPosition(x,y){
+ stickyBlockPositions.add(game.at(x, y))
+ }
+
+ method drawCharacters(){
+
+ //Instanciamos un StickyBlock pero lo inicializamos como cuerpo
+ const personajePrincipal = new PersonajeInicial(position = mainCharacterPosition)
+ personajePrincipal.iniciar()
+
+ //Instanciamos los compis
+ stickyBlockPositions.forEach({position =>
+ const stickyBlock = new StickyCompi(position = position)
+ stickyBlock.iniciar()
+ })
+ }
+
+ method addLampPosition(x,y){
+ lampPosition.add(game.at(x-1, y-1))
+ }
+
+ method drawTopLayer(){
+ lampPosition.forEach({pos =>
+ const lampara = new Lampara(position = pos)
+ lampara.iniciar()
+ })
+ }
+ }
+
+//------------------ Representaciones del GridMap ------------------
+//---------(Entorno)--------
+
+ //Vacio
+ object v{
+ method decode(_x,_y,_level){}
+ }
+
+ //Pared
+ object p{
+ method decode(x,y,_level){
+ const pared = new Pared(position = game.at(x, y))
+ pared.iniciar()
+ }
+ }
+
+ //Lamparas
+ object l{
+ method decode(x,y,level){
+ p.decode(x, y,level)
+ level.addLampPosition(x,y)
+ }
+ }
+
+ //Suelo
+ object _{
+ method decode(x,y,_level){
+ const suelo = new Suelo(position = game.at(x, y))
+ suelo.iniciar()
+ }
+ }
+
+ //Trampa
+ object o{
+ method decode(x,y,_level){
+ const agujero = new Agujero(position = game.at(x, y), estadoActual = true)
+ agujero.iniciar()
+ }
+ }
+
+ //Trampa
+ object x{
+ method decode(x,y,_level){
+ const agujero = new Agujero(position = game.at(x, y), estadoActual = false)
+ agujero.iniciar()
+ }
+ }
+
+ //Meta
+ object g{
+ method decode(x,y,level){
+
+ if(level.firstGoal()){
+ //Solo la primer meta generada por el nivel sera la encargada de evaluar si el nivel fue completado
+ level.firstGoal(false)
+ const metaValidadora = new MetaValidadora(position = game.at(x, y))
+ metaValidadora.iniciar()
+
+ }else{
+
+ const meta = new Meta(position = game.at(x, y))
+ meta.iniciar()
+ }
+
+ level.addGoalPosition(x,y)
+ }
+ }
+
+ object u{
+ method decode(x,y,_level){
+ const arrowPopUp = new OnlyVisual(image = "ArrowsPopUp.gif",position = game.at(x+2, y-1))
+ arrowPopUp.iniciar()
+ }
+ }
+
+//-------(Personajes)-------
+
+ //Personaje Principal
+ object m{
+ method decode(x,y,level){
+ //Guardo la posicion del personaje principal
+ level.mainCharacterPosition(game.at(x, y))
+
+ //Creo suelo donde Spawnea el personaje principal
+ _.decode(x, y,level)
+ }
+ }
+
+ //Compis
+ object z{
+ method decode(x,y,level){
+ //Guardo la posicion de los stickyBlocks
+ level.addStickyBlockPosition(x,y)
+
+ //Creo suelo donde Spawnea el personaje principal
+ _.decode(x, y,level)
+ }
+ }
+
+//*==========================| Niveles Instanciados |==========================
+
+ //Move Tutorial
+ const nivel1 = new Nivel(
+ initialGridMap = [
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v],
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v],
+ [v,v,v,v,p,p,p,p,p,p,p,p,p,p,p,v,v,v,v,v],
+ [v,v,v,v,p,_,_,_,_,p,_,_,_,_,p,v,v,v,v,v],
+ [v,v,v,v,p,_,m,_,_,p,_,_,_,_,p,v,v,v,v,v],
+ [v,v,v,v,l,_,_,_,_,_,_,_,g,_,p,v,v,v,v,v],
+ [v,v,v,v,p,_,_,_,_,_,_,_,_,_,p,v,v,v,v,v],
+ [v,v,v,v,p,_,_,_,_,_,_,_,_,_,p,v,v,v,v,v],
+ [v,v,v,v,p,p,p,p,p,p,p,p,p,p,p,v,v,v,v,v],
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,u,v,v,v,v]
+ ],
+ siguienteNivel = nivel2
+ )
+
+ //Friend Tutorial
+ const nivel2 = new Nivel(
+ initialGridMap = [
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v],
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v],
+ [v,v,v,v,p,p,p,p,p,p,p,p,p,p,p,v,v,v,v,v],
+ [v,v,v,v,p,_,_,_,_,p,_,z,_,_,p,v,v,v,v,v],
+ [v,v,v,v,p,_,m,_,_,p,_,_,_,_,p,v,v,v,v,v],
+ [v,v,v,v,l,_,_,_,_,_,_,g,_,_,l,v,v,v,v,v],
+ [v,v,v,v,p,_,_,_,z,_,_,g,g,_,p,v,v,v,v,v],
+ [v,v,v,v,p,_,_,_,_,_,_,_,_,_,p,v,v,v,v,v],
+ [v,v,v,v,p,p,p,p,p,p,p,p,p,p,p,v,v,v,v,v],
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v]
+ ],
+ siguienteNivel = nivel3
+ )
+
+ // Friends Levels
+ const nivel3 = new Nivel(
+ initialGridMap = [
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v],
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v],
+ [v,v,v,v,p,p,p,p,p,p,p,p,p,p,p,v,v,v,v,v],
+ [v,v,v,v,p,z,p,_,_,_,_,_,_,_,p,v,v,v,v,v],
+ [v,v,v,v,p,_,g,_,_,_,_,_,_,z,p,v,v,v,v,v],
+ [v,v,v,v,l,g,g,g,_,p,_,_,_,_,l,v,v,v,v,v],
+ [v,v,v,v,p,m,g,_,_,p,_,_,_,_,p,v,v,v,v,v],
+ [v,v,v,v,p,_,_,z,_,p,z,_,_,_,p,v,v,v,v,v],
+ [v,v,v,v,p,p,p,p,p,p,p,p,p,p,p,v,v,v,v,v],
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v]
+ ],
+ siguienteNivel = nivel4
+ )
+
+ const nivel4 = new Nivel(
+ initialGridMap = [
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v],
+ [v,v,v,p,p,p,p,p,p,p,p,p,p,p,p,p,p,v,v,v],
+ [v,p,p,p,z,_,_,_,_,_,_,_,_,_,_,_,p,p,p,v],
+ [v,p,_,z,_,_,_,_,_,_,z,_,_,_,_,_,_,_,p,v],
+ [v,p,_,_,g,_,_,_,_,p,_,_,_,_,_,_,_,_,p,v],
+ [v,l,_,_,g,g,m,_,_,p,p,p,_,_,z,_,_,_,l,v],
+ [v,p,_,_,g,g,g,_,_,_,p,p,_,_,_,_,_,_,p,v],
+ [v,p,_,_,_,_,_,_,_,_,z,p,_,_,_,_,_,_,p,v],
+ [v,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,v],
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v]
+ ],
+ siguienteNivel = nivel5
+ )
+
+ const nivel5 = new Nivel(
+ initialGridMap = [
+ [v,v,v,v,v,v,v,p,p,p,l,p,p,p,v,v,v,v,v,v],
+ [v,v,v,v,p,p,p,p,_,z,_,_,_,p,p,p,p,v,v,v],
+ [v,v,p,p,p,_,_,_,_,_,_,_,_,_,_,_,p,p,p,v],
+ [v,v,p,_,_,_,_,z,_,_,z,_,_,_,_,_,_,_,p,v],
+ [v,v,p,_,_,_,_,_,_,_,_,_,z,_,z,_,_,_,p,v],
+ [v,v,l,_,_,m,_,_,_,p,p,p,p,_,_,_,_,_,l,v],
+ [v,v,p,_,_,_,_,_,_,g,g,g,g,_,_,_,_,_,p,v],
+ [v,v,p,_,_,_,_,_,_,_,g,g,_,_,_,_,_,_,p,v],
+ [v,v,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,v],
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v]
+ ],
+ siguienteNivel = nivel6
+ )
+
+ // Holes Levels
+ const nivel6 = new Nivel(
+ initialGridMap = [
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v],
+ [v,v,v,v,p,p,p,p,p,p,p,p,p,p,p,p,p,v,v,v],
+ [v,v,v,p,p,_,_,_,_,_,_,_,_,_,_,_,p,p,v,v],
+ [v,v,v,p,_,_,_,_,_,_,_,_,_,_,_,_,_,p,v,v],
+ [v,v,v,p,_,m,_,_,z,_,o,_,z,_,_,_,_,p,v,v],
+ [v,v,v,p,_,_,_,_,_,_,_,_,_,_,_,_,_,p,v,v],
+ [v,v,v,p,_,_,_,_,_,g,p,g,_,_,_,_,_,p,v,v],
+ [v,v,v,p,p,_,_,_,_,_,p,_,_,_,_,_,p,p,v,v],
+ [v,v,v,v,p,p,p,p,p,p,p,p,p,p,p,p,p,v,v,v],
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v]
+ ],
+ siguienteNivel = nivel7
+ )
+
+ const nivel7 = new Nivel(
+ initialGridMap = [
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v],
+ [v,v,v,p,p,p,p,p,p,p,p,p,p,p,p,p,p,v,v,v],
+ [v,v,v,p,_,_,_,_,_,p,p,_,_,_,_,_,p,v,v,v],
+ [v,v,v,p,_,z,_,_,_,x,x,_,_,_,z,_,p,v,v,v],
+ [v,v,v,p,_,_,_,x,_,g,g,_,x,_,_,_,p,v,v,v],
+ [v,v,v,p,_,_,_,x,_,g,g,_,x,_,_,_,p,v,v,v],
+ [v,v,v,p,_,m,_,_,_,x,x,_,_,_,z,_,p,v,v,v],
+ [v,v,v,p,_,_,_,_,_,p,p,_,_,_,_,_,p,v,v,v],
+ [v,v,v,p,p,p,p,p,p,p,p,p,p,p,p,p,p,v,v,v],
+ [v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v]
+ ],
+ siguienteNivel = nivel8
+ )
+
+ const nivel8 = new Nivel(
+ initialGridMap = [
+ [v,v,v,v,p,p,p,p,p,p,p,p,p,p,p,p,v,v,v,v],
+ [v,v,v,p,p,_,_,_,_,z,_,_,_,_,_,p,p,v,v,v],
+ [v,v,v,p,_,_,_,_,_,_,_,_,_,_,_,_,p,v,v,v],
+ [v,v,v,p,_,_,_,_,x,_,x,_,_,_,_,_,p,v,v,v],
+ [v,v,v,p,_,_,z,_,_,x,_,_,z,_,_,_,p,v,v,v],
+ [v,v,v,p,_,_,_,_,x,_,x,_,_,_,_,_,p,v,v,v],
+ [v,v,v,p,_,_,_,_,_,m,_,_,_,g,_,_,p,v,v,v],
+ [v,v,v,p,_,_,_,_,_,_,_,_,_,g,p,g,p,v,v,v],
+ [v,v,v,p,p,_,_,_,_,z,_,_,_,_,p,g,p,v,v,v],
+ [v,v,v,v,p,p,p,p,p,p,p,p,p,p,p,p,p,v,v,v]
+ ],
+ siguienteNivel = nivel9
+ )
+
+ const nivel9 = new Nivel(
+ initialGridMap = [
+ [p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p],
+ [p,_,_,l,g,g,p,p,g,p,g,p,p,g,g,l,_,_,_,p],
+ [p,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,p],
+ [p,_,_,_,_,_,o,o,_,_,_,_,_,o,_,_,_,_,_,p],
+ [p,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,p],
+ [p,_,_,_,_,_,_,_,o,_,_,_,_,_,_,z,z,_,_,p],
+ [p,_,o,_,_,_,_,_,_,_,_,_,_,_,_,o,_,_,_,p],
+ [p,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,p],
+ [p,_,_,z,z,z,z,z,_,m,_,z,z,z,_,_,_,_,_,p],
+ [p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p]
+ ],
+ siguienteNivel = endCredits
+ )
+ object endCredits {
+ method iniciar(){
+ juegoStickyBlock.clear()
+ configTeclado.gameOn()
+ new OnlyVisual(image="End.png",position = game.at(8,1)).iniciar()
+ }
+ }
+
+
+
diff --git a/main.wpgm b/main.wpgm
deleted file mode 100644
index 4337325..0000000
--- a/main.wpgm
+++ /dev/null
@@ -1,16 +0,0 @@
-import wollok.game.*
-
-import pepita.*
-
-program PepitaGame {
- game.title("Pepita")
- game.height(10)
- game.width(10)
- game.cellSize(100)
-
- game.addVisual(pepita)
-
- keyboard.w().onPressDo({ pepita.fly(1) })
-
- game.start()
-}
diff --git a/mainStickyBlocks.wpgm b/mainStickyBlocks.wpgm
new file mode 100644
index 0000000..7f326a1
--- /dev/null
+++ b/mainStickyBlocks.wpgm
@@ -0,0 +1,8 @@
+import wollok.game.*
+
+import stickyBlocks.juegoStickyBlock
+
+program StickyBlock {
+ juegoStickyBlock.iniciar()
+ game.start()
+}
diff --git a/menuYTeclado.wlk b/menuYTeclado.wlk
new file mode 100644
index 0000000..b4e28dc
--- /dev/null
+++ b/menuYTeclado.wlk
@@ -0,0 +1,204 @@
+import stickyBlocks.*
+import levels.*
+
+//*==========================| MENU Inicial |==========================
+ object menu{
+ method iniciar(){
+ juegoStickyBlock.clear()
+
+ //Visuales
+ self.drawMenu()
+
+ //Teclado
+ configTeclado.menuOn()
+ }
+
+ method drawMenu(){
+ new OnlyVisual(image = "Logo.png", position = game.at(8,7)).iniciar()
+ levelMenu.iniciar()
+ }
+ }
+
+ object levelMenu{
+ const property position = game.at(7,4)
+ var levelMenuIsOpen = false
+ var image = "CloseMenu.png"
+
+ method image() = image
+
+ method iniciar(){
+ game.addVisual(self)
+ configTeclado.menuOn()
+ levelMenuIsOpen = false
+ image = "CloseMenu.png"
+ }
+
+ method toggle() = if(levelMenuIsOpen) self.close() else self.open()
+
+ method close(){
+ image = "CloseMenu.png"
+ configTeclado.menuOn()
+ levelMenuIsOpen = false
+ }
+
+ method open(){
+ image = "OpenMenu.png"
+ configTeclado.levelMenuOn()
+ levelMenuIsOpen = true
+ }
+ }
+
+ class OnlyVisual{
+ method iniciar(){
+ game.addVisual(self)
+ }
+
+ var property image
+
+ const property position
+ }
+
+//*==========================| Config Teclado |==========================
+ object configTeclado{
+
+ var teclado = tecladoJuego
+
+ method iniciar(){
+
+ //* GAME ON:
+
+ //Movimientos:
+ keyboard.up().onPressDo({teclado.up()})
+ keyboard.down().onPressDo({teclado.down()})
+ keyboard.left().onPressDo({teclado.left()})
+ keyboard.right().onPressDo({teclado.right()})
+
+ //unDo:
+ keyboard.control().onPressDo({teclado.control()})
+
+ //Menu en nivel:
+ keyboard.m().onPressDo({teclado.m()})
+ keyboard.r().onPressDo({teclado.r()})
+
+ //* MENU ON:
+ keyboard.p().onPressDo({teclado.p()})
+ keyboard.l().onPressDo({teclado.l()})
+
+ //* LEVEL MENU ON:
+ keyboard.num1().onPressDo({teclado.num1()})
+ keyboard.num2().onPressDo({teclado.num2()})
+ keyboard.num3().onPressDo({teclado.num3()})
+ keyboard.num4().onPressDo({teclado.num4()})
+ keyboard.num5().onPressDo({teclado.num5()})
+ keyboard.num6().onPressDo({teclado.num6()})
+ keyboard.num7().onPressDo({teclado.num7()})
+ keyboard.num8().onPressDo({teclado.num8()})
+ keyboard.num9().onPressDo({teclado.num9()})
+
+ }
+
+ method gameOn(){
+ teclado = tecladoJuego
+ }
+
+ method menuOn(){
+ teclado = tecladoMenu
+ }
+
+ method levelMenuOn(){
+ teclado = tecladoSelectorNivel
+ }
+ }
+
+ class TecladoBase{
+ method up(){}
+ method down(){}
+ method left(){}
+ method right(){}
+
+ method control(){}
+
+ method m(){}
+ method r(){}
+ method p(){}
+ method l(){}
+
+ method num1(){}
+ method num2(){}
+ method num3(){}
+ method num4(){}
+ method num5(){}
+ method num6(){}
+ method num7(){}
+ method num8(){}
+ method num9(){}
+ }
+
+ object tecladoJuego inherits TecladoBase{
+ override method up(){
+ cuerpo.moverCuerpo(arriba)
+ }
+ override method down(){
+ cuerpo.moverCuerpo(abajo)
+ }
+ override method left(){
+ cuerpo.moverCuerpo(izquierda)
+ }
+ override method right(){
+ cuerpo.moverCuerpo(derecha)
+ }
+
+ override method control(){
+ juegoStickyBlock.unDo()
+ }
+
+ override method m(){
+ menu.iniciar()
+ }
+
+ override method r(){
+ juegoStickyBlock.reset()
+ }
+ }
+
+ class TecladoMenu inherits TecladoBase{
+ override method p(){
+ juegoStickyBlock.nivelActual().iniciar()
+ }
+
+ override method l(){
+ levelMenu.toggle()
+ }
+ }
+
+ const tecladoMenu = new TecladoMenu()
+
+ object tecladoSelectorNivel inherits TecladoMenu{
+ override method num1(){
+ nivel1.iniciar()
+ }
+ override method num2(){
+ nivel2.iniciar()
+ }
+ override method num3(){
+ nivel3.iniciar()
+ }
+ override method num4(){
+ nivel4.iniciar()
+ }
+ override method num5(){
+ nivel5.iniciar()
+ }
+ override method num6(){
+ nivel6.iniciar()
+ }
+ override method num7(){
+ nivel7.iniciar()
+ }
+ override method num8(){
+ nivel8.iniciar()
+ }
+ override method num9(){
+ nivel9.iniciar()
+ }
+ }
\ No newline at end of file
diff --git a/package.json b/package.json
index a879289..e07cd4e 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
{
- "name": "2024-o-tpijuego",
+ "name": "stickyBlocks",
"version": "1.0.0",
"resourceFolder": "assets",
"wollokVersion": "4.0.0",
- "author": "usuario",
+ "author": "facundo",
"license": "ISC"
}
diff --git a/pepita.wlk b/pepita.wlk
deleted file mode 100644
index 8763973..0000000
--- a/pepita.wlk
+++ /dev/null
@@ -1,16 +0,0 @@
-object pepita {
- var energy = 100
- const position = new MutablePosition(x=0, y=0)
-
- method image() = "golondrina.png"
- method position() = position
-
- method energy() = energy
-
- method fly(minutes) {
- energy = energy - minutes * 3
- position.goRight(minutes)
- position.goUp(minutes)
- }
-
-}
\ No newline at end of file
diff --git a/pruebas.wtest b/pruebas.wtest
deleted file mode 100644
index 7342cd1..0000000
--- a/pruebas.wtest
+++ /dev/null
@@ -1,9 +0,0 @@
-import pepita.*
-
-describe "group of tests for pepita" {
-
- test "pepita has initial energy" {
- assert.equals(100, pepita.energy())
- }
-
-}
\ No newline at end of file
diff --git a/stickyBlocks.wlk b/stickyBlocks.wlk
new file mode 100644
index 0000000..6679117
--- /dev/null
+++ b/stickyBlocks.wlk
@@ -0,0 +1,432 @@
+import levels.*
+import menuYTeclado.*
+
+object juegoStickyBlock {
+
+ var property nivelActual = nivel1
+ var movimientos = []
+
+ //Config Audio
+ const music = game.sound("InideGame.mp3")
+
+ method iniciar(){
+
+ //Set game properties
+ game.title("StickyBlock")
+ game.height(12)
+ game.width(24)
+ game.boardGround("Fondo.png")
+
+ //Set Background Audio
+ music.shouldLoop(true)
+ music.volume(0.3)
+ music.play()
+
+
+ //inicializo teclado
+ configTeclado.iniciar()
+
+ //Inicio el menu
+ menu.iniciar()
+ }
+
+ method reset(){
+ movimientos.forEach({_=> self.unDo()}) // Ejecuta unDo() por la cantidad de movimientos ejecutados
+ }
+
+ method clear(){
+ cuerpo.clear()
+ movimientos.clear()
+ game.allVisuals().forEach({visual => game.removeVisual(visual)})
+ }
+
+ method siguienteNivel(){
+ nivelActual = nivelActual.siguienteNivel()
+ nivelActual.iniciar()
+ }
+
+ method addMove(movimiento){
+ movimientos = [movimiento] + movimientos
+ }
+
+ method unDo(){
+ if(!movimientos.isEmpty()){
+ const move = movimientos.head()
+ movimientos = movimientos.drop(1)
+ move.unDo()
+ }
+ }
+}
+
+//*==========================| Cuerpo |==========================
+ object cuerpo{
+
+ // Cuerpo
+ const property compis = []
+
+ method clear(){
+ compis.clear()
+ }
+
+ method agregarACuerpo(compi){
+ compis.add(compi)
+ }
+
+ method eliminarCompi(compi){
+ compis.remove(compi)
+ }
+
+ method moverCuerpo(movimiento){
+
+ const cuerpoPuedeAvanzar = compis.all({compi => compi.puedeAvanzar(movimiento.nuevaPosicion(compi))}) && !compis.isEmpty()
+
+ if(cuerpoPuedeAvanzar){
+ juegoStickyBlock.addMove(movimiento) // Agrega el movimiento al stack de movimientos
+
+ self.ejecutarMovimiento(movimiento) //Mueve a los elementos del cuerpo
+
+ const moveSound = game.sound("drag1.mp3")
+ moveSound.volume(0.07)
+ moveSound.play()
+
+ compis.forEach({compi => compi.collideWith()}) // Ejecuta Nuesto "Collider"
+ }
+ }
+
+ method ejecutarMovimiento(movimiento){
+ compis.forEach({compi => compi.moveTo(movimiento)})
+ }
+
+ // Victoria
+ method victoriaValida() = juegoStickyBlock.nivelActual().cuerpoSobreMeta() // Verifica si existen compis sobre cada meta
+ }
+
+//*========================| StickyBlock |=======================
+ class StickyBlock{
+
+ //Imagen
+ var property image = "RojoCerrado.png"
+
+ //Posicion
+ var property position
+
+ method iniciar(){
+ game.addVisual(self)
+ }
+
+ //Colision
+ method esPisable() = true
+
+ //Puede avanzar
+ method puedeAvanzar(posicion) = game.getObjectsIn(posicion).all({objeto => objeto.esPisable()})
+
+ method moveTo(movimiento){
+ position = movimiento.nuevaPosicion(self)
+ }
+
+ method collideWith(){
+ game.getObjectsIn(position).forEach({objeto => objeto.interactuarConPersonaje(self)}) //? Utilizamos esto como onCollideDo ya que on colide se saltea colisiones y va mas lento
+ }
+
+ //Desaparecer 🚙😥🔫
+ method desaparecer(){
+ game.removeVisual(self)
+ cuerpo.eliminarCompi(self)
+
+ //Se agrega a movimientos para poder deshacer
+ juegoStickyBlock.addMove(self)
+ }
+
+ //Aparecer
+ method aparecer(){
+ game.addVisual(self)
+ cuerpo.agregarACuerpo(self)
+
+ //Deshace el movimiento anterior
+ juegoStickyBlock.unDo()
+ }
+
+ method interactuarConPersonaje(pj){}
+ }
+
+ //--------- Personaje Inicial ---------
+ class PersonajeInicial inherits StickyBlock{
+
+ override method iniciar(){
+
+ super()
+
+ cuerpo.agregarACuerpo(self)
+
+ image = "RojoParpadea.gif"
+ }
+
+ method unDo(){
+ self.aparecer()
+ }
+ }
+
+ //--------- Sticky Compis ---------
+ class StickyCompi inherits StickyBlock{
+
+ //Genera las HitBox alrededor del StickyBlock
+ const hitBoxes = [
+ new HitBox(padre = self, position = position.up(1)),
+ new HitBox(padre = self, position = position.down(1)),
+ new HitBox(padre = self, position = position.left(1)),
+ new HitBox(padre = self, position = position.right(1))
+ ]
+
+ override method iniciar(){
+ super()
+ self.iniciarHitBoxes()
+ }
+
+ //Setea el compi como elemento del cuerpo del personaje principal
+ method setAsCuerpo(){
+
+ const attachSound = game.sound("pop1.mp3")
+ attachSound.volume(0.15)
+ attachSound.play()
+
+ self.eliminarHitBoxes()
+
+ cuerpo.agregarACuerpo(self)
+
+ self.collideWith()
+
+ image = "RojoParpadea.gif"
+
+ juegoStickyBlock.addMove(self) //Se agrega a movimientos para poder deshacer
+ }
+
+ method iniciarHitBoxes(){
+ hitBoxes.forEach({hitBox => hitBox.iniciar()})
+ }
+
+ method eliminarHitBoxes(){
+ hitBoxes.forEach({hitBox => hitBox.eliminar()})
+ }
+
+ method desanclar(){
+
+ cuerpo.eliminarCompi(self) //1. Lo elimino del cuerpo
+ juegoStickyBlock.unDo() //2. Hago el movimiento anterior
+ self.iniciarHitBoxes() //3. Agrego la hitbox
+
+ image = "RojoCerrado.png"
+ }
+
+ method unDo(){
+ //Valida si se esta esta haciendo el unDo de la caida en una Trampa/Agujero o de un seteo como cuerpo
+ if(game.hasVisual(self)){self.desanclar()}else{self.aparecer()}
+ }
+ }
+
+ //----- HitBox
+ class HitBox{
+
+ const padre
+
+ //Posicion
+ const property position
+
+ method iniciar(){
+ game.addVisual(self)
+ }
+
+ method eliminar(){
+ game.removeVisual(self)
+ }
+
+ //Colision
+ method esPisable() = true
+
+ method interactuarConPersonaje(pj){
+
+ //Setea como compi al padre
+ padre.setAsCuerpo()
+ }
+ }
+
+ //----------------| Movimiento Colectivo |----------------
+ object arriba {
+ method nuevaPosicion(objeto) = objeto.position().up(1)
+ method unDo(){cuerpo.ejecutarMovimiento(abajo)}
+ }
+
+ object abajo {
+ method nuevaPosicion(objeto) = objeto.position().down(1)
+ method unDo(){cuerpo.ejecutarMovimiento(arriba)}
+ }
+
+ object izquierda {
+ method nuevaPosicion(objeto) = objeto.position().left(1)
+ method unDo(){cuerpo.ejecutarMovimiento(derecha)}
+ }
+
+ object derecha {
+ method nuevaPosicion(objeto) = objeto.position().right(1)
+ method unDo(){cuerpo.ejecutarMovimiento(izquierda)}
+ }
+
+ //PD: Los unDo directamente ejeceutan el movimiento contrario (sin pasar por la validacion ni del collider de MoverCuerpo)
+
+//*==========================| Entorno |=========================
+ class Meta{
+
+ //Posicion
+ const property position
+
+ //Imagen
+ method image() = "Salida.png"
+
+ method iniciar(){
+ game.addVisual(self)
+ }
+
+ //Colision
+ method esPisable() = true
+
+ method interactuarConPersonaje(pj){
+ }
+ }
+
+ class MetaValidadora inherits Meta{
+ override method interactuarConPersonaje(pj){
+ //Verifica si ha ganado el nivel
+ const ganoNivel = cuerpo.victoriaValida()
+
+ if (ganoNivel){
+
+ //Sonido de Victoria
+ const winSound = game.sound("Victoria.mp3")
+ winSound.volume(0.1)
+ winSound.play()
+
+ juegoStickyBlock.siguienteNivel()
+
+ }
+ }
+ }
+
+ class Pared{
+
+ //Imagen
+ const images = ["Ladrillo1.png","Ladrillo2.png","Ladrillo3.png","Ladrillo4.png"]
+ var property image = ""
+
+ //Posicion
+ const property position
+
+ method iniciar(){
+ self.choseImage()
+ game.addVisual(self)
+ }
+
+ method choseImage(){
+ image = images.randomized().head()
+ }
+
+ //Colision
+ method esPisable() = false
+
+ method interactuarConPersonaje(pj){}
+
+ }
+
+ class Suelo{
+
+ //Imagen
+ const images = ["Piso1.png","Piso1.png","Piso1.png","Piso1.png","Piso1.png","Piso1.png","Piso1.png","Piso1.png", "Piso2.png", "Piso3.png"]
+ var property image = ""
+
+ //Posicion
+ const property position
+
+ method iniciar(){
+ self.choseImage()
+ game.addVisual(self)
+ }
+
+ method choseImage(){
+ image = images.randomized().head()
+ }
+
+ //Colision
+ method esPisable() = true
+
+ method interactuarConPersonaje(pj){}
+
+ }
+
+ class Lampara{
+
+ //Posicion
+ const property position
+
+ //Imagen
+ method image() = "Lampara.png"
+
+
+ method iniciar(){
+ game.addVisual(self)
+ }
+
+ //Colision
+ method esPisable() = true
+
+ method interactuarConPersonaje(pj){}
+ }
+
+ class Agujero{
+
+ var estadoActual // true = abierta
+
+ //Posicion
+ const property position
+
+ //Imagen
+ const images = ["Trampa2.png","Trampa3.png","Trampa4.png","Trampa5.png"]
+ var property image = ""
+
+ method iniciar(){
+
+ self.choseImage()
+ game.addVisual(self)
+ }
+
+ method choseImage(){
+ image = if(estadoActual) "Trampa1.png" else images.randomized().head()
+ }
+
+ //Colision
+ method esPisable() = true
+
+ method activar(){
+ image = "Trampa1.png"
+ estadoActual = true
+ }
+
+ //Este unDo es para desactivar la trampa --> En el caso de deshacer la eliminacion de un personaje se encarga el StickyBlock
+ method unDo(){
+ estadoActual = false
+ self.choseImage()
+
+ //Se ejecuta tambien el movimiento anterior
+ juegoStickyBlock.unDo()
+ }
+
+ method interactuarConPersonaje(compi){
+
+ if(estadoActual){
+ compi.desaparecer()
+ } else {
+ self.activar()
+ //Se agrega a movimientos para poder deshacer
+ juegoStickyBlock.addMove(self)
+ }
+ }
+ }
+
+
\ No newline at end of file
diff --git a/stickyTest.wtest b/stickyTest.wtest
new file mode 100644
index 0000000..2502054
--- /dev/null
+++ b/stickyTest.wtest
@@ -0,0 +1,101 @@
+import wollok.game.*
+import stickyBlocks.*
+import levels.*
+import menuYTeclado.*
+
+describe "Tests StickyBlock (individual)" {
+
+ method initialize(){
+ game.clear()
+ }
+
+ test "El StickyBlock se mueve correctamente." {
+
+ const personajePrincipal = new PersonajeInicial(position = game.at(0,0))
+ personajePrincipal.iniciar()
+
+ personajePrincipal.moveTo(arriba)
+ assert.equals(game.at(0,1), personajePrincipal.position())
+ }
+
+ test "El StickyBlock no se mueve al colisionar con una pared." {
+
+ const personajePrincipal = new PersonajeInicial(position = game.at(0,0))
+ personajePrincipal.iniciar()
+
+ const pared = new Pared(position = game.at(0,1))
+ pared.iniciar()
+
+ cuerpo.moverCuerpo(arriba)
+ assert.equals(game.at(0,0), personajePrincipal.position())
+ }
+}
+describe "Tests del cuerpo." {
+
+ method initialize(){
+ game.clear()
+ }
+
+ test "Compi se une al cuerpo." {
+
+ //Seteo el curpo con un compi y un personaje principal
+ const compi = new StickyCompi(position = game.at(0,2))
+ compi.iniciar()
+
+ const personajePrincipal = new PersonajeInicial(position = game.at(0,0))
+ personajePrincipal.iniciar()
+
+ //Muevo el cuerpo, tomo al compi y bajo
+ cuerpo.moverCuerpo(arriba)
+ cuerpo.moverCuerpo(abajo)
+
+ assert.equals(game.at(0,0), personajePrincipal.position())
+ assert.equals(game.at(0,1), compi.position())
+ }
+
+ test "El cuerpo se mueve correctamente." {
+
+ //Seteo el cuerpo con un compi y un personaje principal
+ const compi = new StickyCompi(position = game.at(0,1))
+ compi.iniciar()
+ compi.setAsCuerpo()
+
+ const personajePrincipal = new PersonajeInicial(position = game.at(0,0))
+ personajePrincipal.iniciar()
+
+ //Muevo el cuerpo
+ cuerpo.moverCuerpo(arriba)
+
+ assert.equals(game.at(0,1), personajePrincipal.position())
+ assert.equals(game.at(0,2), compi.position())
+ }
+
+ test "El cuerpo no se mueve si algun compi colisiona con una pared." {
+
+ //Seteo el cuerpo con un compi y un personaje principal
+ const compi = new StickyCompi(position = game.at(1,0))
+ compi.iniciar()
+ compi.setAsCuerpo()
+
+ const personajePrincipal = new PersonajeInicial(position = game.at(0,0))
+ personajePrincipal.iniciar()
+
+ //Seteo una pared que colisionara con el cuerpo
+ new Pared(position = game.at(0,1)).iniciar()
+
+ cuerpo.moverCuerpo(arriba)
+ assert.equals(game.at(0,0), personajePrincipal.position())
+ assert.equals(game.at(1,0), compi.position())
+ }
+
+ test "Se revierten el movimiento del cuerpo al ejecutar unDo." {
+ const personajePrincipal = new PersonajeInicial(position = game.at(0,0))
+ personajePrincipal.iniciar()
+
+ cuerpo.moverCuerpo(arriba)
+
+ juegoStickyBlock.unDo()
+
+ assert.equals(game.at(0,0), personajePrincipal.position())
+ }
+}