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):
class Escena
{
public:
AñadirEntidad(Entidad*, int categoria);
ActualizarEscena();
DibujarEscena();
TestPorColision(int categoria1, int categoria2, Accion*);
private:
lista de entidades;
}
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
class Entidad
{
public:
Entidad(pos,vel,accel);
Actualizar();
Dibujar();
private:
Vector2D posicion, velocidad, aceleracion;
}
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