Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Dudas Para Un "proyectillo"

Iniciado por erchus, 17 de Enero de 2006, 12:47:09 PM

« anterior - próximo »

erchus

 Pues eso, que me he planteado hacer un jueguecillo relativamente sencillo para practicar (con C++ y DirectX) y así, sin profundizar mucho, me han surgido un par de dudas.

Bueno, la idea es un juego 2D...Imaginaos el plano de un piso(con sus muebles y todo eso) visto desde arriba, pues bien para establecer las zonas "no transitables" he pensado hacer algo como un mapa de durezas...vamos, crear una imagen igual de grande que la del fondo y poner por ejemplo en color blanco las zonas por las que no se puede pasar.
Mi pregunta es si esta es la mejor opción, y por otro lado...¿se supone que el mapa de durezas hay que analizarlo pixel a pixel?¿existe alguna forma más eficiente de hacer esto?

Por otro, quiero tener algunos personajes por la pantalla haciendo distintas tareas (hablando por teléfono, andando por una ruta fija, escribiendo,un perro ladrando,...).
¿Cuál sería la mejor forma (a nivel de la estructura del código) de plasmar esto?¿Creo distintas funciones que ejecuten esas animaciones periódicamente o existe alguna forma "metodológicamente" más correcta?

Bueno, espero que entendáis lo que quiero decir...

Gracias a todos y un saludo

KACHORRO

 Si el juego va a ser 2D, supongo que implementarás un sistema de sprites.
Así pues, lo mejor es implementar un sistema de colisión de sprites y con eso ya lo tienes todo resuelto. Creo que es mejor que el mapa de durezas y te acelerará toda la historia.

Respecto a la IA de los personajes y sus tareas... hay muchas formas supongo, pero si lo vas a orientar a objetos, supongo que deberias tener un procedimiento "tarea que hacer mientras (loquesea)" en cada personaje.

En cualquier caso, como supongo que habrá muchas más opiniones más expertas y diáfanas que la mia, lo dejo de momento ahí, y a ver por donde te orientan los demás.

javiel

 Yo te comento como he estado haciendo yo algo parecido, pero en 3d, de un proyecto que tengo a medias (bueno, empezado a medias ;-))

Por ejemplo la habitación la divides en diferentes tiles (que pueden ser transitables o no transitables). Por ejemplo. Tienes una habitación de 200x200 y haces tiles de 20x20. O sea, que tendrás 10 tiles horizontales y 10 verticales. Ahora pues te creas un array de enteros en el que por ejemplo 0 es transitable y 1 no lo es. Pues ya lo tienes, puedes posicionar tus elementos por ejemplo en la fila 3 columna 2, y ya está. Luego sólo tienes que empezar a poner muebles. Por ejemplo pones una mesa en la fila 4 columna 3, pues ya sabes que ese tile no será transitable, y lo marcas en el array. De esta forma también te sirvará cuando quieras hacer búsquedas de caminos. Los elementos siempre estarán en una fila y columna y se desplazarán a otra fila y columna. Puedes hacer tu camino sin  pisar por las zonas no transitables ya  que tienen obstáculos.

No se si me he explicado, o si es la mejor forma, pero yo lo tengo mas o menos así

