• Martes 14 de Mayo de 2024, 08:53

Autor Tema:  Oop  (Leído 1877 veces)

ibito

  • Miembro HIPER activo
  • ****
  • Mensajes: 549
  • Nacionalidad: mx
  • Se mas de C++ que lo que se de ese CSS
    • Ver Perfil
    • http://www.ibquezada.com
Oop
« en: Martes 28 de Septiembre de 2004, 20:51 »
0
este thread es para los usuarios mas avanzados, como utilizan los objetos a la hora de crear un juego? la duda es para hacerme un concepto ya "aplicado" al momento de programar, se lo que es un objeto, herencia y todas esas cosas que lei en un e-book llamado "Think in Cpp" (muy bueno por cierto),  yo supongo que hacen un objeto player1 con tales y cuales atributos y metodos... espero estar en lo correcto, si pueden poner un ejemplo (no necesita ser muy completo, solo atributos y metodos mini-basicos) se los agradeceria.



Gracias
______________________________________
www.hazjuegos.com Una comunidad dedicada al desarrollo de videojuegos.

BlackWind

  • Miembro activo
  • **
  • Mensajes: 89
    • Ver Perfil
Re: Oop
« Respuesta #1 en: Miércoles 29 de Septiembre de 2004, 04:09 »
0
eso tambien lo puedes hacer con structuras, (me imagino que lo estas haciendo en c++), por ahi lei que  es recomendable eviitar las clases, porque son mas lentas, pero no sabria decirte si es verdad o no,
aqui te va un buen ejemplo con structuras, que lo puedes modificar para que sea una clase:


struct PLAYER {
 {
      int Health;
      int Mana;
      ARMOR Armor
      WEAPON Weapon;
      INV Inv;
      etc...;
 };


la ventaja, es que puedes ahorrar mucho codigo, a la hora de usar metodos, por ejemplo, con las estructuras en vez de poner:

void InitPlayer(int Health, int Mana, ARMOR armor,etc....);

puedes poner:
void InitPlayer(PLAYER Player);

que te contendra todo.......
aunque tambien con las clases puedes hacer eso.....

de todas formas, ese ejemplo de la estructura es totalmente aplicable a las clases....

ibito

  • Miembro HIPER activo
  • ****
  • Mensajes: 549
  • Nacionalidad: mx
  • Se mas de C++ que lo que se de ese CSS
    • Ver Perfil
    • http://www.ibquezada.com
Re: Oop
« Respuesta #2 en: Miércoles 29 de Septiembre de 2004, 07:31 »
0
muchas gracias, a ver como lo aplico ahora  :P


no, en serio si muchas gracias, casi no tengo tiempo por culpa de la escuela pero pues intentare hacerlo en cuanto pueda  ;)
______________________________________
www.hazjuegos.com Una comunidad dedicada al desarrollo de videojuegos.

Ruben3d

  • Miembro HIPER activo
  • ****
  • Mensajes: 710
  • Nacionalidad: es
    • Ver Perfil
    • Web personal
Re: Oop
« Respuesta #3 en: Viernes 1 de Octubre de 2004, 13:59 »
0
En verdad, has planteado mal el objeto, BlackWind. Si el struct se puede inicializar con esa función sin parámetros (a parte del propio struct), el constructor del objeto debería llevar ese mismo código, por lo que no hace falta que tenga parámetros.

Volviendo a la pregunta original, ibito, te diré que para crear un juego uso objetos para casi todos (sólo tengo unas 4 ó 5 funciones muy específicas en 8k líneas de código). En el caso concreto de los jugadores y la escena, lo que hago es crear un grafo de escena que los manipule, algo como (muy simplificado):
Código: Text
  1. class Escena
  2. {
  3. public:
  4.   AñadirEntidad(Entidad*, int categoria);
  5.   ActualizarEscena();
  6.   DibujarEscena();
  7.   TestPorColision(int categoria1, int categoria2, Accion*);
  8. private:
  9.   lista de entidades;
  10. }
  11.  

