Clases heredadas en C# y Unity

jalsimoo

Veamos. No posteo mucho aquí, pero creo que en cuanto a desarrollo de videojuegos aquí hay bastante personal cualificado.

Estoy en mitad de un juego 2D con Unity. Es un "plataformas" (vamos a dejarlo ahí), para que os pongáis en situación. Pues bien, obviamente tengo enemigos, pero tengo de diferentes tipos. Tengo estos tipos:
-Caminantes: si los tocas te quitan vida.
-Shooters: disparan y si tocas o a ellos o el disparo te quitan vida.
-Voladores: si los tocas te quitan vida.

Bien. Obviamente lo más lógico para tratarlos es crear una clase Enemigo y que las demás hereden de ella (EnemigoVolador, EnemigoShooter, EnemigoCaminante). El problema es que al principio no me lo planteé así y ahora tengo un poco de cacao. Veamos. Todos los enemigos tienen una vida y un daño que ejercen. El comportamiento varía, pero esos 2 atributos siempre están. El caso es que tengo la detección del daño en el héroe. Al héroe le digo que si toca a algún enemigo, llame a la función getDamage que está en la clase base Enemigo para saber cuánta vida he de quitarle.

Y aquí viene mi pregunta: A la hora de añadirle el Script Enemigo, ¿he de meterle el base o el específico? Lo digo porque tanto el daño como la vida quería hacerlos variables públicas y si dichas variables están en la clase base Enemigo... no podré configurarlo desde el editor, ¿no?

Espero que se entienda el rollo que he soltado y me podáis ayudar :D
Más adelante ya pondré fotos y cosas del juego.

EnderFX

Ahora mismo no estoy en casa para probarlo, pero es posible/probable que si defines daño y vida como variables públicas de Enemigo, y luego añades un script EnemigoVolador que extienda de Enemigo, probablemente el inspector del editor sea lo suficientemente listo como para mostrarte las variables públicas de la clase base. Todo sería probar.

Como último recurso, y esto ya es más una ñapa, podrías intentar crear dos variables públicas xDanio y xVida (sustituye x por caracteres a tu gusto) en EnemigoVolador, EnemigoCaminante... y en el constructor de la clase asignar estos valores a las variables de la clase Base. No estoy seguro de si funcionaría bien, pero es una chapuza ya que tienes que redefinir estos xVida y xDanio en todos los descendientes de Enemigo :S.

1 respuesta
r2d2rigo

#1 esa seria la manera de pensar en la POO tradicional, pero Unity usa el sistema basado en componentes, asi que... por que no haces un componente para la funcionalidad compartida del enemigo (vida y daño), y luego otros componentes independientes que definan el comportamiento (volar, andar, disparar)? Cada enemigo seria un GameObject con un comportamiento compartido y uno especifico.

Aparte que te recomiendo que la deteccion de colision y el daño lo hagas en el enemigo para mayor claridad del codigo.

2 2 respuestas
jalsimoo

#2 Esta es la manera que se me ha ocurrido y la vía que había tomado. El editor no muestra automáticamente las variables, con lo que es un peñazo, pero funcionar funciona...

#3 A qué te refieres con componentes? Te refieres a scripts diferentes?

1 respuesta
sergilazaro

Estoy de acuerdo con #3 .

La herencia en scripts mejor evítala, haz un script Base y varios script Derivado y incluye los dos en cada enemigo. Cuando quieras acceder a algún campo común, estarán en el script Base, y los específicos en el Derivado.

1 respuesta
jalsimoo

#5 Vale. Pensaba que me daría problemas, pero leyendo poco a poco voy enterándome de que puede ser una buena solución. Voy a ir implementandolo a ver cómo va quedando.

jalsimoo

Quiero aclarar, por cierto, que el editor sí me muestra las variables públicas de la clase base si pongo el script de la clase derivada. No sé por qué antes no, igual tenía errores y no lo mostraba por eso...
sigo.

1 respuesta
r2d2rigo

#4 componente = clase derivada de MonoBehavior.

Srednuht

#7 Eso te iba a decir, claro que las muestra.

Y luego además será interesante que emplees funciones virtuales para hacerlo más cómodo

1 respuesta
jalsimoo

#9 Sí, sí que las muestra; sería cosa del momento. Ya he conseguido hacer una estructura decente a falta de pulirla. Me podríais explicar la utilidad de las funciones virtuales?

1 respuesta
Srednuht

#10 Puedes establecer comportamientos a la clase base, y luego según la clase heredada que la use que haga una cosa u otra.

Te pongo un ejemplo fácil con animalitos. Supongamos que quieres tener animales que 'hablen'

Clase Base - Animales

public virtual void Hablar ()
{
// Puedes dejarlo en blanco
}

Luego tienes las clases heredadas, Perro y Gato. puedes hacer un override a esa funcion y modificar su comportamiento. Asi, según quien la llame hará una cosa u otra.

Así pues, en la clase ' Perro' y 'Gato' podrias hacer algo así.

[Perro]
public override Hablar()
{
sound.Play("Ladrido.wav" );
}
[Gato]
public override Hablar()
{
sound.Play("Maullido.wav" );
}

Y luego pues puedes hacer un

Animales dog = new Perro(); // o Perro dog = new Perro();
Animales cat = new Gato(); // o Gato cat = new Gato();
dog.Hablar();
cat.Hablar();

De esta forma, teniendo claro que un comportamiento va a ser común, pero su efecto va a ser distinto puedes implementar comodamente la misma funcion.

Tu por ejemplo, tienes enemigos, todos los enemigos hacen daño. Lo que cambia es, supongo, el daño que hacen y las condiciones en las que hacen daño. Tu clase 'Enemigo' podría tener fácilmente una funcion virtual "Dañar()" cuyos efectos varíen según sean llamados por 'voladores','caminantes,'etc.

No se si se entiende xD

1 respuesta
jalsimoo

#11 Se entiende muy bien. Básicamente se pone el virtual en las funciones que vayamos a sobrecargar ¿no?
Vengo de C++ donde no se pone ni virtual ni override, por eso imagino que esto me viene de nuevas.

2 respuestas
r2d2rigo

#12 que en C++ no se ponga virtual no te lo crees ni tu, otra cosa es que la palabra reservada override no exista a diferencia de Java/C# que la introdujeron para hacer las cosas mas claras.

sasher

#12 Hombre, virtual se lleva poniendo toda la vida en C++ hasta donde yo se, y desde C++11 se admite la palabra reservada override.

Aparte, te recomiendo que profundices un poco antes en OOP y después avances a lo que usa unity, que es básicamente un diseño orientado a componentes.

Para lo último, empieza por aquí: http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/ Y si quieres profundizar un poco mas, mírate los árticulos relacionados en los libros Game Programming Gems, volúmenes 6 y 8 creo que eran.

1 respuesta
jalsimoo

Tenéis razón una vez más (que para eso he preguntado) que sí se usa virtual en C++. Debería haber dicho que no lo había usado ni sabía su existencia; lo que yo sí he hecho es sobrecargar funciones en general, no con herencia de por medio :palm: .

#14 La verdad es que el modelo ya me funciona muy bien y voy a seguir tirando; no obstante miraré el enlace que me has puesto. Profundizar en OOP siempre se puede pero considero que tengo una muy buena base ya, al igual que con Unity (con este menos), pese a no haber usado virtual :P

Usuarios habituales

  • jalsimoo
  • sasher
  • r2d2rigo
  • Srednuht
  • sergilazaro
  • EnderFX