Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Como se estructura el codigo en un juego

Iniciado por vib, 12 de Enero de 2013, 03:31:42 PM

« anterior - próximo »

vib

Hola de nuevo, despues de llevar unas semanas parado, he querido continuar con mi motor de juegos 2d que estaba haciendo y repasando el codigo me surgio esta question.
Los juegos, en general como se estructuran?
Me explico.
Mi motor de momento es algo sencillo conta de estas clases. El codigo esta hecho en c++ sdl, nombrados tambien en otros post.
Clase fichero: para abrir ficheros .txt etc " correspondiente a la matriz mapa, matriz colision del mapa, alturas del mapa

Clase imagen: Es donde se guarda la imagen.
Clase scroll: contiene la clase fichero y se relaziciona en la creacion del mapa, herencia de imagen.

clase animacion: herencia de imagen, es donde le decidimos el perimetro que ocupara la imagen, en que posicion esta, si tiene alguna secuencia de imagenes, si colisiona.

clase personaje: herencia de animacion, es donde estan los atributos de la clase personaje, su movimiento,vida etc

Bien mi pequeño motor consta de esto, quiero ampliarlo pero 1r quiero resolver las pequeñas dudas.

A la hora de realizar la profundiad de la imagen "saber cuala se  imprime antes" tenia de poner todas las clases que creaba en un mismo lugar y que se ordenara segun ivan a salir por pantalla
Para esto cree una clase:
Juego y tuviera vectores de todas las clases anteriores, y que cada vez que se tuviera de crear una cosa se creara en ese vector asi ya tendria todas las clases dentro de vectores para luego ordenarlos e imprimirlos...
La cosa esque la clase juego, me esta dejando el codigo super feo, ya que tengo de repetir el mismo codigo para llamar a una clase, llamar a otra y todo sale de la clase juego...y nose si lo estoy haciendo bien.

La cosa es..como lo harias vosotros tener de manera practica, si por ejemplo quereis hacer un juego que las clases en ese nivel ya estan predefinidas...Por ejemplo 2 scroll, 3 animaciones, 10 personajes "9 npcs y el controlado por ti"

Como lo organizariais para saber quien es quien...porque me imagino que esto se debe hacer de forma automatica no creando todas las clases manualmente que es lo que no entiendo.

Otro nivel empezarian por ejemplo 5 personajes, pero se hiria incrementando infinitamente....claro aqui se tiene de crear de forma automatica y tenerlos controlados

Nose si me explico bien, me da la sensacion que no.
Las clases que las guardas todas en vectores o listas? o haceis eso de crear una clase que lo engloba todo ? porque yo tenia..