AñadirEntidad añade a la escena una nueva entidad (jugador, enemigo, item, etc). Se puede añadir en cierta categoría (la utilidad se ve más abajo).

ActualizarEscena recorre todas las entidades actualizando sus posiciones y reaccionando ante sus interacciones (colisiones, por ejemplo).

DibujarEscena recorre todas las entidades y las dibuja.

TestPorColision lo que hace es comprobar si hay colision entre objetos de la categoria 1 y de la categoria 2 y, si la hay, llama a la funcion apuntada por Accion (me he pasado la sintaxis un poco por la gorra) para que realice la acción adecuada.

Por otro lado, el tipo básico de entidad puede ser
Código: Text
  1. class Entidad
  2. {
  3. public:
  4.   Entidad(pos,vel,accel);
  5.   Actualizar();
  6.   Dibujar();
  7. private:
  8.   Vector2D posicion, velocidad, aceleracion;
  9. }
  10.  

A partir de este tipo se pueden crear el resto por herencia, como el jugador (con métodos para modificar sus atributos de velocidad, etc), enemigos ,etc. Cuando detectes que el jugador ha pulsado la tecla de disparar, sólo tendrás que crear una nueva entidad del tipo Disparo, añadirla a la escena, y hacer su test de colisión. O cuando un jugador presione la tecla de avanzar, sólo has de llamar al método de su entidad que actualice su velocidad o aceleración, que ya al actualizarse la escena se actualizarán todas las posiciones.

Es importante que se haga por herencia, para que el polimorfismo cumpla su función y se puedan añadir los punteros a la escena.

Este es un modelo simplificado de uno en el que estoy trabajando. Puede ampliarse añadiendo una jerarquía entre las entidades de forma que el movimiento de una se compute de manera relativa al movimiento de otra, y no de manera absoluta, por lo que se pueden conseguir efectos bastante buenos. Te pongo aqui el .h de ésto (si ves cosas raras piensa que es algo inacabado y que le tengo que invertir aún trabajo).
<!--xc1--></div><table border='0' align='center' width='95%' cellpadding='3' cellspacing='1'><tr><td>XCODE </td></tr><tr><td id='XCODE'><!--exc1-->//
// scene.h
//

#ifndef _SCENE_H_
#define _SCENE_H_

#pragma once

#include "mathlib.h"
#include "graphics.h"
#include <list>
#include <vector>
#include <stack>
#include <string>

/*

PENDIENTE:

¿Eliminar m_properties de las entidades?

Revisar la manera en que se gestionan las colisiones.
- ¿Se detiene en la primera colisión o testea todas? ¿Configurable?
- ¿Usar clases en vez de funciones para gestionar los eventos de colisión?

*/


namespace ae
{
    class BoundingArea
    {
    public:
        BoundingArea();
        void SetupMatrices(const Matrix4x4 &local, const Matrix4x4 &strange) const;
        virtual bool TestCollision(const Circle2D &c2d) const = 0;
        virtual bool TestCollision(const Quad2D &q2d) const = 0;
        virtual const CBaseArea *GetArea() const = 0;
    protected:
        mutable Matrix4x4 m_matrix_local, m_matrix_strange;
    };

    class BoundingCircle : public BoundingArea
    {
    public:
        BoundingCircle(const Circle2D &circle) : m_circle(circle) {};
        bool TestCollision(const Circle2D &c2d) const;
        bool TestCollision(const Quad2D &q2d) const;
        const Circle2D *GetArea() const {return &m_circle;};
    private:
        Circle2D m_circle;
    };

    class BoundingQuad : public BoundingArea
    {
    public:
        BoundingQuad(const Quad2D &quad) : m_quad(quad) {};
        bool TestCollision(const Circle2D &c2d) const;
        bool TestCollision(const Quad2D &q2d) const;
        const Quad2D *GetArea() const {return &m_quad;};
    private:
        Quad2D m_quad;
    };

