Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Gestion De Disparos En Un ...

Iniciado por josette, 14 de Abril de 2006, 12:12:12 PM

« anterior - próximo »

josette

    Hola a todos, estoy haciendo pruebas con mi nuevo 'beta engine' y para ello estoy haciendo un juego de naves. Me ha surgido una duda:

La duda es la de como gestionar los disparos de la nave. Lo que es la creacion y destruccion de los disparos lo tengo claro, pero lo que no tengo tan claro es en que parte del codigo hacer esto. Yo tengo varias soluciones pero me leer vuestras opiniones antes de tomar una decisión.

Tengo lo siguiente:

Cgame
{
...
/// VARIABLES ///
CspaceShip m_SpaceShip;
...
}


CspaceShip::move()
{
  if (ngn->getKeyboard()->isKeyDown(m_Control.m_keyFire))
  {
      Cbullet* BulletMgr.createBullet();
      Pos = ...
      bullet->setPosition(Pos);
  }
}


Mi duda es donde colocar el BulletMgr. Si lo coloco dentro de la clase CspaceShip luego a la hora de hacer las colisiones de acceder a la clase CspaceShip para tomar el BulletMgr y si lo coloco fuera por ejemplo en la clase Cgame para crear disparos CspaceShip ha de tener un puntero al BulletMgr. Lo mas intuitivo es lo primero, no?

  Otra duda es donde chequear las colisiones. ¿En un metodo de Cgame?
¿Hay alguna forma mas  menos estandarizada de hacer esta gestion de objetos para poder hacer luego una deteccion de colisiones mas eficiente?


Vicente

 Un singleton me parece que es lo que quieres (una clase a la que puedes acceder desde cualquier sitio). Un saludo!

Vicente

tiutiu

 Mirate el patron Prototype para instanciar las balas (no querras hacer un new/delete cada vez que dispares). Simplemente necesitas el mismo grafico pero cambiando la posicion en cada instancia.

El gestor de balas (no creo que haga falta un gestor para algo asi) podria ir tranquilamente como singleton dentro de algun namespace para tener las cosas mas organizadas. Pero repito que no creo que necesites un gestor de balas, simplemente el propio gestor de recursos te da la bala y ya esta, se trata como otra entidad movil y colisionable mas.
b>:: Pandora's Box project ::
Notas e ideas sobre desarrollo de engines para juegos

zupervaca

 [off-topic]
Perdonar por el offtopic, tiutiu ¿como solucionas con el patron prototype el no hacer el new o el delete? ¿esta patron no es para hacer que sean las clases las que se saben clonar, es decir:

class nave
{
public:
   int x, y, anim, ...
   nave *clonar()
   {
       nave *nueva = ...
       return nueva;
   }
};

¿Que haces en la funcion clonar para no hacer un new?
[/off-topic]

senior wapo

 Tener un array o lista enlazada que sean estaticos de la clase e ir pasando objetos que mueren a la lista de objetos libres y sacándolos de allí al clonar. Vamos, que haces new solo cuando al clonar no hay objetos disponibles en la lista/array de libres. Variaciones hay muchas, con array no me refiero necesariamente a un array tradicional de C.

en lugar de new bala:  clonar bala: (saca de la lista libres, o hace new) y llama al metodo initialize()
en lugar de delete bala:  llamar a un metodo shutdown() y pasar a la lista de libres.

zupervaca

 Oki, es que estaba todo intrigado ya que yo el sistema que uso es el que mencionadas de tener dos listas enlazadas y mover de una a otra.

josette

 Me miraré el patron 'Prototype'. Lo de la gestion de las balas no pretendía hacer un new/delete pero si tener un array grande en donde cada vez que se necesito de una bala recorrer el array en busca de una que este libre y ponerla como activa y ponerle la posicion relativa a la nave.

Lo de las listas, es mas eficiente.

Lo de hacer el simgleton el manager, ¿que pasa si quiero gestionar los disparos de las naves enemigas, si el manager es global?