main()
{
    juego g;//clase juego que engloba todo
   g.crear_personaje();
   g.poner_imagen_personaje(g.obt_pos_personaje()-1, "ruta/imagen");//obt_pos_personaje es la que utilizo para saber en que //posicion del vector esta el personaje que acabo de crear
//y asi lo voy haciendo con todo..

nose no me gusta por eso quiero otros puntos de vista, quiero hacer el motor de juego para ya bonito para poder usarlo siempre...
Gracias

Gallo

#1
Para pintar objetos de la escena en un orden determinado se suele utilizar una estructura jerarquica y todos los objetos de la escena extienden o son referenciados por una misma clase que representa elementos de la escena. Te voy a poner el ejemplo que aprovecha la polimorfia:

class ElementoEscena
{
public:
virtual void actualizar(float deltaTime){ };
virtual void pintar(SoporteRender& soporte) = 0;
}

class ContenedorElementosEscena : public ElementoEscena
{
protected:
std::list<ElementoEscena*> hijos;

public:
virtual void actualizar(float deltaTime)
{
for (std::list<ElementoEscena*>::iterator hijo=hijos.begin(); hijo != hijos.end(); ++hijo)
{
(*hijo)->actualizar(deltaTime);
}
}

virtual void pintar(SoporteRender& soporte)
{
for (std::list<ElementoEscena*>::iterator hijo=hijos.begin(); hijo != hijos.end(); ++hijo)
{
(*hijo)->pintar(soporte);
}
}

virtual void agregarElemento(ElementoEscena* elemento)
{
hijos.push_back(elemento);
}
}

class Imagen : public ElementoEscena
{
public:

Imagen(std::string nombreArchivo)
{
//cargar imagen de archivo
}

virtual void actualizar(float deltaTime)
{
//actualizar la posicion de la imágen en cada frame, aqui puedes hacer scrolling o mover el personaje
};

virtual void pintar(SoporteRender& soporte)
{
//código que pinta la imágen con la api gráfica
};
}

class Jugador : public ContenedorElementosEscena
{
Imagen cabeza;
Imagen cuerpo;

Jugador() : cabeza("cabeza.png"), cuerpo("cuerpo.png")
{
this->agregarElemento(&cabeza);
this->agregarElemento(&cuerpo);
}

virtual void agregarElemento(ElementoEscena* elemento);
}

int main(int argc, char** argv)
{
SoporteRender soporte;
ContenedorElementosEscena escenaPrincipal;
Imagen fondo;
Jugador jugador;

escenaPrincipal.agregarElemento(&fondo);
escenaPrincipal.agregarElemento(&jugador);

while(juegoActivo)
{
escenaPrincipal.actualizar(0.016);
escenaPrincipal.pintar(soporte);
}

return 0;
}



Este es un ejemplo en C++ pero no es la forma mas correcta de implementar este código, tomalo como un pseudocódigo.

Como ves, usando métodos virtuales no hace falta que tengas arrays/listas segun los tipos, si no, según en que orden los necesitas. Al ser las listas elementos que se pueden agregar a la escena, surje la jerarquia.

SoporteRender es una clase pensada para guardar transformaciones y otras utilidades para el rendering.

Lo que se hace en el main puede estar contenido en una clase como haces tu llamada Juego, para que esté mas ordenado.

Espero que te aclare algunas dudas,

Saludos.

Vicente

Ahora se lleva mucho el utilizar arquitecturas orientadas a componentes en vez de orientadas a objetos, este link de Stack Overflow tiene información a patadas al respecto:

http://stackoverflow.com/questions/1901251/component-based-game-engine-design

vib

Vale me ha quedado bastante claro!
la web que me habeis puesto ya le hechare un ojo con calma.
Luego el ejemplo que has puesto es mas o menos lo que buscaba.

MI CLASE juego, la dejare mas simplificada para tener el vector de la clase en comun, y que se dedique ordenar,preparar,imprimir.

Lo que veo que en el contenedor, guardas las clases que se crean en el main...
osea creas la clase y la guardas en la otra clase pasandola como referencia
asi lo que se canvia de la clase tambien canviara al contenedor no?
pero entonces realmente se crean 2 clases iguales no?
Es un poco gasto o no tiene nada que ver?
IGUALmente ya he cojido la idea de como hacerlo!

OS AGRADEZCO QUE CONTESTARAIS!
GRACIAS :D

Gallo

Quizá tengas que repasar algunos conceptos de cpp. Lo que guardo en la lista son punteros al objeto, el objeto lo instancio de forma estática en el main o en otra clase.


class Juego
{
public:
Escena escena; //Escena es extiende ContenedorEelementosEscena.
Jugador jugador;
boolean juegoActivo;

Juego() : juegoActivo(false){};

void init()
{
    //se guarda una referencia a que juego pertenece la escena
    //de esta forma la logica de escena puede, por ejemplo, setear juegoActivo = false para parar el juego
    escena.setJuego(this);

    //puedes guardar como única referencia el puntero instanciando el objeto de forma dinámica por ejemplo
    escena.agregarElemento(new Imagen("fondo.png"));
    escena.agregarElemento(new Imagen("casa.png"));

    //&jugador es un puntero al objeto jugador solo guardas el puntero a un objeto estático no otra copia
    escena.agregarElemento(&jugador);
   
    juegoActivo = true;
}

void buclePrincipal()
{
while(juegoActivo)
{
escenaPrincipal.actualizar(0.016);
escenaPrincipal.pintar(soporte);
pauseMiliseconds(0.016);
}
}
}

void main()
{
Juego juego;
juego.init();
juego.buclePrincipal();
}


Esto es solo un ejemplo para que se comprenda un poco el funcionamiento pero no es un ejemplo real, monta la estructura de clases que mejor se adapte a tus necesidades o a tu forma de entender como ha de funcionar el juego.

Normalmente diseñar estas cosas implica una constante toma de decisiones de que clase referencia a que otra clase, donde o como instancias objetos, etc... y lo normal es equivocarse, por eso hay tantos motores de juegos, por que desde el punto de vista de otro programador ese código está equivocado en algo y hace su versión con lo que para el es lo correcto a su criterio o necesidades.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.