    class Scene;

    enum delete_type {DELETE_ALL, ATTACH_PARENT, ATTACH_SCENE};
    enum attach_type {INHERIT_NONE, INHERIT_ROTATION, INHERIT_DISPLACEMENT, INHERIT_ALL};
    enum class_id {ID_SCENE=0, ID_HELPER=1, ID_PARTICLESYSTEM=2, ID_PARTICLE=3};

    #define AE_ENTITY_BASE 0
    #define AE_ENTITY_DRAWABLE 1
    #define AE_ENTITY_COLLISIONABLE 2

    #define AE_ENTITY_INMORTAL 0e255f

    class CEntity
    {
    public:
        CEntity(const unsigned int class_id,        // Identificador de clase de objeto
                const Vector2D &pos,                // Posición del objeto
                const float angle,                    // Ángulo del objeto
                const Vector2D &vel,                // Velocidad del objeto
                const float accel = 0.0f,            // Aceleración del objeto.
                const float rotvel = 0.0f,            // Velocidad de rotación
                const float life = AE_ENTITY_INMORTAL,        // Vida de la entidad, en segundos
                const delete_type del_action = DELETE_ALL    // Acción al ser borrado
                )
            : m_class_id(class_id),m_pos(pos), m_angle(angle), m_vel(vel), m_accel(accel),
            m_rotvel(rotvel), m_ondelete(DELETE_ALL), m_parent(NULL), m_life(life),
            m_life_left(life), m_properties(AE_ENTITY_BASE)
        {};

        virtual ~CEntity();

        // Añade una subentidad
        void Attach(CEntity *pEntity, const attach_type type = INHERIT_ALL);

        // Se des-atachea de donde esté. Deja de estar bajo control del SceneManager.
        // Se puede reinsertar si se quiere que vaya a otro sitio.
        //void DeAttach(); *** Por el momento esto no es posible ***

        virtual void Update();
        virtual void Draw();

        virtual CTexture *GetTexture() {return NULL;}
        virtual BoundingArea *GetCollisionArea() {return NULL;}

        unsigned int GetClassID() {return m_class_id;}
        const Vector2D &GetPos() {return m_pos;}
        float GetAngle() {return m_angle;}
        const Vector2D &GetVel() {return m_vel;}
        float GetAccel() {return m_accel;}
        float GetRotVel() {return m_rotvel;}
        float GetLife() {return m_life;}
        float GetLifeLeft() {return m_life_left;}
        // Retorna la vida en el rango [0,1]. 1 es toda la vida y 0 es que ha agotado el
        // tiempo.
        float GetNormLifeLeft() {return 1.0f - (m_life-m_life_left)/(m_life);}

        void SetPos(const Vector2D &newPos) {m_pos = newPos;}
        void SetAngle(const float newAngle) {m_angle = newAngle;}
        void SetVel(const Vector2D &newVel) {m_vel = newVel;}
        void SetAccel(const float newAccel) {m_accel = newAccel;}
        void SetRotVel(const float newRotvel) {m_rotvel = newRotvel;}

        friend class Scene;

    protected:
        unsigned int m_class_id;

        int m_properties;

        float m_life, m_life_left;

        Vector2D m_pos;
        Vector2D m_vel;
        float m_accel;
        float m_angle;        // 0º está a las 3.
        float m_rotvel;        // Grados/segundo. Positivo en contra de las agujas del reloj.

        Matrix4x4 m_local_world_matrix;

    private:
        delete_type m_ondelete;

        typedef struct st_subentity_t
        {
            CEntity *pEntity;
            attach_type inherit;
        } subentity_t;
        std::list<subentity_t> m_attached;

        CEntity *m_parent;    // Puntero al padre en la jerarquía
    };
/*
    // Es un renombramiento, ya que una entidad base se puede usar como ayudante para
    // movimientos jerárquicos. Ya que no se pinta y no se testea por colisión es
    // relativamente rápido.
    typedef class CEntity CHelper;
*/