tiutiu

 Creo que me he colado un poco con lo del prototype, al final acabas haciendo un new y pasandole una referencia al componente grafico, que es el que compartes. De todos modos ya habeis dicho una manera de solucionarlo, usando una especie de cache de disparos para reutilizar los que te sobran en vez de hacer un delete (hay varias soluciones).

josette, el BulletMgr que gestiona? balas en general o las balas del jugador? creo que no es necesario hacer esa distincion (desde el punto de vista del gestor). De todos modos sigo pensando que no necesitas un gestor de balas (KISS).
b>:: Pandora's Box project ::
Notas e ideas sobre desarrollo de engines para juegos

Pogacha

 Lo que se se hace en ese caso es un pool,  tienes un array de structs de balas, struct bala { int x, y, dx, dy ... }; cuando una bala muere copias la ultima bala del array sobre esta y listo.

int n_balas;
bala lasbalas[MAX_BALAS];

void agregar_bala(bala &b) {  lasbalas[n_balas++] = b; }
void destruir_bala(int i) {  lasbalas[i] = lasbalas[-n_balas]; }


Esto lo pasas de c a c++ metiendolo en una clase o lo que sea, pero la solución es mas que obvia ;)

Ojo que esto altera el orden, tenlo en cuenta en la fase de dibujo.

Saludos.

ethernet

 Un sistema cutre pero funcional:


struct Bullet
{
...
};

struct BulletManager
{
enum{ MAX_BULLETS = 1024 };
static int i; //ponerlo a 0 donde cuadre
static Bullet b[MAX_BULLETS];

static Bullet* GetBullet()
{
  return &b[i++%MAX_BULLETS];
}


};

Este sistema es el que usé yo en la última compo de stratos para las partículas, funciona a la perfección y está implementado en unos 2 minutos.


struct particle Particles[MAX_PARTICLES];
int idx = 0;


struct particle* get_particle()
{
return &Particles[(idx++)%MAX_PARTICLES];
}




Luego usé un par de funciones:


void PART_Update(float delta);
void PART_Render();


ejemplo de uso

for(i=0;i<100;i++)
{
 struct particle* p = get_particle();
 p->color[0] = 0;
 p->color[1] = 0;
 p->color[2] = 0.8;
 p->color[3] = 0.5;

 p->pos[0] = BALA_pos[0];
 p->pos[1] = BALA_pos[1];
 p->pos[2] = BALA_pos[2];

 p->dir[0] = RandAB(-10,10);
 p->dir[1] = RandAB(-10,10);
 p->dir[2] = RandAB(-10,10);

 p->life = 0.2+ 0.6*Rand01();

}


También hace tiempo empecé un pequeño juego de naves y usé un sistema parecido, algo más elaborado en el cual tenía un pool de balas y tiraba de ahí. Para evitar la autocolisión debido a que cuando se lanza una bala puede estar dentro de bbox (o el sistema de colisión que uses) usé un id para cada bala que coincidía con el id (que a su vez era el this del la instancia Nave) de la nave que la había enviado, de esta forma sabía si tenía que colisionar o no. De nuevo cutre pero funcional y rápido.

