-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feedback #1
base: feedback
Are you sure you want to change the base?
Feedback #1
Changes from 37 commits
8393451
1795fdf
9e855f2
405bcfd
17726ec
d58e929
f72720b
b5a9254
497184b
9398e35
f2159d2
8b9c2a4
44fe050
da862e8
ddb7e98
1d89a71
ce96b96
d0c9126
be5b03b
c156af6
d1972d1
82a9b7b
58e0d31
ada2d43
1622628
f093712
ea84785
6f7c04d
d190b91
b51e224
d10a273
03b7af6
7ca087a
fdff84e
f456a8c
142f6df
d308cee
3e03027
fedc1dc
f362f41
4b87bcf
ede386d
8cf5b1b
d0b21c8
eb578f1
2a9db8b
bbb54bc
d0b4718
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
object inventarioHUD { | ||
const property image = "franja_inventario.png" | ||
const property position = game.origin() | ||
const inventario = [] | ||
|
||
method tomar(item) { | ||
if (inventario.size() < 3 && item.agarrable()) { | ||
inventario.add(item) | ||
item.position(game.at(12 + inventario.size(), 0)) | ||
} | ||
} | ||
|
||
method usar(pos){ | ||
const item = inventario.get(pos) | ||
item.accion() | ||
inventario.remove(item) | ||
game.removeVisual(item) | ||
} | ||
|
||
method moverItems() { | ||
var i = 1 | ||
inventario.forEach({ item => | ||
item.position(game.at(12 + i, 0)) | ||
i += 1 | ||
}) | ||
} | ||
} | ||
|
||
object vidaHUD { | ||
var property image = "vida_full.png" | ||
const property position = game.origin() | ||
method actualizarVida(entidad){ | ||
if (entidad.vida() > 80) | ||
{ | ||
self.image("vida_full.png") | ||
} | ||
else if(entidad.vida() > 60 ) | ||
{ | ||
self.image("vida_4quintos.png") | ||
} | ||
else if(entidad.vida() > 40) { | ||
self.image("vida_3quintos.png") | ||
} | ||
else if(entidad.vida() > 20) { | ||
self.image("vida_2quintos.png") | ||
} | ||
else if(entidad.vida() > 0){ | ||
self.image("vida_1quinto.png") | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,36 @@ | ||
# (reemplazar nombre de juego acá) | ||
# The Legend Of Alf | ||
|
||
UTN - Facultad Regional Buenos Aires - Materia Paradigmas de Programación | ||
|
||
## Equipo de desarrollo: | ||
|
||
- completar... | ||
- completar... | ||
|
||
|
||
- Dante Ezequiel Samudio (SamDante) | ||
- Joaquin Mariosa Rendon (JoaquinMariosa) | ||
- Leandro Leones (LeandroLeones) | ||
- Pablo La Rocca (Pabloutndev) | ||
- Gonza Galarza (GonzaGalarza) | ||
## Capturas | ||
|
||
![pepita](assets/golondrina.png) | ||
![alf](assets/alf_sprite.png) | ||
![cofre](assets/cofre.png) | ||
![hamburguesa](assets/hamburguesa.png) | ||
![espada](assets/espada.png) | ||
![llave](assets/llave.png) | ||
![enemigo](assets/placeholder_attack.png) | ||
|
||
## Reglas de Juego / Instrucciones | ||
|
||
(completar...) | ||
- Esta basado en The Legend of Zelda. Existen enemigos que se pueden atacar objetos para obtener y un jefe final para derrotar. | ||
- Alf tiene una cierta cantidad de vida que puede ir variando a lo largo de la partida. | ||
- Hay dos mapas para recorrer: uno principal (la superficie) y una dungeon. | ||
- Alf cuenta con un arma con la cual puede realizar daño a los enemigos que encuentre en su camino. | ||
|
||
## Controles: | ||
|
||
- `W` para... | ||
|
||
- Las flechas para moverse | ||
- `Z` para atacar | ||
- `X` para agarrar items | ||
- `E` para abrir puerta | ||
- `A` para utilizar el primer item del inventario | ||
- `S` para utilizar el segundo item del inventario | ||
- `D` para utilizar el tercer item del inventario |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import items.* | ||
import HUD.* | ||
import mapa.* | ||
|
||
object alf { | ||
var property vida = 100 | ||
var property position = game.at(0,1) | ||
var property image = "alf_sprite.png" | ||
var property danio = 20 | ||
var property habitacionActual = h1 // Empieza en h1 | ||
|
||
method position() = position | ||
|
||
method curarse(curacion) { | ||
vida = (vida + curacion).min(100) | ||
vidaHUD.actualizarVida(self) | ||
} | ||
|
||
method danio(danioExtra) { | ||
danio += danioExtra | ||
} | ||
|
||
method atacar(enemigo) | ||
{ | ||
if ( enemigo.position().distance(self.position()) == 1 ) | ||
{ | ||
enemigo.recibirDanio(self) | ||
game.say(self,"Japish ") | ||
} | ||
} | ||
|
||
method recibirDanio(enemigo) { | ||
vida -= enemigo.danio() | ||
vidaHUD.actualizarVida(self) | ||
self.morir() | ||
} | ||
|
||
method morir() { | ||
if(vida <= 0){ | ||
game.removeVisual(self) | ||
} | ||
} | ||
|
||
method utilizar(pos) { | ||
inventarioHUD.usar(pos) | ||
inventarioHUD.moverItems() | ||
} | ||
|
||
method agarrar(item) { | ||
inventarioHUD.tomar(item) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import wollok.game.* | ||
import main.* | ||
import alf.* | ||
|
||
class Enemigo { | ||
var property image | ||
const agarrable = false | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ¡Estas decisión de diseño, nos puede traer inconvenientes! Principalmente conceptos de polimorfismos se pueden ver afectados, ya que se espera que cada objeto gestione su comportamiento específico sin necesidad de verificaciones adicionales. Además, ¿qué pasaría si en algún momento agrego NPCs al sistema? Nuevamente, tendría que definir si son "agarrables" o no, lo que implica que, por cada nueva entidad, tendría que repetir esta misma decisión. |
||
var property vida | ||
var property danio | ||
const x_inicial | ||
const y_inicial | ||
const movete_x | ||
const movete_y | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ¡Bien! Esto es una decision de diseño, que nos puede traer ciertas consecuencias. |
||
var position = game.at(x_inicial, y_inicial) | ||
var property puedoAtacar = true | ||
method position() = position | ||
method danio() = danio | ||
|
||
// Revisar metodos de atacar y recibirDanio tanto en Alf como en los enemigos | ||
method atacar(alf) { | ||
if (puedoAtacar) { | ||
alf.recibirDanio(self) | ||
puedoAtacar = false | ||
game.schedule(3000, {self.puedoAtacar(true)}) | ||
} | ||
} | ||
|
||
// ENEMIGO | ||
var count = 0 | ||
var flag_1 = 0 | ||
var flag_2 = 1 | ||
var flag_3 = 1 | ||
var flag_4 = 1 | ||
|
||
method movete() { | ||
// 3,3 4x2 | ||
// 7,5 | ||
var p_x = position.x() | ||
var p_y = position.y() | ||
|
||
if ( flag_1 == 0 ) | ||
{ | ||
count += 1 | ||
position = game.at(p_x + 1, p_y) | ||
if(count == movete_x) { | ||
flag_1 = 1 | ||
flag_2 = 0 | ||
count = 0 | ||
} | ||
} | ||
else if ( flag_2 == 0 ) | ||
{ | ||
count += 1 | ||
position = game.at(p_x, p_y + 1) | ||
if(count == movete_y) { | ||
flag_2 = 1 | ||
flag_3 = 0 | ||
count = movete_x | ||
} | ||
} | ||
else if ( flag_3 == 0 ) | ||
{ | ||
count -= 1 | ||
position = game.at(p_x - 1, p_y) | ||
if(count == 0) { | ||
flag_3 = 1 | ||
flag_4 = 0 | ||
count = movete_y | ||
} | ||
} | ||
else if ( flag_4 == 0 ) | ||
{ | ||
count -= 1 | ||
position = game.at(p_x, p_y - 1) | ||
if(count == 0) { | ||
flag_4 = 1 | ||
flag_1 = 0 | ||
} | ||
} | ||
|
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Siguiendo el análisis anterior, podemos ver cómo se justifica la decisión de diseño que tomamos. ¿Qué podemos notar? Para empezar, nuestro Enemigo conserva varios atributos internos que son importantes para su movimiento. Sin embargo, definir el tipo de movimiento al inicializarlo puede ser algo rígido, ya que obliga a recordar siempre el patrón que debe seguir. ¿Y si nos equivocamos en esa elección inicial? Una solución acorde a nuestro paradigma actual, seria delegar la lógica a un objeto, de la siguiente manera: class Enemigo {
// Opcion 1: movimientoCuadrado es una object que por limites de celdas genera un mov cuadrado
const movimiento = movimientoCuadrado
// Opcion 2: movimientoCuadrado es un wrapper object de una coleccion de movimientos: [abajo, izquierda, arriba, derecha]
const movimiento = movimientoCuadrado
method moverser() {
movimiento.actualizarPosicionDe(self)
}
} ¿Qué estamos logrando con esto? 👀 Un enemigo, no necesitaba saber cómo se mueve en detalle, solo sabe que tiene un objeto Movimiento que se encarga de esa lógica. Esto facilita el manteamiento, ya que los cambios que se hagan a futuros se pueden hacer dentro de Movimiento sin afectar a lógica de los Enemigos. Temas como: Polimorfismo - Encapsulamiento - Abstracción se están poniendo práctica. |
||
|
||
method recibirDanio(alf) { | ||
vida -= alf.danio() | ||
self.morir() | ||
} | ||
|
||
method morir() { | ||
if(vida <= 0){ | ||
game.removeVisual(self) | ||
self.puedoAtacar(false) | ||
alf.habitacionActual().enemigosDisponibles().remove(self) | ||
alf.habitacionActual().refrescarEnemigos() | ||
} | ||
// Condicion para ganar el juego | ||
if(self == jefe) { | ||
game.stop() | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ¡Bien! Misma corrección que hicimos frente a preguntar quien soy. |
||
|
||
// Crear instancias | ||
const enemigo1 = new Enemigo(image = "placeholder_attack.png", vida = 100, danio = 20, x_inicial = 5, y_inicial = 3, movete_x = 3, movete_y = 3) | ||
const enemigo2 = new Enemigo(image = "placeholder_attack.png", vida = 100, danio = 20, x_inicial = 5, y_inicial = 4, movete_x = 2, movete_y = 2) | ||
const jefe = new Enemigo(image = "placeholder_attack_jefe.png", vida = 500, danio = 50, x_inicial = 3, y_inicial = 3, movete_x = 4, movete_y = 2) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import HUD.* | ||
import main.posicionAleatoria | ||
import mapa.* | ||
|
||
import alf.* | ||
|
||
class Item { | ||
const property image | ||
const property agarrable = true | ||
var property position = posicionAleatoria.calcular() | ||
method accion() | ||
} | ||
|
||
class ItemOfensivo inherits Item { | ||
const property danioExtra | ||
override method accion() { | ||
alf.danio(danioExtra) | ||
} | ||
} | ||
|
||
class ItemDeCuracion inherits Item { | ||
const property curacion | ||
override method accion() { | ||
alf.curarse(curacion) | ||
} | ||
} | ||
|
||
class ItemDeApertura inherits Item { | ||
const abreA | ||
override method accion() { | ||
abreA.accion() | ||
} | ||
} | ||
|
||
class ItemDeAlmacenamiento inherits Item (agarrable = false) { | ||
override method accion() { | ||
if(alf.position().distance(self.position()) == 1) { | ||
alf.habitacionActual().itemsDisponibles().remove(self) | ||
alf.habitacionActual().itemsDisponibles().add(llaveJefe) | ||
game.addVisual(llaveJefe) | ||
game.removeVisual(self) | ||
} | ||
} | ||
} | ||
|
||
const espada = new ItemOfensivo(image = "espada.png", danioExtra = 20, position = game.at(11,6)) | ||
const hamburgesa = new ItemDeCuracion(image = "hamburguesa.png", curacion = 50, position = game.at(12,6)) | ||
const cofre = new ItemDeAlmacenamiento(image = "cofre.png", position = game.at(14,6)) | ||
const llave = new ItemDeApertura(abreA = cofre, image = "llave.png", position = game.at(13,6)) | ||
const llaveJefe = new ItemDeApertura(abreA = puerta3, image = "llaveJefe.png", position = cofre.position()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
¡Bien! Esto es un enfoque interesante, para ir actualizando la vida del Hub.
Nuestra pregunta es, ¿que pasa si quisiera agregar nuevos estados?
Voy a tener que realizar otras comparaciones, ¿no?
¡Seguramente que si! Generandome que el código sea dificil de mantener, y hasta de leer. Una segurencia que podemos realizar, es delegar estos ¨estados¨ a una colección, y encontrar el más adecuado frente al estado actual de Alf.
Otro enfoque aún más simple, es crear una formula que calcule el "nivel" de vida en función del porcentaje de vida del personaje, y luego usar ese valor para construir dinámicamente el nombre del archivo de imagen.