    class CHelper : public CEntity
    {
    public:
        CHelper(const Vector2D &pos,                // Posición del objeto
                const float angle,                    // Ángulo del objeto
                const Vector2D &vel,                    // Velocidad del objeto
                const float accel = 0.0f,            // Aceleración del objeto.
                const float rotvel = 0.0f,            // Velocidad de rotación
                const float life = AE_ENTITY_INMORTAL,        // Vida de la entidad, en segundos
                const delete_type del_action = DELETE_ALL    // Acción al ser borrado
                )
            : CEntity(ID_HELPER, pos, angle, vel, accel, rotvel, life, del_action) {};
    };


    class CEntityDrawable : public CEntity
    {
    public:
        CEntityDrawable(const unsigned int class_id,    // Identificador de clase de objeto
                CTexture *pTexture,            // Textura
                const float width,
                const float height,
                const Vector2D &pos,                // Posición del objeto
                const float angle,                    // Ángulo del objeto
                const Vector2D &vel,                // Velocidad del objeto
                const float accel = 0.0f,            // Aceleración del objeto.
                const float rotvel = 0.0f,            // Velocidad de rotación
                const float life = AE_ENTITY_INMORTAL,
                const delete_type del_action = DELETE_ALL,    // Acción al ser borrado
                const float alpha = 1.0f,            //
                const unsigned int flip = Renderer::FLIP_NONE    //
                )
            : CEntity(class_id, pos, angle, vel, accel, rotvel, life, del_action),
            m_pTex(pTexture), m_width(width), m_height(height), m_alpha(alpha), m_flip(flip)
        {
            m_properties |= AE_ENTITY_DRAWABLE;
        };

        void Draw();

        CTexture *GetTexture() {return m_pTex;}

    protected:
        CTexture *m_pTex;
        float m_width;
        float m_height;
        float m_alpha;
        unsigned int m_flip;
    };

    class CEntityCollisionable : public CEntityDrawable
    {
    public:
        CEntityCollisionable(const unsigned int class_id,    // Identificador de clase de objeto
                CTexture *pTexture,                // Textura
                const float width,                // Anchura
                const float height,                // Altura
                BoundingArea *pCollisionArea,    // Área de colisión
                const Vector2D &pos,            // Posición del objeto
                const float angle,                // Ángulo del objeto
                const Vector2D &vel,                // Velocidad del objeto
                const float accel = 0.0f,        // Aceleración del objeto.
                const float rotvel = 0.0f,        // Velocidad de rotación
                const float life = AE_ENTITY_INMORTAL,
                const delete_type del_action = DELETE_ALL,    // Acción al ser borrado
                const float alpha = 1.0f,
                const unsigned int flip = Renderer::FLIP_NONE
                )
            : CEntityDrawable(class_id, pTexture, width, height, pos, angle, vel, accel, rotvel, life, del_action, alpha, flip),
            m_pCollisionArea(pCollisionArea)
        {
            m_properties |= AE_ENTITY_COLLISIONABLE;
        };

        ~CEntityCollisionable() {if (m_pCollisionArea != NULL) delete m_pCollisionArea;}

        BoundingArea *GetCollisionArea() {return m_pCollisionArea;}

    protected:
        BoundingArea *m_pCollisionArea;
    };

/* Todo esto de aqui desaparecerá */
    //
    //inline CEntityDrawable *AE_DRAWABLE(CEntity *x) {return static_cast<CEntityDrawable*>(x);}
    //inline CEntityCollisionable *AE_COLLISIONABLE(CEntity *x) {return static_cast<CEntityCollisionable*>(x);}

    //
    //#define AE_C2D(x) dynamic_cast<Circle2D>(x)
    //#define AE_Q2D(x) dynamic_cast<Quad2D>(x)

    // Cuidado con esto. Habilitar en el compilador RTTI
    //#define AE_GENERIC_CAST(x, type) dynamic_cast<type>(x)