un saludo
uper-Tirititran: el superhéroe gaditano (http://www.super-tirititran.com)

erchus

 
Citarsupongo que deberias tener un procedimiento "tarea que hacer mientras (loquesea)"
Sí, algo así había pensado... Crear un método para cada personaje y que dependiendo del estado del mismo, ejecute una secuencia de animación u otra...Pero no sabía si esto era muy correcto.

Javiel, lo de los tiles quizás sea una buena idea... Los había desechado, porque el juego es de una única fase y en una única pantalla (en la que hay que resolver una serie de puzzles para llegar al final)...Supongo que aquí el problema será ajustar los objetos del juego (mesas, sillas,...)  a los tiles.

En fin, gracias por las respuestas.... :lol:  

marcode

 Yo creo que lo normal en c++ es que hicieras una clase genérica para mantener ese tipo de objetos, con las propiedades básicas como la posición, punteros a sprites, animaciones, o sonidos que use, estado, tile al que corresponde, etc.

Y si acaso luego hacer otras derivadas dependiendo de si es una persona, un animal, o un objeto. Y si lo necesitas puedes hacer clases más específicas por ejemplo para personas pasivas, personas amigas, enemigas, etc. Con los objetos haces lo mismo, dependiendo de si son de adorno, máquinas, trampas, etc.

En definitiva si lo que quieres es aprender la POO deberías de clasificarlo todo usando el sentido común, recuerda también que quede bien encapsulado, además de facilitarte el mantenimiento y claridad en el código, las clases más básicas podrás usarlas en cualquier otro juego que hagas sin ninguna complicación.

Quizás todo esto te parezca mucha movida para hacer unas simples animaciones, o unos objetos, pero te puedo asegurar que lo agradecerás cuando el programa empiece a crecer y a crecer y veas que todo continua ordenado y clasificado, y que puedes modificar o ampliar facilmente.

size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

zupervaca

 Te pongo un codigo muy basico que solia usar para crear controles de animacion muy dinamicos desde codigo, tiene su tiempo, pero para darte una idea te valdra:

Anim.h
// Anim.h
// Clases para controlar animaciones de cualquier tipo

#ifndef dib_Library_Anim
#define dib_Library_Anim

// Incluir cabeceras
#include "../../cons.h"
#include "../../Object.h"

// Namespaces
namespace dib
{
namespace Library
{
 namespace Anim
 {
  // Predeclarar las clases
  class Key;
  class Sequence;
  class Control;

  // Llave de una secuencia
  class Key
  {
  // Eventos
  protected:
   // Se llama cuando la llave es ejecutada por primera vez
   virtual void OnStart( Control *pCtrl ) = 0;
   // Se llama cada vez que debemos de actualizar esta llave
   virtual void OnUpdate( Control *pCtrl ) = 0;
   // Se llama cuando la secuencia se debe de compilar
   virtual bool OnCompile( Sequence *pSeq ) = 0;

  // Amistades
  private:
   friend Control;
   friend Sequence;
  };

  // Clase que memoriza secuencias de llaves
  class Sequence : public Object
  {
  // Inicializar la clase
  public:
   // Constructor
   Sequence( int nNumKeys );
   // Destructor
   virtual ~Sequence();
   // Compilar toda la secuencia, se llamara al evento OnCompile de todas las llaves
   bool Compile();

  // Propiedades
  public:
   // Obtener o devolver una llave indicando su indice
   __forceinline void SetKey( int nIndex, Key *pKey );
   __forceinline Key *GetKey( int nIndex );
   // Obtener el numero de llaves en la secuencia
   __forceinline int GetNumKeys();

  // Valores de la clase
  private:
   // Puntero a las llaves de esta secuencia
   Key **m_pKeys;
   // Número de llaves en la secuencia
   int m_nNumKeys;
  };

  // Clase que controlar la secuencia de las animaciones
  class Control : public Object
  {
  // Inicializacion
  public:
   // Constructor
   Control();

  // Metodos
  public:
   // Comenzar a reproducir una secuencia
   __forceinline void Start( Sequence *pSeq );
   // Actualizar la secuencia de animacion
   __forceinline void Update();
   // Saltar a una llave directamente
   __forceinline void GotoKey( int nIndex );

  // Propiedades
  public:
   // Activar o desactivar la pausa
   __forceinline void Pause( bool bActive );
   __forceinline bool IsPause();
   // Obtener la llave actual
   __forceinline int GetKey();
   // Obtener la secuencia actual
   __forceinline Sequence *GetSequence();

  // Valores de la clase
  private:
   // Secuencia que esta activada actualmente
   Sequence *m_pCurrentSeq;
   // Llave actual
   int m_nCurrentKey;
   Key *m_pCurrentKey;
   // Indica si esta o no en pausa
   bool m_bPause;
  };


  /************************************************/
  /* Clase derivadas de Key para su funcionalidad */
  /************************************************/

  // Llave para producir un salto en el control
  class KeyGotoKey : public Key
  {
  // Inicializacion
  public:
   // Constructor
   KeyGotoKey( int nGotoKey );

  // Eventos
  protected:
   // Se llama cuando la llave es ejecutada por primera vez
   __forceinline virtual void OnStart( Control *pCtrl );
   // Se llama cada vez que debemos de actualizar esta llave
   __forceinline virtual void OnUpdate( Control *pCtrl );
   // Se llama cuando la secuencia se debe de compilar
   __forceinline virtual bool OnCompile( Sequence *pSeq );

  // Valores de la clase
  private:
   // Llave a la que saltar
   int m_nGotoKey;
  };

  // Lave para producir la pausa en el control
  class KeyPause : public Key
  {
  // Eventos
  protected:
   // Se llama cuando la llave es ejecutada por primera vez
   __forceinline virtual void OnStart( Control *pCtrl );
   // Se llama cada vez que debemos de actualizar esta llave
   __forceinline virtual void OnUpdate( Control *pCtrl );
   // Se llama cuando la secuencia se debe de compilar
   __forceinline virtual bool OnCompile( Sequence *pSeq );
  };
 }
}
}

// Incluir metodos en linea
#include "Anim.inl"

#endif dib_Libraries_Anim

/* Por David Inclán Blanco
* http://www.davidib.com
* Este codigo fuente puede ser utilizado para cualquier proposito, incluso para uso
* comercial, pero nunca podra decir que ha asi creado por usted, cualquier fallo
* derivado de este codigo no sera responsabilidad del autor
*/


Anim.inl
// Anim.inl

// Namespaces
namespace dib
{
namespace Library
{
 namespace Anim
 {
  // Obtener la llave actual
  __forceinline int Control::GetKey()
  {
   return m_nCurrentKey;
  }

  // Obtener la secuencia actual
  __forceinline Sequence *Control::GetSequence()
  {
   return m_pCurrentSeq;
  }

  // Indica si esta o no en pausa
  __forceinline bool Control::IsPause()
  {
   return m_bPause;
  }

  // Actualizar la secuencia de animacion
  __forceinline void Control::Update()
  {
   if( !IsPause() )
   {
    m_pCurrentKey->OnUpdate( this );
   }
  }

  // Saltar a una llave directamente
  __forceinline void Control::GotoKey( int nIndex )
  {
   m_nCurrentKey = nIndex;
   if( m_nCurrentKey < m_pCurrentSeq->GetNumKeys() )
   {
    m_pCurrentKey = m_pCurrentSeq->GetKey(m_nCurrentKey);
    m_pCurrentKey->OnStart( this );
   }
   else
   {
    Pause( true );
   }
  }

  // Activar o desactivar la pausa
  __forceinline void Control::Pause( bool bActive )
  {
   m_bPause = bActive;
  }

  // Comenzar a reproducir una secuencia
  __forceinline void Control::Start( Sequence *pSeq )
  {
   m_pCurrentSeq = pSeq;
   if( m_pCurrentSeq != NULL )
   {
    Pause( false );
    GotoKey( 0 );
   }
   else
   {
    Pause( true );
   }
  }

  // Obtener el numero de llaves en la secuencia
  __forceinline int Sequence::GetNumKeys()
  {
   return m_nNumKeys;
  }

  // Obtener o devolver una llave indicando su indice
  __forceinline void Sequence::SetKey( int nIndex, Key *pKey )
  {
   m_pKeys[nIndex] = pKey;
  }

  __forceinline Key *Sequence::GetKey( int nIndex )
  {
   return m_pKeys[nIndex];
  }

  // Se llama cuando la llave es ejecutada por primera vez
  __forceinline void KeyGotoKey::OnStart( Control *pCtrl )
  {
   pCtrl->GotoKey( m_nGotoKey );
  }

  // Se llama cada vez que debemos de actualizar esta llave
  __forceinline void KeyGotoKey::OnUpdate( Control *pCtrl )
  {
  }

  // Se llama cuando la secuencia se debe de compilar
  __forceinline bool KeyGotoKey::OnCompile( Sequence *pSeq )
  {
   return true;
  }

  // Se llama cuando la llave es ejecutada por primera vez
  __forceinline void KeyPause::OnStart( Control *pCtrl )
  {
   pCtrl->Pause( true );
  }

  // Se llama cada vez que debemos de actualizar esta llave
  __forceinline void KeyPause::OnUpdate( Control *pCtrl )
  {
  }

  // Se llama cuando la secuencia se debe de compilar
  __forceinline bool KeyPause::OnCompile( Sequence *pSeq )
  {
   return true;
  }
 }
}
}

/* Por David Inclán Blanco
* http://www.davidib.com
* Este codigo fuente puede ser utilizado para cualquier proposito, incluso para uso
* comercial, pero nunca podra decir que ha asi creado por usted, cualquier fallo
* derivado de este codigo no sera responsabilidad del autor
*/


Anim.cpp
// Anim.cpp

// Incluir cabeceras
#include "Anim.h"

// Namespaces
namespace dib
{
namespace Library
{
 namespace Anim
 {
  // Compilar toda la secuencia, se llamara al evento OnCompile de todas las llaves
  bool Sequence::Compile()
  {
   for( int nKey = 0; nKey < m_nNumKeys; nKey++ )
   {
    if( !m_pKeys[nKey]->OnCompile(this) )
    {
     return false;
    }
   }
   return true;
  }

  // Constructor
  Control::Control()
  {
   m_pCurrentSeq = NULL;
   m_nCurrentKey = 0;
   m_pCurrentKey = NULL;
   m_bPause = true;
  }

  // Constructor
  Sequence::Sequence( int nNumKeys )
  {
   m_nNumKeys = nNumKeys;
   m_pKeys = new Key*[nNumKeys];
  }

  // Destructor
  Sequence::~Sequence()
  {
   // Borrar todos las llaves
   for( int nKey = 0; nKey < m_nNumKeys; nKey++ )
   {
    delete m_pKeys[nKey];
   }
   // Borrar la lista de llaves
   delete []m_pKeys;
  }

  // Constructor
  KeyGotoKey::KeyGotoKey( int nGotoKey )
  {
   m_nGotoKey = nGotoKey;
  }
 }
}
}

/* Por David Inclán Blanco
* http://www.davidib.com
* Este codigo fuente puede ser utilizado para cualquier proposito, incluso para uso
* comercial, pero nunca podra decir que ha asi creado por usted, cualquier fallo
* derivado de este codigo no sera responsabilidad del autor
*/


Su funcionamiento es muy basico, debemos de crear una clase Sequence donde se iran agregando clases Key basicas o creadas por ti, luego se crea otra clase llamada Control donde se indica la secuencia con la que trabaja.
Un ejemplo cutre:
 // Crear las animaciones
 m_Seq = new dib::Library::Anim::Sequence( 2 );
 m_Seq->SetKey( 0, new dib::Library::Anim::KeyPause() );
 m_Seq->SetKey( 1, new dib::Library::Anim::KeyGotoKey(0) );
 m_Seq->Compile();
 // Crear el control de secuencias
 m_Ctrl = new dib::Library::Anim::Control();
 m_Ctrl->Start( m_Seq );


Editado: Debes de darte cuenta que este sistema te sirve para todo, animaciones, maquinas de estado, mover objetos, etc.

Ruben

 Hi,
para lo de la ia puedes tener una maquina de estados por personaje:

Por ejemplo:
Si estas en el estado de "hablar por telefono" y te viene el jugador pasa al estado de "mirar a jugador mientras que hablas".

Cada estado tendra sus caracteristicas, animaciones, ...

Es muy sencillito y con 4 ifs te solucionara la historia.

Un saludo,
Rubén



ZüNdFoLGe

 
CitarPor ejemplo la habitación la divides en diferentes tiles (que pueden ser transitables o no transitables). Por ejemplo. Tienes una habitación de 200x200 y haces tiles de 20x20. O sea, que tendrás 10 tiles horizontales y 10 verticales. Ahora pues te creas un array de enteros en el que por ejemplo 0 es transitable y 1 no lo es.

:ph34r:  eso si el juego es en pantalla fija, si va a usar scrolling es una locura.
En mi opinion si vas a trabajar en 2d lo mejor que podes hacer es editar el mapa del juego con el editor que mas te guste y lo demás queda en manos de la clase que hayas hecho para los sprites, diferenciando las colisiones de 'paredes' por ejemplo, con las colisiones con una bala.

para la IA de tus enemigos podes usar un sistema basado en conocimiento, es decir por ejemplo, si el enemigo esta cerca del jugador entonces dispara...si el enemigo esta por detras del jugador entonces lo apuñala...si no se detecta movimiento al rededor del enemigo, entonces camina...etc etc

CitarPues eso, que me he planteado hacer un jueguecillo relativamente sencillo para practicar (con C++ y DirectX)

que motor estas usando?  :ph34r:  

sés

Cita de: "ZüNdFoLGe":ph34r:  eso si el juego es en pantalla fija, si va a usar scrolling es una locura.
No sé exactamente a que parte te refieres pero los mapas de tiles son perfectos para muchas cosas, y si además lo que quiere es algo sencillo...
Soy indeciso... ¿o no?

ZüNdFoLGe

 
CitarNo sé exactamente a que parte te refieres pero los mapas de tiles son perfectos para muchas cosas, y si además lo que quiere es algo sencillo...

:blink:  ?
yo no dije nada acerca de que no use tiles, al contrario, le recomendé usar un editor de mapas.  O_O

Citareso si el juego es en pantalla fija, si va a usar scrolling es una locura.

con eso me refería al método del array para las zonas transitables... si lo que quiere es hacer las cosas 'sencillas' como dices, entonces esta opción no es válida  :P

sés

 Hombre, definir que tile es transitable y cual no, y no usar otra tabla para esto. Aun así sigue siendo un método válido (no óptimo) y sencillo.

De todas formas veo el método como "no óptimo", independientemente del scroll.
Soy indeciso... ¿o no?

erchus

 Gracias Zupervaca por el código, le echaré un vistazo en cuanto pueda...

Citarque motor estas usando?
Algo muy básico para dibujar imágenes por pantalla y hacer "double buffering" con direct draw.

Supongo que el uso de tiles teniendo en cuenta los casos especiales (como las paredes,...) es la mejor opción. :lol:

Había pensado para el tema de las animaciones en distinguir entre animaciones con y sin desplazamiento del sprite. La idea sería leer de un fichero asociado a cada sprite la secuencia de tiles (o coordenadas) por las que debe pasar en el caso de las animaciones con desplazamiento, o la secuencia de frames que se deben seguir para las animaciones sin desplazamiento.
No se si entendéis la idea de lo que quiero decir, tal vez sea un poco rebuscado. Pero creo que así puedo gestionar las animaciones con independencia del código ¿cómo véis esto?... O_O

Una cosilla más.  :lol:
La idea del juego es realizar una serie de acciones (encontrar una llave, cortar un cable, si abro una puerta el enemigo tal va en mi busca,...) antes de pasar a la siguiente prueba... ¿cómo se suelen modelar las quest o pruebas en un juego?¿se crean clases independientes para cada puzzle o es todo un poco menos "estructurado"?
Es una curiosidad que tengo  :P

Muchas gracias a todos por vuestra ayuda...
Seguiré dándole vueltas al coco  (nooo)

Salu2

ZüNdFoLGe

 
CitarDe todas formas veo el método como "no óptimo", independientemente del scroll.

ok  (ole)

zupervaca

 Si el juego lo quieres hacer 100% c++ olvidate de la programacion estructurada de toda la vida y usa programacion orientada a objetos ya que asi aprovecharas el lenguaje (fijo que mas de uno me crucificara por esto :P).
Lo correcto es poner todas las secuencias de animacion, movimiento, etc. en archivos externos al ejecutable, si miramos el codigo que te he puesto es compatible al 100% con ello, ya que puedes tener un interprete de texto plano o xml por ejemplo que te cree las clases en tiempo de ejecucion, un ejemplo:

El archivo movertio.anim tendria dentro:

animar pepe
mover pepe a mesa
esperar 5
coger telefono
etc...


Cada instruccion: animar, mover, esperar, coger, etc. puede ser una clase derivada de Key indicandole sus parametros, con lo que el interprete lo convertiria en esto:

// Crear las animaciones
m_Seq = new dib::Library::Anim::Sequence( 4 );
m_Seq->SetKey( 0, new dib::Library::Anim::KeyAnimar(Pepe) );
m_Seq->SetKey( 1, new dib::Library::Anim::KeyMover(Pepe, Mesa) );
m_Seq->SetKey( 2, new dib::Library::Anim::KeyEsperar(5) );
m_Seq->SetKey( 3, new dib::Library::Anim::KeyCoger(Telefono) );
m_Seq->Compile();
// Crear el control de secuencias
m_Ctrl = new dib::Library::Anim::Control();
m_Ctrl->Start( m_Seq );


Si no me explico bien (como siempre) dimelo que o intento hacer mejor :lol:

Editado: Se me olvidaba, lo correcto normalmente es que el propio tile tenga si es o no pasable entre otros parametros, asi te ahorras un mapa de tiles para este objetivo y lo mas importante la memoria que ocuparia. Para que te hagas una idea pasate por mi web y mira uno de los subproyectos de dibGameMaker v1.2 llamado dibTiles.

erchus

 
CitarSi no me explico bien (como siempre) dimelo
No problemo...Todo entendido.
Esto es más o menos lo que yo pretendía...tener organizadas la animaciones de forma que no se lie un caos en el código. Por eso comentaba de lo de los archivos externos.

Asias.  :D  






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.