Logica Del Videojuego

download Logica Del Videojuego

of 84

Transcript of Logica Del Videojuego

  • Lgica delvideojuego

    Jordi Duch i GavaldHeliodoro Tejedor Navarro

    PID_00188520

  • CC-BY-NC-ND PID_00188520 Lgica del videojuego

    Los textos e imgenes publicados en esta obra estn sujetos excepto que se indique lo contrario a una licencia deReconocimiento-NoComercial-SinObraDerivada (BY-NC-ND) v.3.0 Espaa de Creative Commons. Podis copiarlos, distribuirlosy transmitirlos pblicamente siempre que citis el autor y la fuente (FUOC. Fundacin para la Universitat Oberta de Catalunya),no hagis de ellos un uso comercial y ni obra derivada. La licencia completa se puede consultar en http://creativecommons.org/licenses/by-nc-nd/3.0/es/legalcode.es

  • CC-BY-NC-ND PID_00188520 Lgica del videojuego

    ndice

    Introduccin............................................................................................... 5

    Objetivos....................................................................................................... 6

    1. Ingeniera del software aplicada a los videojuegos.................. 71.1. Paradigmas de programacin ...................................................... 7

    1.1.1. Programacin no estructurada ...................................... 81.1.2. Programacin estructurada ............................................ 81.1.3. Programacin modular .................................................. 91.1.4. Programacin usando tipos abstractos de datos ............ 101.1.5. Programacin orientada a objetos ................................. 111.1.6. Caractersticas de la POO .............................................. 13

    1.2. Patrones de diseo ...................................................................... 161.2.1. Singleton ........................................................................ 171.2.2. Factory Method ............................................................. 181.2.3. Proxy .............................................................................. 191.2.4. Iterator.............................................................................. 211.2.5. Observer ......................................................................... 231.2.6. Modelo-vista-controlador .............................................. 26

    2. El programa principal de un videojuego.................................... 282.1. Estados de un videojuego ........................................................... 28

    2.1.1. Diagrama de estados ...................................................... 292.1.2. El gestor de estados ....................................................... 302.1.3. Diagrama de estados y subestados ................................ 33

    2.2. El controlador principal .............................................................. 342.3. El bucle principal del juego ........................................................ 36

    3. El motor lgico de un videojuego................................................. 393.1. El mundo lgico del juego ......................................................... 39

    3.1.1. Discretizacin del mundo ............................................. 403.2. Tareas del motor de lgica .......................................................... 42

    3.2.1. Aplicar movimiento de los elementos del juego ........... 423.2.2. Aplicar acciones de los elementos del juego ................. 433.2.3. Clculo del nuevo estado del juego .............................. 44

    4. Gestin de los datos de un videojuego......................................... 464.1. Objetos y entidades .................................................................... 46

    4.1.1. Implementacin de un objeto ....................................... 484.1.2. Implementacin de objetos usando herencia ............... 53

    4.2. Niveles del juego ......................................................................... 61

  • CC-BY-NC-ND PID_00188520 Lgica del videojuego

    4.2.1. Implementando un nivel .............................................. 624.3. Almacenamiento de los datos ..................................................... 63

    4.3.1. Datos binarios ................................................................ 634.3.2. Datos no binarios .......................................................... 64

    4.4. Editor de objetos y de niveles .................................................... 67

    5. Lenguajes del scripting..................................................................... 685.1. Diferencia entre un lenguaje interpretado y un lenguaje

    compilado .................................................................................... 685.2. Ventajas y desventajas del scripting.............................................. 705.3. Lenguajes de scripting................................................................... 71

    5.3.1. Introduccin a LUA ....................................................... 725.3.2. Integracin de LUA con C ............................................ 735.3.3. Integracin de LUA con C++ usando luabind................. 74

    5.4. Usos del scripting.......................................................................... 775.4.1. Almacenamiento de datos ............................................. 775.4.2. Grafos de estado de la IA y lgica del juego .................. 775.4.3. Definicin y control de interfaces de usuario ............... 785.4.4. Guiones de vdeos ......................................................... 79

    Resumen....................................................................................................... 80

    Actividades.................................................................................................. 81

    Glosario........................................................................................................ 82

    Bibliografa................................................................................................. 83

  • CC-BY-NC-ND PID_00188520 5 Lgica del videojuego

    Introduccin

    Lo que diferencia un videojuego de cualquier otro tipo de aplicacin no sonsus grficos ni su sonido, sino el conjunto de retos y reglas que estimulan lainteraccin con el usuario. Con los elementos explicados hasta ahora an nopodemos implementar ningn juego, sino que se trata solamente de comple-mentos que principalmente van a ayudar a que el usuario se sienta ms inte-grado dentro del juego y que pueda tener acceso a la mayor cantidad de infor-macin posible para poder desarrollar la partida.

    La parte donde se controla el desarrollo del juego es lo que llamamos el mo-tor de lgica. Esta parte, tan o ms importante que todas las descritas ante-riormente, incluye la descripcin de los atributos de todos los elementos queparticipan, y de todas las reglas y condiciones que hemos situado en el juego.Continuamente mira las acciones que han realizado los jugadores y los ele-mentos controlados por la inteligencia artificial y decide si estas acciones sepueden llevar a cabo y cul es el resultado de ejecutarlas.

    Dentro del motor lgico de juego se juntan tres elementos muy importantes:

    La integracin de todos los componentes que hemos visto hasta ahora La gestin de todos los datos de la partida La aplicacin de las reglas del juego

    Veremos con detalle cmo se implementan estos tres elementos, que sern elcorazn de nuestro juego.

    Adems, la parte del motor lgico es la que se encuentra ms ligada al procesocreativo del juego y es donde intervienen algunos perfiles no tan familiariza-dos con la programacin avanzada. Para separar la parte creativa de la progra-macin se utilizan los lenguajes de script, que veremos en la ltima parte delmdulo.

  • CC-BY-NC-ND PID_00188520 6 Lgica del videojuego

    Objetivos

    Con el material de este curso podris alcanzar los objetivos siguientes:

    1. Repasar los conceptos de ingeniera del software necesarios para el desa-rrollo de la estructura del videojuego.

    2. Implementar un diagrama de estados para gestionar las transiciones entrelos diferentes estados de un juego.

    3. Disear el bucle principal de un juego.

    4. Organizar la informacin en la vista lgica para que el motor lgico y lainteligencia artificial conozcan el desarrollo de la partida.

    5. Implementar el motor lgico para garantizar que las reglas del juego secumplen.

    6. Almacenar los datos necesarios para el juego de una forma ptima y es-tructurada.

    7. Utilizar un lenguaje de scripting para facilitar el trabajo del diseador deljuego.

  • CC-BY-NC-ND PID_00188520 7 Lgica del videojuego

    1. Ingeniera del software aplicada a los videojuegos

    En el primer apartado de este mdulo vamos a hacer un repaso de la teorabsica de ingeniera del software y cmo se introducen los conceptos clsicosde esta teora en el desarrollo de un videojuego.

    Es muy importante conocer la mayora de estos conceptos, sobre todo parapoder desarrollar aplicaciones a gran escala de una forma modular y estructu-rada.

    Aprender estas tcnicas de ingeniera de software adicionalmente nos va a per-mitir:

    Resolver problemas comunes con un procedimiento ptimo y ya probado.

    Ser ms productivos porque no tenemos que volver a pensar cmo hacerun algoritmo y porque sabemos que el que implementamos ya ha sidoprobado para resolver otros problemas con buenos resultados.

    Complementar la documentacin con el propio cdigo (aunque nunca lasustituye).

    Entender cdigo ajeno con slo ver su estructura.

    En la ingeniera del software se han ido desarrollando nuevas formas de orga-nizacin a la hora de crear nuevas aplicaciones. Una de estas formas, que esmuy interesante conocer a la hora de desarrollar aplicaciones, son los patronesde diseo.

    Para entender bien el concepto de los patrones de diseo, veremos primero laevolucin que ha sufrido el arte de la programacin y los diferentes paradigmasque han ido apareciendo.

    A partir del repaso a estos paradigmas, conoceremos el concepto de patrn dediseo y estudiaremos los ms importantes y que nos sern tiles a la hora dedesarrollar un videojuego.

    1.1. Paradigmas de programacin

    Los paradigmas de programacin ms destacados y que vamos a repasar a con-tinuacin son los siguientes:

    Programacin no estructurada Programacin estructurada

  • CC-BY-NC-ND PID_00188520 8 Lgica del videojuego

    Programacin modular Programacin usando tipos abstractos de datos Programacin orientada a objetos

    1.1.1. Programacin no estructurada

    Es la primera y ms bsica forma de programacin. En este tipo slo preten-demos hacer que un algoritmo funcione sin tener en cuenta ningn aspectoextra: estructuracin, seguridad, mantenimiento, etc.

    Utilizamos variables globales, no prestamos atencin a los identificadores delas variables.

    El control del flujo de las instrucciones la realizamos bsicamente conla instruccin "goto" y el bucle "if".

    ejemplo.c

    #include

    float a, aa, aaa;

    int main()

    {

    inicio:

    a = 3.1415926f;

    scanf("%f\n", &&aa);

    if (aa == 0.0f) goto fin;

    aaa = 2 * a * aa;

    printf("El perimetro de una circumferencia de radio %f es %f\n", aa, aaa);

    goto inicio;

    fin:

    return 0;

    }

    1.1.2. Programacin estructurada

    Una vez hemos aprendido a desarrollar pequeos algoritmos, empezamos autilizar estructuras que nos permiten mantener mejor nuestro cdigo. Ade-ms, nos damos cuenta de que este cdigo es ms legible para los dems desa-rrolladores.

    Evitamos las variables globales, intentamos dividir los algoritmos en pequeosprocedimientos, utilizamos nombres de variables ms correctos.

  • CC-BY-NC-ND PID_00188520 9 Lgica del videojuego

    Se utilizan bucles "for" y "while" y se evita la instruccin "goto".

    ejemplo.c

    #include

    float leer_radio()

    {

    float radio;

    scanf("%f", &radio);

    return radio;

    }

    float calcular_perimetro(float radio)

    {

    float PI = 3.1415926f;

    return 2.0 * PI * radio;

    }

    int main()

    {

    float radio;

    float perimetro;

    do

    {

    radio = leer_radio();

    if (radio != 0.0f)

    {

    perimetro = calcular_perimetro(radio);

    printf("El perimetro de una circunferencia de radio %f es %f\n", radio, perimetro);

    }

    } while (radio != 0.0f);

    return 0;

    }

    1.1.3. Programacin modular

    En este nuevo paradigma, los programadores necesitamos cada vez ms desa-rrollar un cdigo ms complejo y vemos que es necesario volver a escribir de-terminados algoritmos. Empezamos a utilizar mdulos (o bibliotecas) dondepodemos ir almacenando cdigo que podemos utilizar en otros programas.

    Por ejemplo, tenemos un mdulo llamado "circunferencia" con las siguientesfunciones:

    Circunferencia.h

    float leer_radio();

  • CC-BY-NC-ND PID_00188520 10 Lgica del videojuego

    float calcular_perimetro(float radio);

    void imprimir_info(float radio, float perimetro);

    Y un programa que lo utiliza:

    Ejemplo.c

    #include

    int main()

    {

    float radio;

    float perimetro;

    do

    {

    radio = leer_radio();

    if (radio != 0.0f)

    {

    perimetro = calcular_perimetro(radio);

    imprimir_info(radio, perimetro);

    }

    } while (radio != 0.0f);

    return 0;

    }

    1.1.4. Programacin usando tipos abstractos de datos

    Una vez conocidas las ventajas de la programacin modular, nos damos cuen-ta de una fuente de errores bastante comn. Los datos se suelen agrupar for-mando una entidad (por ejemplo, un cliente tiene un DNI, un nombre, untelfono...). Estos datos debemos tratarlos en conjunto y evitar en lo posibleque funciones externas al mdulo puedan modificar esta informacin. Conesta nueva forma de trabajar, evitaremos que los datos de una entidad dejende ser consistentes (una funcin externa puede cambiar solamente el nombrede un cliente, pero seguira teniendo los mismos apellidos; y puede que seaun comportamiento no deseado).

    Podemos solucionar este problema trabajando con los datos de una entidaddentro de su mdulo y que el cliente de ste slo pueda acceder a ellos utili-zando las funciones que el mdulo le proporciona.

    Por ejemplo, desarrollamos el siguiente mdulo para trabajar con un avatarde un videojuego:

    Avatar.h

    typedef void* avatar_t;

    avatar_t avatar_create(string name, point_t location, state_t state);

  • CC-BY-NC-ND PID_00188520 11 Lgica del videojuego

    void avatar_delete(avatar_t avatar);

    string avatar_get_name(avatar_t avatar);

    point_t avatar_get_location(avatar_t avatar);

    void avatar_move(avatar_t avatar, vector_t distance);

    ...

    Y un programa que utiliza este mdulo:

    Game.c

    #include

    #include

    #include

    void update_state(game_t game)

    {

    list_t list = game_get_avatars(game);

    while (list_has_next(list))

    {

    avatar_t cur_avatar = (avatar_t) list_get_next(list);

    vector_t distance = game_calculate_movement(game, cur_avatar);

    avatar_move(cur_avatar, distance);

    list_move_next(&list);

    }

    }

    1.1.5. Programacin orientada a objetos

    A partir de la programacin usando tipos abstractos de datos, nos damos cuen-ta de que estos mdulos los podemos organizar usando jerarquas (un avatary un coche son dos objetos animados). Es en este paso cuando nos adentra-mos en la programacin orientada a objetos (POO), que nos permite aadirmuchas ms funcionalidades a la programacin con tipos abstractos de datos.

    Este paradigma nos proporciona muchos mecanismos para programar cdigoms seguro, funcional y reutilizable. Sus principales ventajas son:

    Los paquetes de objetos bien construidos los podemos utilizar en otrosproyectos aumentando su productividad. Fomenta la reutilizacin de c-digo.

    Si los objetos se reutilizan, aumentamos la seguridad, puesto que estosobjetos ya han sido probados en otras aplicaciones.

    Los mecanismos de la POO nos permiten crear jerarquas de objetos quese pueden ampliar con menor coste que los sistemas tradiciones de pro-gramacin.

  • CC-BY-NC-ND PID_00188520 12 Lgica del videojuego

    La correcta utilizacin de la POO nos permite reaprovechar las mismaslneas de cdigo de un algoritmo para diferentes tipos de datos (objetos).A menor lneas de cdigo, menor probabilidad de errores y tenemos unmantenimiento menor.

    La POO permite resolver problemas trabajando con los mismos trminosdel problema (dominio); no se utilizan trminos del ordenador (podemoshablar de avatares, enemigos, coches, pelotas...).

    Al igual que en la utilizacin de tipos abstractos de datos, la POO nos per-mite modificar un determinado algoritmo sin necesidad de reprogramarel resto de la aplicacin, siempre y cuando la interfaz (contrato entre elresponsable de un objeto y sus usuarios) se mantenga.

    La POO nos facilita la programacin en un grupo de trabajo. Una vez seconcluye la fase de diseo, cada miembro del grupo puede ir programan-do los diferentes objetos que componen el problema con apenas interfe-rencias de los dems miembros. Tambin nos facilita la creacin de testsunitarios para cada uno de los objetos (tiles tanto en la fase de diseocomo en la de depuracin).

    Un cdigo creado con POO es ms legible y fcil de entender para un pro-gramador medio comparndolo con lenguajes ms tradicionales (bsica-mente, C). No es necesario contratar a programadores expertos para la ma-yora de problemas y se pueden rebajar costes (en la mayora de casos, sloes necesario contratar programadores expertos en C++ para programar elncleo de un videojuego).

    La POO genera un mercado de compra/venta de componentes y una basepara que en un futuro haya un procedimiento para interactuar entre variosobjetos de diferentes programadores (y entre diferentes lenguajes). Variosintelectuales no consideran la programacin como una ingeniera puestoque no hay ningn procedimiento estndar que permita reutilizar cdigo(comprese con las dems ciencias tcnicas).

    Como todos los paradigmas, la POO tambin tiene sus desventajas:

    La primera y ms importante es que es muy difcil de traducir a un len-guaje orientado a objetos el cdigo que ya existe. En el caso concreto delos videojuegos, este punto no es muy importante, ya que la mayora dedesarrollos se empiezan casi desde cero.

    Se debe formar a los grupos de desarrollo con las nuevas tcnicas de pro-gramacin, lo que genera costes.

  • CC-BY-NC-ND PID_00188520 13 Lgica del videojuego

    Los desarrolladores ya formados en programacin tradicional suelen serreacios a aprender nuevas formas de programacin. Se debe cambiar laforma de pensar en el problema y eso no suele gustarle a mucha gente.

    Aunque en la mayora de aplicaciones no suele ser crtico, la ejecucin deun cdigo realizado con POO suele ser ms lenta que usando tcnicas deprogramacin tradicional.

    1.1.6. Caractersticas de la POO

    La POO no slo ampla los conceptos de la programacin tradicional, modificala forma de pensar para atacar los problemas.

    Los puntos bsicos a tener en cuenta cuando se trata de aprender el paradigmade la POO son los siguientes:

    Modelo de objeto

    Definiremos una clase como la definicin de una estructura que contiene in-formacin (datos) y una declaracin de algoritmos (o mtodos) que modifica-rn la informacin.

    Un objeto es una zona de memoria que cumple con la estructura de una claseconcreta y se puede deducir que un objeto slo existe mientras est en ejecu-cin la aplicacin.

    Podemos comparar una clase como un tipo de datos de la programacin tra-dicional y un objeto como una variable del tipo definido por la clase.

    Un objeto puede seguir vindose como un tipo abstracto de datos.

    Abstraccin

    Podemos definir la abstraccin como la representacin de las caractersticasesenciales de cualquier cosa sin incluir detalles irrelevantes. Todos tenemos unmodelo de un coche, pero pocos (mecnicos) saben exactamente cmo fun-ciona. Nosotros hemos abstrado un modelo simplificado que representa lascaractersticas que necesitamos conocer de un coche para hacerlo funcionar.

    De la misma manera, podemos crear una clase (un objeto en movimiento, porejemplo) que represente un detalle concreto del problema y que los usuariosde nuestra clase slo necesiten saber las funcionalidades que necesitan (hacerque se mueva en una direccin, consultar su posicin actual...).

  • CC-BY-NC-ND PID_00188520 14 Lgica del videojuego

    Encapsulamiento

    Al igual que con los tipos abstractos de datos (una clase no deja de serlo), ne-cesitamos evitar que el usuario de nuestra clase pueda acceder a la informacininterna, hacer mal uso de ella y crear inconsistencia en nuestros datos.

    Debemos actuar como si cada clase fuese una caja negra, donde no se sabe quse guarda ni cmo se trabaja con la informacin; slo necesitamos saber quehace la funcin, cunto tarda en hacer su trabajo y que lo hace bien (en el casode que no fuese as, el responsable de la clase debera solucionarlo).

    Herencia

    La herencia es el mecanismo que consiste en extender los comportamientosde una clase y poder compartir los mtodos y atributos (datos) con sus subcla-ses (clases que heredan de ella). En el ejemplo de los objetos en movimiento,podemos crear una herencia sencilla que explicar este apartado:

    Un objeto en movimiento se define como una posicin, una velocidad y una acele-racin.

    Un objeto en movimiento tiene como un mtodo "update" al que se le pasa el nmerode segundos que han transcurrido y debe modificar su posicin.

    MovingObject.h

    class MovingObject

    {

    protected:

    Point position;

    Vector3D velocity;

    Vector3D acceleration;

    public:

    void update(float seconds)

    {

    position += velocity * seconds;

    velocity += acceleration * seconds;

    }

    Point& getPosition() { return position; }

    Type getType() { return MovingObjectType; }

    ...

    };

    A partir de aqu, un avatar es un objeto en movimiento:

    Avatar.h

    #include

  • CC-BY-NC-ND PID_00188520 15 Lgica del videojuego

    class Avatar

    : public MovingObject

    {

    private:

    Vector3D desiredVelocity;

    public:

    void update(float seconds)

    {

    velocity = velocity * 0.5f + desiredVelocity * 0.5f;

    position += velocity * seconds;

    }

    Type getType() { return AvatarType; }

    };

    Con el ejemplo anterior, podemos crear la clase siguiente:

    Game.h

    #include

    class Game

    {

    private:

    std::list movingObjects;

    public:

    Game()

    {

    movingObjects.push_back(new Avatar("Malo"));

    movingObjects.push_back(new Avatar("Bueno"));

    movingObjects.push_back(new MovingObject("Piedra de Indiana Jones"));

    movingObjects.push_back(new MovingObject("Balancn"));

    }

    void update(float seconds)

    {

    std::list::iterator it;

    for (it = movingObjects.begin(); it != movingObjects.end(); it++)

    (*it)->update(seconds);

    prepareDraw();

    for (it = movingObjects.begin(); it != movingObjects.end(); it++)

    draw((*it)->getPosition(), (*it)->getType());

    drawOverlays();

    finalizeDraw();

    }

    };

  • CC-BY-NC-ND PID_00188520 16 Lgica del videojuego

    Polimorfismo

    Permite que varios objetos de una misma clase puedan tener comportamientosdiferentes. ste suele ser un concepto ms difcil de explicar que de entendercon un ejemplo. La idea bsica la podemos explicar con el ejemplo anterior,donde el mtodo "update" tiene dos comportamientos diferentes segn sea unmovingObject o un avatar. En la clase Game se llama indistintamente a cadauno de los dos comportamientos segn el objeto que hay en la lista (movin-gObjects) sea de una clase o de otra (se define el tipo al crear la lista).

    Ligadura dinmica

    La ligadura dinmica es el mecanismo que tiene el lenguaje para decidir qumtodo debe ejecutarse de todos los que implementa un objeto. En el ejemploanterior, cmo ha sabido el lenguaje qu mtodo "update" tena que ejecu-tar de los dos posibles? El algoritmo encargado de decirlo se llama ligaduradinmica.

    1.2. Patrones de diseo

    Un patrn de diseo consiste en la definicin de un problema recurrente y desu solucin simple y elegante.

    Este concepto se utiliza en varias disciplinas, pero no se usar en la ingenie-ra del software hasta la publicacin del libro Desing Pattern, escrito por ErichGamma, Richard Helm, Ralph Johnson y John Vlisides (tambin conocidospor "Gang of Four", o GoF). En este libro se definen veintitrs patrones recu-rrentes y proponen soluciones sencillas.

    De estos veintitrs, veremos los ms destacados y que podremos utilizar a lahora de disear e implementar cdigo de un videojuego. Los patrones quehemos seleccionado son:

    Singleton Factory Method Proxy Iterator Observer

    Aparte de estos patrones, tambin se explicar con detalle el patrn mode-lo-vista-controlador, muy til para desarrollar todo tipo de aplicaciones quetienen interaccin con el usuario.

  • CC-BY-NC-ND PID_00188520 17 Lgica del videojuego

    1.2.1. Singleton

    Este patrn garantiza que una clase slo pueda tener una instancia dentro dela aplicacin y establece su punto de acceso global.

    Un ejemplo de su uso puede ser el controlador de algn elemento de hardwareque necesitemos en nuestra aplicacin, por ejemplo, el ratn, el teclado, elsonido, etc.

    Otro uso es mantener el estado del videojuego (posiciones de los elementosmviles, estado de los avatares...).

    Hay dos formas bsicas de implementar un singleton:

    "eager instantiation": la instancia se crea al inicio de la aplicacin. "lazy instantiation": la instancia no se crea hasta que no se necesite por

    primera vez.

    Ejemplo de "eager instantiation":

    MouseController.h

    class MouseController

    {

    private:

    static MouseController m_instance;

    MouseController()

    {

    // init...

    }

    public:

    static MouseController& getInstance() { return m_instance; }

    };

    MouseController.cpp

    #include

    static MouseController MouseController::m_instance;

    Ejemplo de "lazy instantion":

    MouseController.h

  • CC-BY-NC-ND PID_00188520 18 Lgica del videojuego

    class MouseController

    {

    private:

    static MouseController* m_pInstance;

    private MouseController() {

    // init

    }

    public:

    static MouseController& getInstance() {

    if (NULL == m_pInstance)

    m_pInstance = new MouseController();

    return *m_pInstance;

    }

    };

    MouseController.cpp

    #include

    static MouseController* MouseController::m_pInstance = NULL;

    En la API del engine Ogre3D es muy comn el uso de este patrn.

    1.2.2. Factory Method

    Este patrn define la forma en que deben de crearse determinados objetos apartir de un objeto llamado fbrica (o Factory). Por ejemplo, al leer una ciertaimagen desde un fichero, podemos delegar la eleccin del algoritmo de des-compresin (gif, png, jpeg...) a un objeto Factory y que ste nos devuelva unainstancia a un objeto imagen:

    ImageFactory.h

    #include

  • CC-BY-NC-ND PID_00188520 19 Lgica del videojuego

    class ImageFactory

    {

    private:

    bool testExtension(const std::string& filename, const std::string& ext) const

    {

    return filename.length() == filename.rfind(ext) + ext.length();

    }

    public:

    Image* createImageFromFile(const std::string& filename)

    {

    if (testExtension(filename, ".png"))

    return new PNGImage(filename);

    if (testExtension(filename, ".gif"))

    return new GIFImage(filename);

    return NULL;

    }

    };

    1.2.3. Proxy

    Este patrn permite el acceso indirecto a un objeto, permitiendo controlar lasacciones que se realizan sobre el objeto real. Dos de estas acciones puedenser: control de acceso de seguridad (login/password) y acceso a objetos remotos(implementacin sencilla de programacin distribuida).

    Para implementar este patrn necesitamos de una interfaz que establezca elcomportamiento de un objeto, una implementacin real de la interfaz y undelegado:

    IController.h

    class IController {

    public:

    virtual void keyPressed(char ch) = 0;

    virtual void keyReleased(char ch) = 0;

    };

  • CC-BY-NC-ND PID_00188520 20 Lgica del videojuego

    NetController.h

    #include

    class MainController

    : public IController

    {

    public:

    MainController() { ... }

    // IController members

    protected:

    virtual void keyPressed(char ch) {

    // update state

    }

    virtual void keyReleased(char ch) {

    // update state

    }

    };

    NetController.h

    #include

    class NetController

    : public IController

    {

    private:

    NetSocket m_ns;

    public:

    NetController(NetSocket ns)

    : m_ns(ns)

    {

    m_ns.connect();

    }

    // IController members

    protected:

    virtual void keyPressed(char ch)

    {

    m_ns.executeCommand("keyPressed", ch);

    }

    virtual void keyReleased(char ch)

    {

    m_ns.executeCommand("keyReleased", ch);

    }

    };

    Una vez diseada esta estructura, el siguiente cdigo:

  • CC-BY-NC-ND PID_00188520 21 Lgica del videojuego

    Ejemplo.cpp

    class GUI

    {

    private:

    IController* m_controller;

    public:

    GUI(IController* controller)

    :m_controller(controller)

    {

    }

    void onKeyPressed(char ch)

    {

    m_controller->keyPressed(ch);

    }

    ...

    };

    Funcionar sin ningn tipo de modificacin para un juego standalone comopara un juego en red:

    class GUIFactory

    {

    public:

    static GUI* createSinglePlayer() {

    return new GUI(new MainController());

    }

    static GUI* createNetPlayer(NetSocket ns) {

    return new GUI(new NetController(ns));

    }

    };

    1.2.4. Iterator

    El patrn iterator soluciona el problema de iterar sobre una serie de elementos.La solucin inicial presentada por GoF indica que se debe crear una interfazcon los siguientes mtodos:

    First(): inicia la enumeracin. Next(): itera sobre el siguiente elemento. GetCurrent(): retorna una instancia al elemento actual. IsDone(): retorna un valor booleano indicando si se ha llegado al final de

    la enumeracin.

  • CC-BY-NC-ND PID_00188520 22 Lgica del videojuego

    En la librera estndar de C++, el patrn de iteracin usado no sigue estas pau-tas. Cada tipo de contenedor de objetos (vector, list, queue, hash, set) defineuna clase interna llamada "iterator". Los mtodos "begin" y "end" devuelvenuna instancia de la clase "iterator" y definen el inicio y el final de la iteracin.Existen dos mtodos anlogos llamados "rbegin" y "rend" que permiten crearuna iteracin inversa y, en cuyo caso, se utiliza la clase "reserve_iterator".

    La clase "iterator" y su anloga "reserve_iterator" contienen los siguientes m-todos:

    operator*: retorna el elemento actual operator++: se mueve al siguiente elemento operator : se mueve al anterior elemento

    Un ejemplo de la creacin y recorrido de una lista en C++:

    Ejemplo.cpp

    #include

    #include

    int main()

    {

    std::list l;

    for(int i = 0; i < 10; i++)

    l.push_back(i);

    std::list::iterator it = l.begin();

    std::cout

  • CC-BY-NC-ND PID_00188520 23 Lgica del videojuego

    it = l.begin();

    while (it != l.end())

    {

    std::cout

  • CC-BY-NC-ND PID_00188520 24 Lgica del videojuego

    virtual void onDisplay() = 0;

    virtual void onKeyboard(unsigned char key, int x, int y) = 0;

    virtual void onKeyboardUp(unsigned char key, int x, int y) = 0;

    virtual void onIdle() = 0;

    };

    Display.h

    #include

    #include

    class Display

    {

    private:

    static Display m_instance;

    Display();

    std::set m_listeners;

    public:

    static Display& getInstance();

    void addListener(DisplayListener* listener);

    void removeListener(DisplayListener* listener);

    private:

    static void static_display() { getInstance().display(); }

    static void static_keyboard(unsigned char key, int x, int y)

    { getInstance().keyboard(key, x, y); }

    static void static_keyboardUp(unsigned char key, int x, int y)

    { getInstance().keyboardUp(key, x, y); }

    static void static_idle() { getInstance().idle(); }

    private:

    void display();

    void keyboard(unsigned char key, int x, int y);

    void keyboardUp(unsigned char key, int x, int y);

    void idle();

    };

    Display.cpp

    #include

    Display::Display()

    {

    glutDisplayFunc(static_display);

    glutKeyboardFunc(static_keyboard);

    glutKeyboardUpFunc(static_keyboardUp);

    glutIdleFunc(static_idle);

    }

    Display& Display::getInstance()

    {

    if (NULL == m_instance)

  • CC-BY-NC-ND PID_00188520 25 Lgica del videojuego

    m_instance = new Display();

    return *m_instance;

    }

    void Display::addListener(DisplayListener* listener)

    {

    m_listeners.insert(listener);

    }

    void Display::removeListener(DisplayListener* listener)

    {

    m_listeners.remove(listener);

    }

    void Display::display()

    {

    std::set::iterator it = listeners.begin();

    while (it != listeners.end())

    {

    (*it)->onDisplay();

    it++;

    }

    }

    ...

    Y una sencilla forma de utilizar el patrn:

    Game.h

    #include

    class Game

    : public DisplayListener

    {

    public:

    Game()

    {

    Display::getInstance().addListener(this);

    }

    virtual ~Game()

    {

    Display::getInstance().removeListener(this);

    }

    // DisplayListener members

    protected:

    void onDisplay();

    void onKeyboard(unsigned char key, int x, int y);

    void onKeyboardUp(unsigned char key, int x, int y);

    void onIdle();

    };

  • CC-BY-NC-ND PID_00188520 26 Lgica del videojuego

    1.2.6. Modelo-vista-controlador

    Este patrn no pertenece a la lista que propusieron los GoF. Empez a utili-zarse con el lenguaje SmallTalk y se defini a finales de los aos setenta. Suarquitectura bsica se descompone de tres elementos:

    Modelo: define el estado de la aplicacin. En este elemento se mantienetoda la informacin necesaria. Esta informacin puede guardarse (seriali-ze) para mantener el estado de la aplicacin entre ejecuciones (guardaruna partida podra hacer uso de esta caracterstica).

    Vista: elemento que presenta la informacin del modelo (render) y recibelos eventos de la interfaz (teclado, ratn...).

    Controlador: trata los eventos de la vista y modifica el estado del modelo.Tambin informa a la vista de los posibles cambios ocurridos en el modelo.

    Figura 1. Esquema modelo-vista-controlador

    En el caso de un videojuego, estos tres elementos los podemos emparejar conlas siguientes definiciones:

    Modelo: informacin que define el estado del videojuego (lista de elemen-tos mviles, avatares, puntos, pistas descubiertas...) y contiene los datossobre el mundo donde se est desarrollando la accin.

    Controlador: entidad que se encarga de la lgica del videojuego (imple-menta todas las operaciones que puede o no puede hacer un determinadoavatar, motor de fsica...). Aqu tambin entrara toda la parte de inteligen-cia artificial y toma de decisiones.

  • CC-BY-NC-ND PID_00188520 27 Lgica del videojuego

    Vista: entidad encargada de renderizar a partir de la informacin del mo-delo lo que el jugador debe de ver, or y sentir. A partir de la entrada dela interfaz (teclado, ratn...), informar al controlador para que modifiqueel estado.

  • CC-BY-NC-ND PID_00188520 28 Lgica del videojuego

    2. El programa principal de un videojuego

    El programa principal de un videojuego es el encargado de coordinar todos losdiferentes componentes que hemos visto en los mdulos anteriores (sonido,entrada de datos, grficos, red) con el motor lgico, que veremos en el apartadosiguiente y la inteligencia artificial, que veremos en el prximo mdulo.

    En este apartado vamos a explicar en primer lugar cmo se segmenta un juegoen diferentes estados. Los estados nos permiten separar ciertas tareas que sonnecesarias para la puesta a punto del mismo.

    Dentro de cada uno de los estados se encuentra un bucle que se ejecuta con-tinuamente. El estado que se encuentre activo nos indicar si estamos en elmen principal esperando que el usuario seleccione cmo quiere jugar o biensi nos encontramos en el estado "de juego", donde transcurre la accin de lapartida.

    Para finalizar el apartado, vamos a analizar paso a paso la estructura internadel bucle principal del estado "de juego", para entender cmo se integra la in-formacin que recibimos y enviamos a todos los componentes que utilizamosdurante el juego, bsicamente: entrada, sonido, grficos y red.

    2.1. Estados de un videojuego

    Entendemos por un estado de un videojuego un mdulo independiente querealiza una funcionalidad especfica y que tiene su propio gestor de eventos,su bucle principal y su engine grfico para mostrar la informacin por pantalla.

    Nota

    No confundir estos estados con los estados que se utilizan en una entidad de inteligenciaartificial para la toma de decisiones o con el estado global de una partida, que se refiereal valor que tienen las variables en cada momento concreto del juego.

    La subdivisin en estados depende de cmo vayamos a estructurar nuestrojuego. No existen reglas en las que basarse para decidir cundo es convenienteseparar dos tareas en dos estados diferentes, pero principalmente dependerde si ests pueden compartir gestores de eventos y los diferentes motores deljuego, o no.

    stos son algunos ejemplos de posibles estados que podemos definir en unvideojuego:

    La configuracin del sistema. El establecimiento de la conexin de la red.

  • CC-BY-NC-ND PID_00188520 29 Lgica del videojuego

    Los vdeos de presentacin o de transicin, donde el usuario no tiene nin-gn tipo de control.

    El bucle principal del juego (o mainloop), donde se desarrolla la accin dela partida.

    Por un lado, cada estado tiene un gestor de eventos propio que se encarga deprocesar todos los eventos que estn permitidos mientras nos encontremos enel estado. Por ejemplo, en el estado de conexin de red tendremos un sistemaque simplemente tratara los eventos de red, e ignorar otro tipo de eventos, oen un estado en que tenemos pausado el juego, nuestro gestor de eventos tanslo reaccionar cuando se pulse una determinada orden.

    Adems, cada estado tiene que renderizar la pantalla para mostrar la informa-cin necesaria para que el usuario pueda interactuar en cada estado. En el casodel men nos puede bastar con un simple engine 2D que sea capaz de mostrarlas opciones al usuario; en cambio, cuando estemos en el bucle principal deljuego posiblemente necesitaremos usar un engine grfico mucho ms comple-jo, como los estudiados en el mdulo de grficos 3D.

    2.1.1. Diagrama de estados

    Un diagrama (o mquina) de estados finitos define una serie de estados y unarelacin entre ellos. De todos los estados, slo uno de ellos est activo y, apartir de una serie de entradas, se realizan transiciones entre estados y cadacambio genera una serie de salidas.

    Podemos decir que la mquina de estados finitos ms estudiada es la mquinade Turing, una mquina terica desarrollada por Alan Turing en 1936 con lacual se pudo definir formalmente el concepto de algoritmo.

    Las caractersticas bsicas de este tipo de estructuras:

    Se pueden implementar con un cdigo muy sencillo y limpio. Son estructuras fciles de depurar. El cdigo de control es mnimo y no generan "overhead". Son muy intuitivas.

    Las mquinas de estado finito se pueden representar mediante grafos, dondecada vrtice corresponde con un estado y las aristas definen las transicionesentre estados. En las aristas podemos incluir informacin como, por ejemplo,condiciones que deben cumplirse.

    Mediante un diagrama de estados podemos visualizar las posibles transicionesque existen entre los diferentes estados del juego. ste es un ejemplo de unposible diagrama de estados para un juego:

  • CC-BY-NC-ND PID_00188520 30 Lgica del videojuego

    Despus de mostrar algunos vdeos introductorios en un primer estado, el estadoque se carga es el del men, donde tratamos slo aquellos eventos que nos permitanseleccionar qu queremos hacer en el juego: jugar nosotros solos, crear un servidorde juegos, conectarnos a un servidor, modificar las opciones de juego o salir.

    En las pantallas del men se configura el comportamiento que tendr nuestro juego.Podemos modelar cada una de estas opciones dentro de un estado propio o ponerlasen un estado ms genrico que incluya toda la configuracin del juego.

    Una vez el usuario haya seleccionado un tipo de juego, podemos empezarlo mos-trando una animacin o vdeo (para posicionar los personajes, etc...), y finalmentepasamos el control al estado que permite jugar al usuario. All todo gira alrededor delbucle principal, que es donde se encuentra implementado el autntico juego.

    Una vez finalice el juego, devolveremos el control al estado del men.

    Nota

    Los diagramas de estado tambin se pueden utilizar para la implementacin de la lgicade todas las entidades de un juego (enemigos, puertas, puzles...). Para los objetos sencilloses una buena opcin (puerta cerrada - abriendo - abierta - cerrando), pero para entidadesms complejas, mejor utilizar otras tcnicas como las que se vern en el punto 2.1.3. olas que se vern en el contenido de Inteligencia artificial.

    2.1.2. El gestor de estados

    La forma tradicional de implementar un sistema de estados ha sido siempreutilizando comandos bucles 'if' y 'case'. Slo tenemos un programa principal, yen cada paso del bucle buscamos el estado en el que estamos y all ejecutamosel cdigo para tratarlo:

    main.c

    int main()

    {

    // Inicializaciones...

    for(;;) // Bucle principal

  • CC-BY-NC-ND PID_00188520 31 Lgica del videojuego

    {

    switch(estadoActual)

    {

    case MENU_JUEGO:...

    case OPCIONES:...

    case JUEGO:...

    }

    }

    return 0;

    }

    El problema de esta implementacin es que no nos permite tener varios mo-tores grficos o gestores para cada uno de los estados del juego. Adems, cadavez que recibimos una entrada de teclado o de red, tenemos que mirar si estoprovoca un cambio de estado, con lo que es ms fcil tener incoherencias enel sistema. Todo esto hace que el programa principal sea difcil de seguir y, portanto, difcil de mantener y depurar.

    Otra alternativa ms eficiente es utilizar la ingeniera del software explicadaen el apartado anterior para disear e implementar un gestor de estados quenos permita modular el comportamiento de los mismos. Un gestor de estadosse compone de dos partes:

    Cada estado es una clase que implementa una serie de funciones comu-nes: iniciar el estado, finalizar el estado, actualizar la pantalla, gestionardeterminados eventos,...

    Tenemos un controlador de estados que se encarga de indicar cul es elestado que se encuentra activo en todo momento y permite cambiar a otroestado.

    Para crear los diferentes estados podemos basarnos en la siguiente interfaz:

    IState.h

    class IState

    {

    public:

    public:

    virtual void enter() = 0;

    virtual void leave() = 0;

    virtual void pause() = 0;

    virtual void resume() = 0;

    virtual void update(double timeElapsed) = 0;

    };

  • CC-BY-NC-ND PID_00188520 32 Lgica del videojuego

    A partir de esta interfaz, podemos crear una serie de clases que definan nuestrosestados, como por ejemplo: MenuState, JugarState, OpcionesState,...

    MenuState.h

    #include

    class MenuState

    : public IState

    {

    private:

    StateManager* m_manager;

    int options;

    public:

    MenuState()

    { }

    // IState members

    public:

    void enter() { /* Dibujar men */ }

    void leave() { /* Limpiar men */ }

    void update(double timeElapsed)

    {

    // Mirar entrada de datos y actuar

    }

    };

    Para coordinar todos los estados, deberemos crear un controlador de estados,al que podemos llamar StateManager. El StateManager debe proporcionar fun-ciones para seleccionar el estado actual o guardar un estado temporalmente(por ejemplo, si hacemos una pausa). Pasamos a ver un ejemplo de la imple-mentacin de un StateManager:

    StateManager.h

    class StateManager

    {

    private:

    std::hash m_states;

    IState* m_current;

    public:

    StateManager() : m_current(NULL) { }

    void registerState(const std::string& name, IState* state)

    {

    m_states[name] = state;

    }

    void changeTo(const std::string& name)

    {

    if (m_current != NULL)

  • CC-BY-NC-ND PID_00188520 33 Lgica del videojuego

    m_current->leave();

    m_current = m_states[name];

    m_current->enter();

    }

    void update(double timeElapsed)

    {

    if (m_current != NULL)

    m_current->update(timeElapsed);

    }

    };

    2.1.3. Diagrama de estados y subestados

    Hemos visto que un diagrama de estados mantiene un estado concreto y definequ transiciones existen entre varios estados y qu acciones deben realizarseen estos cambios.

    Es posible que dentro de un estado queramos definir varios tipos de subesta-dos. Por ejemplo, podemos tener un estado que define la navegacin por elmen del juego. En el men de opciones, podemos presentar varios subesta-dos: sonido activo - desactivando - desactivado - activando (haciendo fade-iny fade-out del sonido como parte de una animacin).

    Figura 2. Ejemplo de un diagrama de estados con subestados

    Este tipo de estructuras necesitan de una implementacin ms compleja. Paraello, es una buena opcin utilizar libreras que permitan facilitar esta tarea.Por ejemplo, usando boost statechart.

  • CC-BY-NC-ND PID_00188520 34 Lgica del videojuego

    Sistemas con mltiples estados simultneos

    En muchos de los juegos podemos encontrarnos que tenemos diferen-tes estados para un objeto, como por ejemplo saltar y golpear, donde,en cada uno de estos estados, el objeto requiere de un tipo de anima-cin, tiene su propia lgica y tiene una duracin asociada al mismo.El problema reside en que muchas veces queremos que el objeto pue-da encontrarse en dos estados de forma simultnea, como por ejemplosaltar y golpear a la vez, lo que implica que debemos controlar qu pasaen ambos estados.

    Hay varias formas de tratar con sistemas con estados simultneos:

    La ms simple es eliminar la concurrencia y transformar las combi-naciones de estados en nuevos estados exclusivos. Por ejemplo, po-dramos separar saltar, golpear y saltar+golpear en tres estados dife-rentes con sus transiciones entre ellos y usar una mquina de esta-dos sencilla. Esta solucin no requiere cdigo extra, pero en cambioes poco escalable: si hay muchas opciones la mquina de estadospuede crecer exponencialmente.

    Una segunda opcin es utilizar los diagramas de estados con subes-tados como los vistos en el apartado 2.1.3. La complejidad en estecaso se encuentra en la programacin de los estados, pero en cam-bio es un sistema muy extensible y fcil de controlar.

    La tercera opcin es utilizar un sistema de scripting como el que sepresenta en el apartado 5.

    2.2. El controlador principal

    Si utilizamos un sistema basado en estados, necesitamos crear otra clase espe-cial que nos permita acceder a los componentes nicos del sistema (el gestorde entrada, de red,...) y a los datos globales del sistema. A esta clase la llama-remos el Controlador Principal, y tiene dos requisitos bsicos:

    Slo puede existir una instancia de la clase, que es creada por el programaprincipal.

    Debe ser visible desde todos los estados que hayamos definido en el sistemapara que stos puedan utilizar los recursos compartidos.

    Si utilizamos esta clase como el elemento central de nuestro programa, el c-digo del programa principal nos quedar extremadamente simple:

    main.cpp

  • CC-BY-NC-ND PID_00188520 35 Lgica del videojuego

    #include

    int main()

    {

    CoreManager* core = new CoreManager();

    core->run();

    delete core;

    }

    Por otro lado, os presentamos una implementacin de un controlador princi-pal. Fijaos que simplemente cumple con los requisitos que hemos detalladoal principio. Se trata de un singleton, con lo que slo se puede instanciar unavez, e incluye todos los recursos globales y las funciones para acceder a ellos.

    CoreManager.h

    class InputManager;

    class CoreManager

    : public Singleton

    {

    public:

    static CoreManager* getSingletonPtr();

    static CoreManager& getSingleton();

    public:

    CoreManager(); // Inicializacin de los recursos

    ~CoreManager(); // Finalizacin de los recursos

    public:

    int run(); // Inicio del gestor de estados

    public:

    // Funciones para acceder a los recursos globales

    InputReader* getInputReader() { return m_inputReader; }

    private:

    // Recursos globales

    InputReader* m_inputReader;

    }

    En la programacin de la clase tenemos que poner especial nfasis en dos fun-ciones: el constructor de la clase, donde vamos a inicializar todos los recursos,y la funcin "run", que es llamada por el programa principal para encender algestor de estados y pasar el control del juego al primer estado.

  • CC-BY-NC-ND PID_00188520 36 Lgica del videojuego

    2.3. El bucle principal del juego

    El bucle principal del juego es la parte que se ejecuta continuamente y es dondese produce todo el desarrollo de la partida.

    El bucle se puede ejecutar de dos formas posibles:

    Podemos ejecutar el bucle cada vez que se genera un evento especial, comopor ejemplo cada vez que tenemos que refrescar la pantalla.

    Otra opcin es estar ejecutndolo todo el tiempo utilizando alguna tcnicamultihilo.

    En ambos casos es necesario que sincronicemos las repeticiones del bucle conun timer, ya que en la mayora de los juegos necesitamos mantener una velo-cidad constante de ejecucin que sea independiente de la capacidad grficay de los recursos que tenga el sistema (es decir, que el juego funcione igualindependientemente del hardware que tenga el sistema).

    Una forma de implementar el timer es aadir al principio del bucle una com-probacin que mire cunto tiempo ha pasado desde la ltima vez que actuali-zamos el estado global Si no ha pasado el suficiente tiempo, podemos simple-mente saltarnos el bucle y esperar hasta que toque actualizar. El nmero deveces que se ejecuta el bucle debera ser mayor de 25 veces por segundo paratener fluidez en la representacin grfica.

    Antes de empezar a ejecutar el bucle principal del estado donde vamos a jugarla partida, es muy importante que se cumplan los siguientes requisitos:

    Cada elemento hardware necesita su propio driver especfico para que sepuedan interpretar todas las seales que se originen en el controlador.

    Todos los recursos deben estar cargados e inicializados.

    Todos los sistemas deben estar inicializados y tener acceso a los datos quenecesitan para poder trabajar (Lgica, Grficos, Red, Sonido, IA, Fsica,etc.).

    El bucle principal est compuesto por tres fases principales: la recogida de da-tos, el clculo del nuevo estado global del juego y la redistribucin de los cam-bios. Estas fases las podemos desglosar ms detalladamente en la siguiente se-cuencia:

    Recoger la entrada de datos: lo primero que hacemos es mirar si el usuarioha realizado alguna accin desde la ltima vez que entramos en el bucle.En el caso de un sistema buffered comprobaremos si ha habido algn cam-bio en el estado del buffer. En el caso de un sistema unbuffered comproba-

    Nota

    Parece ser que el ojo humanoes capaz de ver un vdeo sinsaltos cuando se emiten un m-nimo de 25 imgenes por se-gundo.

  • CC-BY-NC-ND PID_00188520 37 Lgica del videojuego

    remos si tenemos algn aviso de alguna entrada que nos haya dejado elcontrolador de entrada.

    Recoger los datos de la red: si tenemos un juego multijugador, comproba-remos si se han recibido nuevos datos. Miraremos el buffer de paquetesy nos quedaremos con aquellos que nos interesen en el estado en el quenos encontremos. Es importante recordar que no bloquearemos el sistemaesperando los paquetes, tan slo vamos a tratar aquellos que ya hayan lle-gado.

    Recoger las decisiones de la inteligencia artificial: en esta fase recibimoslas nuevas posiciones de los objetos que se encuentran controlados por lainteligencia artificial. Existen dos formas de obtener esta informacin: laprimera es lanzar una funcin que nos determine las decisiones de la IAen este momento, y la segunda es tener un proceso paralelo que siempreest calculando decisiones y al que vamos a consultar qu es lo mejor queha decidido hasta este momento.

    Procesar todas las entradas con el motor lgico del juego. Esta fase slo sepuede ejecutar una vez hemos recibido la entrada de las tres fases anterio-res. La podemos subdividir en dos subfases: Control de fsica y de colisiones: calculamos si las posiciones y accio-

    nes que se piden se pueden llevar a cabo o si existen interaccionesentre los elementos. En este caso el sistema de fsica decide cul esel movimiento real de los elementos. La salida de esta fase indica lasposiciones finales de los objetos en el mundo. Los clculos de esta fa-se siempre se realizan en un tiempo mximo definido que permita lasensacin de fluidez al usuario.

    Control de la lgica del juego: miramos que se estn cumpliendo lasreglas del juego y que el comportamiento de los elementos est dentrode los mrgenes. Tambin miramos si el juego ha finalizado en esteltimo paso. Finalmente, actualizamos todas las variables globales dela partida: tiempos, puntuaciones...

    Distribucin de los resultados: la salida del sistema de lgica (posiciones,variables...) se tiene que hacer llegar a todos los componentes que lo ne-cesiten, al sistema grfico, a la inteligencia artificial y a todos los jugadoresconectados por red.

    Actualizacin de los dispositivos de salida: finalmente reproducimos lossonidos que corresponda y actualizamos el motor grfico para que mues-tre todos los cambios. Puede ser necesario que tengamos que hacer algu-nos clculos extras, como por ejemplo recolocar la cmara para que sigaa nuestro personaje.

  • CC-BY-NC-ND PID_00188520 38 Lgica del videojuego

    La implementacin de este bucle principal se debe realizar ntegramente den-tro de cada estado donde tenga lugar el desarrollo de la partida. En otros esta-dos podemos eliminar algunos de estos puntos (normalmente el de lgica).

    A continuacin presentamos un ejemplo de la implementacin de un buclede juego principal:

    GameState.h

    #include

    class GameState

    : public IState

    {

    private:

    StateManager* m_manager;

    int options;

    public:

    MenuState()

    { }

    // IState members

    public:

    void enter() { /* Inicializar nivel del juego */ }

    void leave() { /* Liberar recursos del nivel del juego */ }

    void update(double timeElapsed)

    {

    CoreManager& core = CoreManager::singleton();

    core.lecturaDatosEntrada(timeElapsed);

    core.lecturaDatosDeRed(timeElapsed);

    core.lecturaDatosIA(timeElapsed);

    core.getFisica().update(timeElapsed);

    core.getLogica().updateReglasDeJuego(timeElapsed);

    core.enviarCambiosDeEstadoPorRed(timeElapsed);

    core.modificarDispositivosSalida(timeElapsed);

    }

    };

  • CC-BY-NC-ND PID_00188520 39 Lgica del videojuego

    3. El motor lgico de un videojuego

    En los mdulos anteriores hemos tratado algunas de las tecnologas que sonnecesarias para poder desarrollar un videojuego. La mayora de estas tecnolo-gas son genricas y pueden utilizarse en otro tipo de aplicaciones.

    En el primer mdulo del curso definimos un juego como un conjunto de ob-jetivos que tenemos que conseguir siguiendo unas reglas. La implementacinde estas reglas, y por tanto del juego propiamente dicho, se lleva a cabo en loque llamamos el motor lgico de un videojuego (tambin llamado motor delgica). Tecnolgicamente hablando, el motor lgico es el componente msimportante de un videojuego y se encarga, entre otras cosas, de:

    Inicializar el contenido del juego y crear el mundo donde se desarrollarla accin.

    Determinar cundo empieza y cundo termina una partida.

    Implementar las reglas que controlan las acciones de los jugadores y con-trolar que estas reglas se cumplen durante el desarrollo de la partida.

    Permitir que los jugadores interacten con el entorno sin romper estasreglas.

    Controlar el estado de todos los elementos que estn participando en lapartida, desde las posiciones de los avatares hasta las variables globales dela partida: tiempo de juego, puntuacin, resultados...

    3.1. El mundo lgico del juego

    El motor lgico utiliza su propia descripcin del mundo donde se desarrollala accin, completamente diferente del que hemos visto anteriormente en elapartado grfico. Este mundo est compuesto principalmente de las descrip-ciones y los atributos de los elementos que se encuentran en l. Por ejemplo,los personajes los representamos mediante cajas con posiciones y vectores, sintener en cuenta la forma real que tienen ni la animacin que se est reprodu-ciendo en este momento.

  • CC-BY-NC-ND PID_00188520 40 Lgica del videojuego

    Esta simplificacin es necesaria para que el ordenador pueda interpretar entodo momento el estado del juego. Por ejemplo, para el sistema de inteligenciaartificial no es necesario conocer si un personaje es un orco de color verde orojo para tomar una decisin de qu hacer con l, simplemente est interesadoen el tamao, la posicin y la direccin en la que est mirando este orco.

    Reflexin

    Durante el desarrollo de un videojuego, a veces es interesante poder observar el mundolgico y el mundo fsico/grfico por separado o conjuntamente. Esto permite trabajar conms detalle con uno u otro y depurar mejor los posibles problemas existentes en cadauno, ya que, de otra manera, podramos tener un exceso de informacin en pantalla.

    La representacin visual del mundo lgico se hace normalmente con grficos sencillosbasados en lneas y textos. Esta representacin se tiene que disear con cuidado, inten-tando simplificar la informacin que mostramos, pero que a la vez podamos ver repre-sentado todo aquello que el sistema est observando del juego.

    3.1.1. Discretizacin del mundo

    Una de las primeras tareas que tenemos que hacer para definir el mundo lgi-co es realizar una discretizacin del mundo real que vamos a utilizar. Depen-diendo del tipo de juego y de los recursos del sistema, utilizaremos una sim-plificacin con ms o menos detalle.

    La discretizacin permite organizar con mayor eficiencia la distribucin delos objetos en el mundo y nos permite asignar diferentes propiedades a lospolgonos que componen el mundo discreto. Por ejemplo, en un juego decoches podemos asignar una propiedad a cada polgono para representar lafriccin del suelo.

    Nota

    Los polgonos que utilizamos para la discretizacin del mundo y los polgonos que utili-zamos en los grficos pueden coincidir, aunque esto no es una condicin necesaria. Enalgunos casos nos puede interesar tener polgonos ms grandes o ms pequeos en elmundo lgico para proporcionar informacin extra al sistema.

    Mediante la discretizacin, tambin podemos crear un grafo que determine losposibles caminos entre dos puntos del mundo lgico, y mediante algoritmosde bsqueda de caminos podemos calcular las rutas de los elementos mvilesdel sistema.

    Existen dos tcnicas comunes para discretizar el mundo, sobreponer un gridregular encima del mundo o extraer una malla de navegacin a partir de lageometra:

    Grid regular

    Un grid es una teselacin de polgonos. Cuando lo sobreponemos encima delmundo, podemos determinar qu parte del mundo est dentro o fuera de nues-tro grid, y adems podemos segmentar la parte interior en polgonos regulares.

    Nota

    Ya vimos tcnicas parecidas dediscretizacin del mundo (oc-trees, BSP) en los mdulos quetrataban los videojuegos 2D y3D.

  • CC-BY-NC-ND PID_00188520 41 Lgica del videojuego

    Figura 3. Ejemplo de un mapa con un grid rectangular (izquierda) y del resultado de la discretizacin (derecha)

    Cuanto ms detalle utilicemos para el grid, mayor ser la resolucin de nuestrosistema, pero tambin necesitamos ms espacio para guardarlo y mayor serel tiempo para calcular caminos sobre el mismo. Tambin podemos utilizaralgunas de las tcnicas vistas anteriormente en el mdulo de grficos para tenerdiferentes niveles de resolucin, como por ejemplo octrees o BSPs, aunquetendremos que tener en cuenta que el uso de diferentes niveles jerrquicospuede complicar el proceso de bsqueda de caminos.

    Para el clculo de caminos, conectaremos con una lnea el centro de todo parde polgonos adyacente. Para esto necesitaremos el grafo de todas las rutasexistentes en este grid. En el caso del grid cuadrangular, es importante consi-derar si podemos ir directamente a las casillas que se encuentran en diagonal.

    Malla de navegacin

    Una malla de navegacin es una particin de la geometra del mundo lgicoen polgonos convexos como los que acabamos de describir. En otras palabras,es un conjunto de polgonos que cubre por completo el mapa, donde cada parde polgonos slo comparte dos puntos y una lnea. Cada polgono representaun punto de un camino que est.

    El hecho de que sean convexos garantiza que slo nos podamos mover enlnea recta dentro de un polgono. Hay gran cantidad de algoritmos que nospermiten realizar esta subdivisin en polgonos convexos, sobre todo a nivelde tringulos.

    Nota

    Un grid regular slo puede es-tar compuesto por tres tiposde polgonos: tringulos equi-lteros, cuadrados o hexgo-nos.

    En este caso podemos asignar los puntos de los caminos desde dos posiciones,en el centro de cada polgono o en el centro de cualquier arista que conectedos polgonos diferentes.

    Nota

    Hay varios tipos de triangula-cin, pero quizs el ms utili-zado sea el que cumple la con-dicin de Delaunay.

  • CC-BY-NC-ND PID_00188520 42 Lgica del videojuego

    Figura 4. Ejemplo de una malla de navegacin con los caminos usando los centros de los polgonos (izquierda) o las aristas(derecha)

    3.2. Tareas del motor de lgica

    El motor de lgica es el encargado de controlar el desarrollo del juego. Recibede todos los sistemas de entrada (jugadores o IA) las acciones que han tomadolos jugadores en un turno, decide qu sucede con ellas, calcula el nuevo estadoglobal del juego y devuelve este estado al sistema de lgica y a los dispositivosde salida para informar de lo que ha ocurrido.

    Vamos a estudiar con ms detalle una posible secuencia de todo lo que sucedeen el motor de lgica cada vez que tenemos que actualizar el sistema en cadaiteracin o 'turno'. El orden de las tareas que ponemos a continuacin no esestricto y se puede reestructurar para adaptarse a las necesidades de cada juegoen concreto.

    3.2.1. Aplicar movimiento de los elementos del juego

    Para poder cambiar el estado del juego, el motor de lgica necesita recibir porparte de todos los elementos 'mviles' o 'activos' del juego la informacin delas acciones que han tomado en cada momento (si es que han decidido realizaralguna).

    Una de las primeras tareas que debemos realizar en cada iteracin de este mo-tor es calcular las nuevas posiciones de todos los elementos. Tenemos dos po-sibles orgenes de movimiento:

    Los elementos controlados por jugadores: la informacin de movimientopuede venir dada de varias maneras (posiciones relativas, absolutas, velo-cidad o aceleracin...). Esto depende de cmo interpretemos la entrada delusuario y el estado actual del jugador. Por ejemplo, si tenemos un cochemovindose con una cierta velocidad, aunque el usuario no realice nin-guna accin en esta iteracin tenemos que considerar que el elemento sesigue moviendo.

  • CC-BY-NC-ND PID_00188520 43 Lgica del videojuego

    Los elementos no controlados por jugadores: estos movimientos nos loproporciona el sistema de inteligencia artificial. Algunos de ellos son mo-vimientos cclicos, con una ruta prefijada, y por tanto fcil de calcular.Otros movimientos son ms complejos y requieren de la observacin delestado del mundo para poder tomar decisiones. El sistema de inteligenciaartificial puede enviar la informacin de varias maneras, as que en estecaso tambin tendremos que interpretar el movimiento y traducirlo a po-siciones reales para cada elemento.

    Una vez hemos calculado todas las posiciones, entra en escena el clculo decolisiones entre los elementos. Aunque lo hayamos introducido en el mdulode grficos, la fsica y el control de colisiones los realiza el motor lgico usan-do la informacin contenida en su representacin del mundo y no el motorgrfico.

    Nota

    Las tcnicas bsicas para sabersi dos objetos colisionan se en-cuentran explicadas en el m-dulo que trata de videojuegos2D.

    La funcin que calcula las colisiones nos devuelve las posiciones finales de to-dos los movimientos realizados en esta iteracin. Slo queremos remarcar quees importante decidir qu elementos tienen prioridad sobre otros al calcularlas nuevas posiciones, ya sea utilizando sus propiedades fsicas (un objeto conms masa y velocidad ocupar el lugar de otro con menos) o utilizando prio-ridades que asignemos nosotros a los objetos.

    Una vez pasado este filtro, falta una ltima comprobacin donde miramosque las posiciones finales de los elementos cumplan con las reglas del juego,es decir, que la posicin final de cada elemento se encuentre dentro de unazona permitida para l.

    3.2.2. Aplicar acciones de los elementos del juego

    La segunda tarea del motor de lgica es la de llevar a cabo todas las otras accio-nes que realizan los elementos descritos en el apartado anterior. La naturalezade estas acciones puede ser muy variada, ya sea lanzar un hechizo, chutar unbaln o construir una granja.

    Nota

    Tenemos libertad, estamosimplementando un videojuegoy no un simulador de fsica!

    Lo primero que tenemos que hacer es ver si las acciones se pueden llevar acabo. Para eso tenemos que comprobar que el elemento que realiza la accintiene todo lo necesario para llevarla a cabo. Por ejemplo, en el caso del hechizo,que el personaje tenga los atributos u objetos necesarios (energa, reactivos,...),o en el caso del jugador, que tenga la posesin del baln.

    En segundo lugar, tenemos que mirar que la accin no infrinja las reglas deljuego y que, por tanto, se pueda efectuar. Por ejemplo, aunque tengamos su-ficiente dinero para construir la granja, el sistema tiene que comprobar que laconstruimos en una posicin donde est permitida por las reglas del juego.

    Reflexin

    Debemos tener en cuenta queel estado de un elemento pue-de intervenir en el estado deotro. As, si tenemos un juga-dor que est dando un pue-tazo mientras salta y otro ob-jeto lo mata, el jugador ya nopodr herir a nadie mientrascae al suelo.

  • CC-BY-NC-ND PID_00188520 44 Lgica del videojuego

    Reflexin

    Es importante decidir quin realiza primero cada accin, sobre todo en el caso de quela accin afecte a otros elementos del juego. Una accin puede cambiar los atributos deotro elemento y evitar que ste pueda llevar a cabo la suya. Por ejemplo, si dos jugadoresse atacan entre s, es posible que el primero acabe con el segundo y que ste ya no puededevolver el golpe.

    Por lo tanto, es muy importante decidir la prioridad de las acciones de loselementos para no perjudicar a nadie. Existen varias formas de decidir el ordende las acciones:

    Una forma es utilizar un sistema round-robin, en el que siempre se utilizael mismo orden de procesamiento de acciones.

    Otra posibilidad es seleccionar el orden en que se llevan a cabo las accionesde forma aleatoria. En este caso slo utilizaremos la aleatoriedad cuandolas acciones se solapen, en otro caso podemos seguir con un round-robin.

    Finalmente, la opcin ms elegante es asignar prioridades a las acciones.Esta opcin se puede complementar con las dos anteriores.

    Una vez realizada cada accin, se computan los cambios del entorno debidosa la misma y se guardan en todos los elementos que se han visto afectados.

    Reflexin

    Cada vez es ms importante tener en cuenta la programacin multihilo porque los nuevosordenadores y videoconsolas se montan con varios procesadores.

    Si se quiere aprovechar al mximo la potencia de estos sistemas, es necesario trabajarcon algoritmos concurrentes y tener mucho cuidado con los errores comunes que tienenasociados.

    3.2.3. Clculo del nuevo estado del juego

    Finalmente, una vez todos los elementos se han movido y han actuado, esnecesario recalcular el estado del sistema y actualizar las variables globales.Este paso se realiza al final de todas las acciones para poder integrar el resultadode la actuacin de los elementos de esta iteracin. Algunas de las tareas quedebemos realizar en este paso final son:

    Incrementar el tiempo del juego proporcionalmente. Por ejemplo, hay jue-gos donde es importante la distincin entre noche y da.

    Comprobar si el juego ha llegado a su fin. En este caso tendremos queinformar al bucle principal que tenemos que cambiar de estado para dejarde procesar las entradas del usuario.

    Comprobar si se ha cumplido algn objetivo intermedio y, por lo tanto,si es necesario cambiar.

    Round-robin

    Round-robin es un algoritmopara repartir un recurso en-tre varios procesos de maneraequitativa.

  • CC-BY-NC-ND PID_00188520 45 Lgica del videojuego

    Toda esta informacin se deja almacenada en las estructuras de datos del sis-tema y se avisa a los componentes que lo necesiten (IA, grficos,...) de todoslos cambios que se han producido para que se puedan actualizar con el nuevoestado del juego.

  • CC-BY-NC-ND PID_00188520 46 Lgica del videojuego

    4. Gestin de los datos de un videojuego

    Los datos que vamos a utilizar en un videojuego son tan importantes como elmotor lgico explicado en el punto anterior. El motor lgico implementa lasreglas, pero sin estos datos no tendremos nada con que jugar.

    Los datos del juego se pueden subdividir en dos grandes grupos:

    En primer lugar, tenemos todos aquellos datos que se utilizan en los mo-tores grfico y sonoro. Estos datos pueden incluir msica, efectos, o mo-delos tridimensionales, texturas o animaciones. A estos datos los llamare-mos entidades.

    Por otro lado, tenemos otro grupo de datos que describe todos los par-metros de los elementos que intervienen en el juego. A estos datos los lla-maremos objetos y pueden incluir desde posiciones, direcciones y veloci-dades, hasta atributos de los personajes. Estos datos son utilizados por elmotor lgico para poder evaluar continuamente el estado del juego.

    Cada estado del juego tendr sus propias entidades y objetos locales. Adems,podr utilizar todos aquellos que se encuentren definidos de forma global atravs del uso del controlador principal del juego que hemos explicado ante-riormente.

    En este apartado vamos a describir los diferentes tipos de objetos y entidades,cmo se implementan en el cdigo del programa y, finalmente, cmo se al-macenan en el disco.

    4.1. Objetos y entidades

    Para cualquier tipo de juego existen una serie de objetos comunes que nor-malmente utilizamos.

    Objeto terreno o entorno: slo existe una copia de este objeto y definela base de nuestro juego. Normalmente este objeto est compuesto poruna nica entidad grande (por ejemplo, la malla donde se posicionan elresto de objetos) y en l incluimos variables globales que influyen en elcomportamiento global del sistema (por ejemplo, la gravedad).

    Objetos estticos: objetos que se encuentran sobre el terreno con unas ca-ractersticas (posicin, tamao, etc., prefijadas desde el principio). Inclu-yen una o varias entidades para poderlos representar en la pantalla. Pue-den estar animados o no.

  • CC-BY-NC-ND PID_00188520 47 Lgica del videojuego

    Objetos mviles: se trata del principal grupo de objetos del juego. Aqu in-cluiremos aquellos objetos que se desplazan e interactan con el entorno,tanto si estn controlados por un jugador como si estn controlados por lainteligencia artificial. Estn compuestos por una o varias entidades, ade-ms de tener incorporados varias animaciones para cada una de las accio-nes que realizan. Estos objetos incorporan varios niveles de informacinpara el sistema lgico que depender de su importancia. Por ejemplo, sise trata de una caja que podemos desplazar, tendremos propiedades fsicascomo su masa o la resistencia a romperse. En cambio, si es un personajetendremos muchsimos ms datos asociados a este objeto (vidas, armas,atributos, etc.).

    Objetos de control: los objetos de control son objetos que no estn rela-cionados con ninguna entidad y por tanto son invisibles al usuario. Se tra-ta de objetos que son necesarios para que sistemas como la IA o el motorlgico del juego puedan conocer ms detalles sobre el mundo donde sedesarrolla la partida. Por ejemplo, en un juego de carreras podemos tenerun objeto de control que nos indique el camino ptimo dentro de la pistapara que la IA pueda calcular las posiciones de los coches.

    Reflexin

    Para poder almacenar y organizar todos los objetos y entidades que tenemos activos ennuestro juego, lo ms fcil es utilizar las estructuras de datos que se utilizan en todo tipode aplicaciones informticas:

    Para representar secuencias de datos, podemos usar vectores, matrices, listas, pilas ocolas.

    Para representar una jerarqua u organizacin, tenemos los rboles y los heaps.

    Para representar las relaciones entre objetos o entidades, podemos utilizar los grafos.

    La gestin de las estructuras de datos las podemos programar nosotros mismos, pero qui-zs es recomendable el uso de alguna API externa que sea contratada. Si programamosusando C++, podemos utilizar la librera STL (standard template library), que incluye es-tructuras de datos genricos que nos permiten gestionar todo tipo de elementos median-te el uso de templates.

    Nota

    Es una buena idea implemen-tar los objetos mviles usandomquinas de estado finitas co-mo los vistos en el punto 2.

  • CC-BY-NC-ND PID_00188520 48 Lgica del videojuego

    Los objetos y las entidades normalmente se encuentran enlazados entre s for-mando estructuras ms complejas. Esto permite mucha ms flexibilidad, yaque podemos combinar objetos y entidades para describir los elementos queparticipan en el juego.

    4.1.1. Implementacin de un objeto

    La forma ms simple de implementar los objetos es utilizando estructuras dedatos. En una estructura de datos describimos todas las variables que estnasociadas a un objeto, tanto las que se usan en la parte lgica como las quese usan para grficos o sonido.

    struct orco

    {

    int posicion_x, posicion_y, posicion_z;

    int armadura, int arma;

    int vida_total, vida_restante;

    Entidad3D *malla;

    Onda *sonidos;

    }

    Como hemos visto en el primer apartado de este mdulo, el problema de estasestructuras de datos es que son muy poco flexibles y seguras. Adems, las fun-ciones que utilizan estos datos se implementan de forma independiente a laestructura, con lo que la organizacin en mdulos es ms difcil de controlar.

    Para facilitar el acceso a los datos de una forma ms segura, la mejor opcin esimplementar una clase que los abstraiga y que nos proporcione una interfazpara poder acceder a ellos. De esta forma podremos controlar mejor el accesoa los datos. Tambin tendremos juntos los datos y las funciones que trabajendirectamente sobre ellos (como por ejemplo las funciones encargadas de ac-tualizar la animacin hacia el siguiente paso).

    Por ejemplo, la clase Orco debe disponer de un constructor donde inicialice-mos el estado de todas las variables, funciones para leer y escribir estas varia-bles (ya sea de forma directa o indirecta), y funciones que permitan actualizartodo el sistema.

    class Orco

    {

    public:

    Orco(const std::string& fichero_datos);

    ~Orco();

    void setPosicion_x(int position) { posicion_x = position; };

    int getPosicion_x() { return posicion_x };

    ...

  • CC-BY-NC-ND PID_00188520 49 Lgica del videojuego

    void update(); // Actualizar el objeto: animaciones...

    private:

    int posicion_x, posicion_y, posicion_z;

    int armadura, int arma;

    int vida_total, vida_restante;

    Entidad3D *malla;

    Onda *sonidos;

    };

    Cada vez que queramos una copia de este objeto, simplemente necesitaremoscrear una nueva instancia. Esta instancia cargar todos los datos que estnespecificados en el fichero que le pasamos como parmetro al constructor einicializar todas las variables del objeto. Una vez tengamos la clase creada, yapodemos acceder a los datos.

    Otra ventaja de la utilizacin de clases es que podemos utilizar la jerarqua declases para representar la jerarqua de objetos que hemos comentado anterior-mente y las relaciones entre los diferentes datos. Mediante el uso de interfacesy la herencia de clases, es mucho ms fcil definir cmo acceder a los datosentre clases de una forma clara y segura.

    Reflexin

    Un error que se comete continuamente es la prdida de memoria debido al mal uso de lamemoria dinmica. Para minimizar el riesgo, es muy recomendable utilizar estructurasque abstraigan al programador de la tarea de reservar y liberar memoria dinmica. Porejemplo, podemos utilizar un patrn Factory que no slo cree las instancias de los objetos,sino que mantenga una lista de los objetos creados y que permita destruirlos.

    En el siguiente ejemplo definimos la clase Orco, que contendr el constructory el destructor privados. Con esta condicin slo ser posible crear un objetode la clase Orco dentro de la propia clase o desde la clase ObjectManager, yaque indicamos que es una clase amiga:

    Orco.h

    #pragma once

    #include

    class ObjectManager;

    class Orco

    {

    private:

    friend class ObjectManager;

    Orco();

    virtual ~Orco();

    public:

    Nota

    Recordad que las funciones deestas clases deben estar muyoptimizadas ya que se llama-rn continuamente y desde di-ferentes puntos del juego (gr-ficos, sonido, IA,...).

  • CC-BY-NC-ND PID_00188520 50 Lgica del videojuego

    const Vector4& pos() const { return m_pos; }

    Vector4& pos() { return m_pos; }

    void update();

    private:

    Vector4 m_pos;

    };

    Orco.cpp

    #include

    #include

    Orco::Orco()

    {

    std::cout

  • CC-BY-NC-ND PID_00188520 51 Lgica del videojuego

    ObjectManager.h

    #pragma once

    #include

    #include

    class ObjectManager

    {

    public:

    ObjectManager();

    virtual ~ObjectManager();

    public:

    Orco *createOrco();

    void destroyOrco(Orco *orco);

    private:

    typedef std::set OrcoSet;

    OrcoSet m_orcos;

    };

    Y su cdigo:

    ObjectManager.cpp

    #include

    #include

    ObjectManager::ObjectManager()

    {

    }

    ObjectManager::~ObjectManager()

    {

    for(OrcoSet::iterator it = m_orcos.begin(); it != m_orcos.end(); ++it)

    {

    std::cout

  • CC-BY-NC-ND PID_00188520 52 Lgica del videojuego

    m_orcos.insert(result);

    return result;

    }

    void ObjectManager::destroyOrco(Orco *orco)

    {

    OrcoSet::iterator found = m_orcos.find(orco);

    if (found == m_orcos.end())

    std::cout

  • CC-BY-NC-ND PID_00188520 53 Lgica del videojuego

    ObjectManager om;

    Orco *orco1 = om.createOrco();

    Orco *orco2 = orco1;

    Orco *orco3 = om.createOrco();

    om.destroyOrco(orco1);

    om.destroyOrco(orco2);

    return 0;

    }

    Genera la siguiente salida:

    I: Orco::Orco()

    I: Orco::Orco()

    I: Orco::~Orco()

    E: No se puede borrar orco, no existe

    W: Borrando orco desde el destructor del manager

    I: Orco::~Orco()

    4.1.2. Implementacin de objetos usando herencia

    En este punto definiremos a tres enemigos (Troll, Dragon y Orco) con caracte-rsticas similares y configurables por interfaz. Tambin definiremos a un juga-dor. Estos cuatro elementos son entidades que habitan en un mundo virtual.En el siguiente diagrama se detallan las interfaces, clases y sus relaciones quedefinen el ejemplo.

  • CC-BY-NC-ND PID_00188520 54 Lgica del videojuego

    Para empezar, definiremos la interfaz entidad (se omite el cdigo necesariopara el dibujo):

    Entity.h

    #pragma once

    class Entity

    {

    public:

    virtual ~Entity() { }

    virtual void update(double elpasedTime) = 0;

    };

    Tambin definimos una interfaz que indique si una entidad puede volar, bu-cear o andar.

    MovableObject.h

    #pragma once

  • CC-BY-NC-ND PID_00188520 55 Lgica del videojuego

    class MovableObject

    {

    public:

    virtual ~MovableObject() { }

    virtual bool canWalk() const = 0;

    virtual bool canFly() const = 0;

    virtual bool canDive() const = 0;

    };

    Se define un enemigo:

    Enemy.h

    #pragma once

    #include

    #include

    class Enemy

    : public Entity

    , public MovableObject

    {

    public:

    virtual ~Enemy() { }

    public:

    virtual bool isDeath() const = 0;

    virtual double level() const = 0;

    virtual double attackDamage() const = 0;

    // returns "true" if this attack kills himself

    virtual bool receiveAttack(double damage) = 0;

    };

    Se proporciona tambin una implementacin bsica de un enemigo en el si-guiente cdigo:

    EnemyImpl.h

    #pragma once

    #include

    class EnemyImpl

    : public Enemy

    {

    public:

    EnemyImpl();

  • CC-BY-NC-ND PID_00188520 56 Lgica del videojuego

    virtual ~EnemyImpl();

    // Enemy partial implementation

    public:

    bool isDeath() const { return m_health

  • CC-BY-NC-ND PID_00188520 57 Lgica del videojuego

    bool canWalk() const { return true; }

    bool canFly() const { return false; }

    bool canDive() const { return false; }

    // Enemy implementation

    public:

    double level() const { return 10; }

    double attackDamage() const { return 0.2; }

    };

    Dragon.h

    [...]

    class Dragon

    : public EnemyImpl

    {

    [...]

    // MovableObject implementation

    public:

    bool canWalk() const { return false; }

    bool canFly() const { return true; }

    bool canDive() const { return false; }

    // Enemy implementation

    public:

    double level() const { return 30; }

    double attackDamage() const { return 0.4; }

    };

    Troll.h

    [...]

    class Troll

    : public EnemyImpl

    {

    [...]

    // MovableObject implementation

    public:

    bool canWalk() const { return true; }

    bool canFly() const { return false; }

    bool canDive() const { return true; }

    // Enemy implementation

    public:

    double level() const { return 20; }

    double attackDamage() const { return 0.25; }

  • CC-BY-NC-ND PID_00188520 58 Lgica del videojuego

    };

    Por ltimo, la declaracin de un jugador:

    Player.h

    #pragma once

    #include

    #include

    class Player

    : public Entity

    , public MovableObject

    {

    public:

    Player();

    virtual ~Player();

    // Entity implementation

    public:

    void update(double elapsedTime);

    // MovableObject implementation

    public:

    bool canWalk() const { return true; }

    bool canFly() const { return false; }

    bool canDive() const { return true; }

    }

    El controlador de objetos:

    ObjectManager.h

    #pragma once

    #include

    #include

    #include

    class ObjectManager

    {

    public:

    ObjectManager();

    virtual ~ObjectManager();

  • CC-BY-NC-ND PID_00188520 59 Lgica del videojuego

    public:

    template Enemy *createEnemy();

    void destroyEnemy(Enemy *enemy);

    Player *createPlayer();

    void destroyPlayer(Player *player);

    public:

    void update(double elapsedTime);

    private:

    typedef std::set EnemySet;

    typedef std::set EntitySet;

    EnemySet m_enemies;

    EntitySet m_entities;

    };

    template Enemy *ObjectManager::createEnemy()

    {

    Enemy *enemy = new T();

    m_enemies.insert(enemy);

    m_entities.insert(enemy);

    return enemy;

    }

    ObjectManager.cpp

    #include

    ObjectManager::ObjectManager()

    {

    }

    ObjectManager::~ObjectManager()

    {

    }

    void ObjectManager::destroyEnemy(Enemy *enemy)

    {

    m_enemies.erase(enemy);

    m_entities.erase(enemy);

    }

    Player *ObjectManager::createPlayer()

    {

    Player *player = new Player();

    m_entities.insert(player);

  • CC-BY-NC-ND PID_00188520 60 Lgica del videojuego

    return player;

    }

    void ObjectManager::destroyPlayer(Player *player)

    {

    m_entities.erase(player);

    delete player;

    }

    void ObjectManager::update(double elapsedTime)

    {

    for(EntitySet::iterator it = m_entities.begin(); it != m_entities.end(); ++it) {

    Entity* curr = *it;

    curr->update(elapsedTime);

    }

    }

    Y un cdigo de ejemplo que lo utiliza:

    main.cpp

    #include

    #include

    #include

    #include

    #include

    #include

    int main()

    {

    ObjectManager om;

    Enemy *orco1 = om.createEnemy();

    Enemy *orco2 = om.createEnemy();

    Enemy *troll = om.createEnemy();

    Enemy *dragon = om.createEnemy();

    Player *player = om.createPlayer();

    std::cout

  • CC-BY-NC-ND PID_00188520 61 Lgica del videojuego

    std::cout

  • CC-BY-NC-ND PID_00188520 62 Lgica del videojuego

    4.2.1. Implementando un nivel

    Existen dos formas de definir un nivel dentro de nuestro juego, introducin-dolo todo como cdigo fuente o combinando parte de cdigo fuente con losdatos de un fichero externo. La primera opcin es slo factible en un juegopequeo y simple donde no existan muchos objetos ni necesitemos realizarun balanceo final de los mismos (por ejemplo, en un juego de ajedrez proba-blemente podremos organizar todos los objetos dentro del propio cdigo).

    Normalmente, la opcin ms utilizada para implementar un nivel se realizaseparando los datos del cdigo principal. Tan slo necesitaremos programaruna clase que nos permita leer los datos externos necesarios para un determi-nado nivel y distribuirlos por la escena para poder empezar a jugar.

    #ifn