    #define COLLISION_FUNC(x) void (x)(CEntity *left, CEntity *right)
    typedef COLLISION_FUNC(*PCOLLISION_FUNC);

    /* ¿Qué sucede cuando se hace el Update() de Scene?
    Se recorre el árbol, actualizando las posiciones relativas de cada entidad, y
    se calculan las matrices de transformación de cada una. A continuación se ejecuta
    el buffer de testeos de colisiones.
    */

    class Scene
    {
    public:
        ~Scene();

        void ClearScene();
        void ClearClassID(const unsigned int class_id);

        // La añade a root
        void AddEntity(CEntity *pEntity);

        // Atachea
        void AttachEntity(CEntity *pParent, CEntity *pChild, const attach_type type = INHERIT_ALL);

        // Cuando se quiera borrar una entidad se ha de usar este método
        void DestroyEntity(CEntity *pEntity);

        // Añade la entidad al buffer de borrado. Se eliminará tras actualizar todas las
        // entidades y antes de ejecutar el buffer de colisiones.
        void AddToDeleteBuffer(CEntity *pEntity);

        // Tras ejecutar el buffer hay q volver a llenarlo cada fotograma
        void AddCollisionTest(const unsigned int left_id, const unsigned int right_id, const PCOLLISION_FUNC pFunc);

        void Update();
        void Draw();

        static Scene &Instance() {return m_scene;};

        friend class CEntity;

    private:
        static Scene m_scene;

        /* ************* GRAFO DE ESCENA **************** */
        // Nodos que cuelgan de la escena directamente
        std::list<CEntity*> m_root;

        // Borra todos los descendientes de un elemento del árbol. Además los da de baja
        // en las listas y libera la memoria.
        void RemoveFromTreeCascade(CEntity *pEntity);

        /* ************* LISTAS DE ENTIDADES **************** */
        typedef struct st_entities_list_t
        {
            unsigned int class_id;
            std::list<CEntity*> entities;
        } entities_list_t;
        // Lista de listas de entidades, ordenadas por class_id
        std::list<entities_list_t> m_entities_lists;

        // Lista de las entidades que se han de borrar
        std::list<CEntity*> m_delete_entities;

        // Registra una entidad en las listas.
        void RegisterEntity(CEntity *pEntity);
        // Da de baja una entidad de las listas. NO LIBERA MEMORIA.
        void UnRegisterEntity(CEntity *pEntity);

        /* ************** PILA DE MATRICES ************ */
        // Pila de matrices, para manejarse de manera similar a OpenGL
        std::stack<Matrix4x4> m_matrixstack;
        void ResetStack();
        void PushMatrix();
        void PopMatrix();
        const Matrix4x4 &GetMatrix();

        /* ************** TRANSFORMACIONES ************ */
        void LoadIdentity();
        void Translate(const double x, const double y, const double z = 0.0);
        void RotateZ(const double angle);    // En grados
        void PreTranslate(const double x, const double y, const double z = 0.0);
        void PreRotateZ(const double angle);    // En grados

        /* ************** BUFFER DE DETECCIÓN DE COLISIONES ********* */
        typedef struct st_collision_test_t
        {
            unsigned int left_class_id;
            unsigned int right_class_id;
            PCOLLISION_FUNC pFunc;
        } collision_test_t;
        // Buffer de rutinas de colisión a ejecutar
        std::vector<collision_test_t> m_collision_buffer;

        // Ejecuta el contenido del buffer (al acabar le hace un clear)
        void ExecuteCollisionBuffer();
        // Ejecuta una prueba de colisión en concreto
        void CollisionTest(const unsigned int left_id, const unsigned int right_id, const PCOLLISION_FUNC pFunc);

        /* ********************** OTRAS COSAS ********************** */
        Scene();
        Scene(const Scene &);
    };

} /* namespace ae */

#endif /* _SCENE_H_ */<!--xc2--></td></tr></table><div class='postcolor'><!--exc2-->

Un saludo.

Ruben3d