Pogacha

 Una cosa que no mensioné en el Pool mio con for(int i=0; i

josette

 Mi propósito es el de hacer una clase que llamo 'CbulletMgr' que quiero que tenga la siguiente interfaz:

- CbulletMgr(CspaceShip* ss): asi las balas saben quien es su dueño.

- setBulletAttr(CbulletAttr* attr): cuando la nave pilla un nuevo tipo de balas se actualiza en el gestor y asi las balas tienen ahora estas características.

- Cbullet* createNew(const Cpoint2i& P): recorrer el array de balas y tomar la primera que este no activa, y asignarle P a su posición.

- move(): mueve las balas segun su velocidad y actualiza el siguiente graphico de la animacion si esque la tiene.

- update(): comprueba si alguna bala ha salido de la pantalla y ha pasado a no activa porque ha colisionado con algun objeto.

El chequeo de las colisiones si lo meto en la funcion update necesito pasarle el resto de objetos y eso no lo veo claro porque lo mismo tendría que hacer con el resto de objetos.

Lo suyo sería meter todos los ojetos en un mismo sitio y detectar colisiones en una misma función.

¿Hay alguna forma de hacer esto de forma estandarizada?
Citarethernet: Un sistema cutre pero funcional:
funciona porque el array es grande y las balas mueren antes de que puedan ser vivas de nueno. Como tu dices, cutre pero funcional.

tiutiu

 Hmmm, creo que tienes varios fallos de diseño.

Dices que el BulletMgr esta enlazado a una nave. ¿Que sentido tiene que sea una entidad a parte? ¿porque no forma parte directamente de la nave (agregado) y le llamas Gun? Por lo que dices que hace tiene mucha mas logica (solo interacciona con una instancia de SpaceShip y no con cualquiera). De ese modo, podrias tener una interfaz basica para armas, y usando polimorfismo puedes tener varios tipos de armas. Algo asi:


Para hacerlo mas realista, cada arma puede tener una cache con un maximo de balas que puede disparar, algo asi como el cargador; lo cual actuara como limite de la cache de balas. Si quieres balas infinitas, con que le pongas 1000 ya te valdra de sobras, no creo que una misma arma pueda disparar 1000 veces sin que ninguna otra bala impacte o se salga de la pantalla.
Para la gestion de las balas libres, te propongo tener un array de enteros con las posiciones del cargador libres. Inicialmente ese array esta lleno con los numeros [0..MAX_BULLETS-1], y cada vez que crees una bala, coges el ultimo indice y lo usas para la nueva instancia. Cuando muere una bala, añades su indice al final de la lista (pop_back, push_back).
Si por lo que sea te quedas sin balas, tienes dos opciones: [1] argumentar que hay que recargar el arma o [2] usas new/delete para las balas 'extra', ya que seran casos remotos para un MAX_BULLETS suficientemente grande (siempre puedes actualizar esa constante en el fichero de configuracion para posteriores ejecuciones, un poco de tweaking automatico no viene mal ;) ).

Para el tema colisiones, yo tendria un evento en la clase SpaceShip que indica que han impactado, y le pasas la bala que lo ha hecho. Puedes tener un gestor de colisiones que sabe donde estan todas las naves de la pantalla en ese momento, o que se lo pregunte al gestor de naves (ahi si seria interesante tener un gestor). Le pasas una bala y le indicas que notifique a las naves a las que ha impactado.

Bueno, creo que no me dejo nada. Espero que te sirva de ayuda :)
b>:: Pandora's Box project ::
Notas e ideas sobre desarrollo de engines para juegos

josette

 Eh tiutiu! le has dado el nombre clave a la entidad que yo tenia como bulletManager. Lo de gun encaja que te cagas en lo que yo quiero hacer. Ahora voy a pensar un poco mas en lo de las colisiones.

He pensado en poner una lista estatica en la clas Csprite de forma que cada vez que se crea un sprite se añade de forma automática a esta lista el puntero al sprite asi cuando se crea se añade a la lista y cuando pasa a ser activa se mete otra vez.

Lo de las colisiones puedo hacer las funciones

Cgame::collisions()
{
   for (i=0;m_spaceShip->m_Gun.sizeAlive(),i++)
   {
      Cbullet* b = m_spaceShip->getBulletAlive(i);
     
      for (j=0;m_Lst_enemys->sizeAlive();j++)
      {
          Cenemy* e = m_Lst_enemys[j];
          if (e->isCollide(b))
          {
              e->OnCollide(b);
          }
      }
   }
}


Algo así, ver que tal me funciona.

Y gracias por vuestras opiniones. Esta claro que si me ongo al final lo saco pero tal vez lo haga de una forma un tanto 'no estandar' y asi por lo menos cuando alguien vea los fuentes que pueda identificar las cosas de forma facil.






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