Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





¿como Hacer Esto?

Iniciado por SrDurden, 24 de Septiembre de 2004, 07:44:14 PM

« anterior - próximo »

SrDurden

 Hola!

Tengo pensado hacer un juego en plan Worms y me gustaría hacer un "generador" de terrenos. Más o menos tengo pensado como hacerlo pero antes de comenzar necesito saber algo básico...

¿Como podría crear un BMP? Tengo pensado programar el juego en C o en C++, soy muy novatillo en el tema y no sé ni donde buscar..

¿Necesito alguna librería en especial? Lo único que necesitaria sería alguna función en plan ColorPixel(Color,Posicion), y otra para definir el tamaño de la imagen..

¿Alguien me podría echar un cable? ¿O decirme donde buscar información sobre el tema?

Muchas gracias,

SrDurden (mola)

(mola)  (mola)  

Sacrifai

 Lo suyo sería que primero nos dijeras que librería o api vas a usar  (uoh) .

SrDurden

 Todavía no lo tengo pensado.

¿Alguna recomendación fácil? Es que ahora mismo solo quiero intentar hacer esto, es decir, crear la imagen aleatoria y mostrarla por pantalla...

Igualmente lo que tenía planeado era hacer servir imagenes BMP sin comprimir, por lo que en el fondo se podría poner una tira de bits con una cabecera, guardarla en el disco duro en un archivo con extensión BMP y después abrirlo con el Paint mismo.

¿Podría hacerlo directamente sin tener que hacer servir ninguna API ni librería?

Saludotes! (mola)

Sacrifai

 
Cita de: "SrDurden"¿Podría hacerlo directamente sin tener que hacer servir ninguna API ni librería?
Si sabes ensamblador sí, pero no te lo recomiendo.

Cita de: "SrDurden"¿Alguna recomendación fácil? Es que ahora mismo solo quiero intentar hacer esto, es decir, crear la imagen aleatoria y mostrarla por pantalla...
Te recomiendo SDL que es muy buena para empezar en la programación grafica ( al menos para mi ) y gracias a sus surfaces lo tendrás mas facil.


SrDurden

 Ok, pos voy a mirarme alguna API sencillita para ir probando cosas, ya os iré explicando  ;)

Muchas gracias por todo,

SrDurden (mola)

Warchief

 Yo tengo una pequeña libreria que he hecho para una práctica de programación paralela. Se cargan imágenes bmp de 24 bits y se guardan en escala de grises (8 bits). Si quieres te la paso, verás lo fácil que es tocar los píxeles como una quiera para hacer cualquier transformación (en mi caso la transformación de color verdadero a escala de grises).

Son sólo dos ficheros, así que no creo que haya nada mas sencillo.

Comentame si es eso lo que quieres.

Sacrifai

 Warchief a mi me interesaría verlo :).

Pogacha

 1ro tenes que definir:
Vas a usar VC++ 6.0?.
Para windows, para linux, multiplataforma, para gameboy, para xbox?
DirectX, OpenGL, solo DirectDraw, SDL o ...?
Por si no lo hiciste, antes de empezar, te recomiendo bajarte ejemplos de juegos sencillos y mira como andan, modificalos y hace un tuyo partiendo de las bases de otro, esta es la forma mas facil de internarte en la programación de juegos.
Si es una pregunta concreta, debo decirte que la verdad no se entiende del todo, como generar terrenos?, el sistema del worm es muy complejo para un novato (lo que hace (worm II) : de un mapa de booleanos ocupacionales genera las formas de los terrenos), Algo comparable y sencillo: "BMP" con un color de mascara, por ejemplo el azul puro, entonces este es atravesable y tambien remplazable por el cielo y agua, pero aun asi no lo veo sencillo para un novato, igual te deseo suerte.

ethernet

 para generar, cargar  y guardar una textura no hace falta ni saber compilador, ni API ni pollas, se puede hacer totalmente standard. Para muestra, un botón:

Texture.h



#pragma once

//#include "types.h"
#include "debug.h"
#include "math.h"

#include <map>
#include <vector>


#define DEBUG_TEX 1

//-------------------------
// macros de pánico
//-------------------------

#define GEN_BEGIN(name) \
class Texture##name: public color::GenTexture \
{ \
public: \
~Texture##name(){if(DEBUG_TEX) this->Write(#name##".tga"); } \
     Texture##name(int _x,int _y):GenTexture(_x,_y){ format = T_RGBA;  


#define INIT() Setup(); } \
   void Setup(){

#define PIXEL()\
    Gen();}\
   color::RGBA&  PixelFunc(int s,int t)  { static color::RGBA c; \
float x = -1.0 + 2.0*(float)s/(float)TextureData::x; float y = -1.0 + 2.0*(float)t/(float)TextureData::y; \
/*polares*/ Vector2f v(x,y); float r = vectorDist(v); float phi= atan2((float)y,(float)x);

#define GEN_END(name)   return c;}   color::Palete paleta;};


#define GEN_TEXTURE(x,a,b) new Texture##x(a,b)


//-------------------------

namespace color
{



typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned int dword;

//fowards
class TextureData;

class RGBA: public vectorSpace<byte,RGBA,4>
{  
   public:
 RGBA():vectorSpace<byte,RGBA,4>(0) {x[0]=x[1]=x[2]=x[3]=0;}
       RGBA(byte r,byte g,byte b, byte a = 255 ):vectorSpace<byte,RGBA,4>(0)
       {x[0]=r;x[1]=g;x[2]=b;x[3]=a;}
#if 0
       friend RGBA operator+(const RGBA &x,const RGBA &y)
       {
#define CLAMP(x) (x)>255?255:(x)

           word r,g,b,a;
           r = x[0] + y[0];
           g = x[1] + y[1];
           b = x[2] + y[2];
           a = x[3] + y[3];
           return RGBA(CLAMP(r),CLAMP(g),CLAMP(b),CLAMP(a));
#undef CLAMP
       }
#endif
};

class Palete
{
public:
struct PaletteEntry
{
 PaletteEntry(const RGBA &x,float y):c(x),i(y){}
       PaletteEntry(){}
 RGBA c;
 float i;
};

   PaletteEntry pal[64];
   int ii;

   Palete():
   ii(0){}
//insertar en orden xD
   void debug()
   {
       for(int i=0;i<ii;++i)
       {
          DLog("%d:%d,%d,%d\n",i,pal[i].c[0],pal[i].c[1],pal[i].c[2]);
       }
       
   }
void AddColor(float idx,const RGBA &c)
{
       
 pal[ii++]=PaletteEntry(c,idx);

 
}
RGBA Color(float idx)
{
       if(fabs(idx) > 1)
       {          
           idx = 1.0;            
       }
     
       for(int i=1;i<ii;++i)
       {
           if(pal[i].i>=idx)
           {
                float lerp = pal[i].i - pal[i-1].i;
             lerp = (idx-pal[i-1].i)/lerp;
                   return Linear(pal[i-1].c,pal[i].c,lerp);
           }
   
       }
       return RGBA(); //WE
 
}
};




class TextureData
{
public:

   enum {T_RGB=3,T_RGBA=4,T_LUMINANCE=1};

   TextureData():x(0),y(0),data(0){}
   TextureData(int _x,int _y):x(_x),y(_y),data(0){}
   TextureData(int _x,int _y,byte *d,int f):x(_x),y(_y),data(d),format(f){}
   virtual ~TextureData(){ Release();   }

   bool Write(const char * );
   bool Read(const char * );
   void Release()
   {
       //delete [] data;    
   }

   friend TextureData &operator*(float c,TextureData &t)
   {  
           register byte *p = t.data;
           int cx= t.x*t.y*t.format;
           int tmp;
           for (int i=0;i<cx;i++)
           {
               tmp=*p*c;
               *p = tmp>255?255:tmp&0xff;
               p++;
           }        
           return t;
       
   
   }

   RGBA GetRGBA(int i,int j)
   {  
       if( i<0 || i >= x) return RGBA();
       if( j<0 || j >= y) return RGBA();
       byte *p =&(data[(i*y+j)*4]);
       return RGBA(*p,p[1],p[2],p[3]);
   }
   void PutRGBA(int i,int j,const RGBA &c)
   {
       byte *p =&(data[(i*y+j)*4]);
       *p = c[0];
       p[1] = c[1];
       p[2] = c[2];
       p[3] = c[3];

   }
   
   void ApplyFilter(float *filter,int rowsize);
   
   TextureData(const TextureData &){/*assert(!"xD");*/}
   TextureData &operator=(TextureData &t)
   {
       if(&t == this) return *this;
       
       Release();
       data = new byte [t.x*t.y*t.format];
       memcpy(data,t.data,t.x*t.y*t.format);
       x= t.x;
       y =t.y;
       format= t.format;
       return *this;
   }
   friend TextureData operator+(TextureData &u,TextureData &v)
   {
        //assert(u.x == v.x && u.y == v.y);
        byte *mem = new byte [u.x*u.y*u.format];
        register byte *d = mem;
        register byte *p = u.data;
        register byte *o = v.data;
        int cx= u.x*u.y*u.format;
        int tmp;
        for (int i=0;i<cx;i++)
        {
               tmp = *o+*p;
               *d++ = tmp>255?255:tmp&0xff;
               p++;o++;
        }        
        return TextureData(u.x,u.y,mem,u.format);
   }
   friend TextureData operator*(TextureData &u,TextureData &v)
   {
        assert(u.x == v.x && u.y == v.y);
        byte *mem = new byte [u.x*u.y*u.format];
        register byte *d = mem;
        register byte *p = u.data;
        register byte *o = v.data;
        int cx= u.x*u.y*u.format;
        int tmp;
        for (int i=0;i<cx;i++)
        {
               tmp = *o*(float)(*p)/255;
               *d++ = tmp>255?255:tmp&0xff;
               p++;o++;
        }        
        return TextureData(u.x,u.y,mem,u.format);
   }

int y,x;
dword format;
   byte *data;
 
};





class GenTexture: public TextureData  
{
   public:
       
       bool Gen()
       {
           data = new byte [x*y*format];
           assert(data);
           byte *p=data;
           for(int i=0;i<x;i++)
           {
               for(int j=0;j<y;j++)
               {
       
                   RGBA &c  = PixelFunc(i,j);    
                   //for(int k = 0;k<format;++k)*p++=c[k];
                   *p++=c[0];
                   *p++=c[1];
                   *p++=c[2];
                   *p++=c[3];
               }
 
        }
           return true;
       }
       
   protected:

       
       GenTexture(int _x,int _y):TextureData(_x,_y){ }      
       virtual RGBA&  PixelFunc(int,int) = 0;
       
};


#ifdef DEBUG_TEX
class TextureManager
{
public:
   typedef GenTexture *(*generator)(int , int );
   
   static std::vector<generator> *Register(generator fn)
   {
       static std::vector<generator> Textures;
       if(!fn) return &Textures;        
       Textures.push_back(fn);
       return 0;
       

   }
   static void Flush()
   {
       std::vector <generator> *v = Register(0);
       for(int i = 0;i< v->size();++i)
           delete (*v)[i](128,128);
   }
   template <class T>
   struct TexReg
   {  
       static GenTexture *Gen(int x, int y) { return new T(x,y); }
       TexReg(){   TextureManager::Register(TexReg<T>::Gen );    }
   };
};
#endif





};



texture.cpp



#include "texture.h"  
#include "stdio.h"

#define REG_TEX(name) TextureManager::TexReg<Texture##name> __##name
namespace color
{

/*
REG_TEX(White);
REG_TEX(Black);
REG_TEX(Sine2);
REG_TEX(Sine);
REG_TEX(Perlin1);
REG_TEX(Paleta1);
REG_TEX(Fondo1);
REG_TEX(Perlin3);
REG_TEX(Perlin2);
REG_TEX(Perlin4);
REG_TEX(LM1);
REG_TEX(Marble);
REG_TEX(Cloud1);
REG_TEX(Madera);
REG_TEX(Sol);
REG_TEX(Sand1);
REG_TEX(GrisTex);
REG_TEX(Exp);
REG_TEX(Interferencia);
REG_TEX(Cloud2);*/
/*
GEN_BEGIN(Sine)
{
     
       float d = r;
       d = -fabs(cos(phi));
     
       c[0] = (byte)255.0*(d);
       c[1] = (byte)250.0*(d);
       c[2] = (byte)100.0*(d);
       c[3] = 255;
}
GEN_END()    

GEN_BEGIN(Sine2)
{
     
       float d =r;
       d = sin(1.3*d);
       c[0] = (byte)255.0*(1-d);
       c[1] = (byte)250.0*(1-d);
       c[2] = (byte)180.0*(1-d);
       c[3] = 255;
}
GEN_END()  

GEN_BEGIN(Exp)
{
       Vector2f v(x,y);
       float d = vectorDist(v);
       d = exp(- 3*d*d );
       c[2] = (byte)255.0*(d*=d);
       c[1] = (byte)255.0*(d*=d);
       c[0] = (byte)255.0*(d*=d);
       
       c[3] = 255;
}
GEN_END()

*/


   
       




bool TextureData::Read(const char *f )
{

   FILE *hFile;
unsigned char header[6];
unsigned char TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0}; //3 -escala de grises

if(!f) return false;
DLog("writing texture to %s\n",f );

hFile=fopen(f,"rb");
if(!hFile) return false;
   fread(TGAheader,sizeof(TGAheader),1,hFile);
fread(header,sizeof(header),1,hFile);
   
if( header[4]!= 32)
       return false;

   x = header[1] *256 + header[0];
   y = header[3] *256 + header[2];
   format = TextureData::T_RGBA;
//header[5]=0;
   //BGR to RGB
   //:_(
   this->data= new byte[x*y*4]; //solo rgba
   if(!data) return false;
   fread(data,format,x*y,hFile);
   byte *d = data;
   for (int i=0;i<x*y*format;i+=format)
   {  
       byte swap;
       swap = d[i];
       d[i]=d[i+2];
       d[i+2]= swap;
   }
   

fclose(hFile);
 return true;

}


bool TextureData::Write(const char *f){

FILE *hFile;
unsigned char header[6];
unsigned char TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0}; //3 -escala de grises

if(!f) return false;
DLog("writing texture to %s\n",f );

hFile=fopen(f,"wb");
if(!hFile) return false;

//valores adecuados

header[0]=x%256;
header[1]=x/256;
header[2]=y%256;
header[3]=y/256;
header[4]= 32;
header[5]=0;
   //RGB to BGR
   //:_(
   byte *d= new byte[x*y*format];
   if(!d) return false;
   memcpy(d,data,x*y*format);
   for (int i=0;i<x*y*format;i+=format)
   {  
       byte swap;
       swap = d[i];
       d[i]=d[i+2];
       d[i+2]= swap;
   }
   
fwrite(TGAheader,sizeof(TGAheader),1,hFile);
fwrite(header,sizeof(header),1,hFile);
   
fwrite(d,format,x*y,hFile);
fclose(hFile);
   delete [] d;
return true;
}

void NormalizeFilter(float *f,int r)
   {
       float t = 0;
       for(int i= 0; i <r*r; i++)
           t+=f[i];
       t=1/t;
       for(i= 0; i <r*r; i++)
           f[i]*=t;
   }
void TextureData::ApplyFilter(float *filter,int rowsize)
{  
       //solo RGBA
     //  NormalizeFilter(filter,rowsize);
           for (int i=0;i<x;i++)
           {
               for (int j=0;j<y;j++)
               {
                 
                   
                   unsigned int total[4] = { 0,0,0,0};
                   for (int ii=0;ii<rowsize;ii++)
                   {
                       for (int jj=0;jj<rowsize;jj++)
                       {
                            RGBA c = GetRGBA(i+(ii -rowsize/2),j+(jj -rowsize/2));
                            total[0] += filter[ii*rowsize+jj]*c[0];
                            total[1] += filter[ii*rowsize+jj]*c[1];
                            total[2] += filter[ii*rowsize+jj]*c[2];
                            total[3] += filter[ii*rowsize+jj]*c[3];
                            //total += filter[ii*rowsize+jj]*c;
               
                       }  
                   }
                   float rr  = 0.2;//rowsize*rowsize;
                   PutRGBA(i,j,RGBA(total[0]*rr,total[1]*rr,total[2]*rr,total[3]*rr));
                   
               
               }        
           }
           
   
}


};


SrDurden

 Hola!

Warchief, podrías mandarme los dos ficheros? me interesa  :P  

srdurden@gmail.com

Pogacha, el algoritmo lo tengo pensado un poco por encima, no pretendo hacer nada demasiado complicado, simplemente una imagen en blanco y negro con un terreno muy básico. Había pensado recorrer la imagen de abajo hacia arriba, y en cada línea mirar si en el pixel que tenga justo debajo hay terreno pintado o no, si hay hacer un random para ver si añado terreno o no.  Nada demasiado complicado, tendré que mejorar alguna cosilla (por ejemplo, para que no se creen barrancos) y listos :P

Todavía no sé que API utilizaremos porqué el juego lo haré con un compañero, es una práctica de una ALE (asignatura de libre elección) de la facultad, me imagino que tiraremos por SDL o directX. Anteriormente ya había hecho mis pinitos con allegro, SDL, div games studio y algo de directX.

Ethernet, ahora me miro el código, muchas gracias.

Saludotes y gracias a todos por contestar,

SrDurden (mola)







Warchief

 Holas,
os paso mi librería y os comento.
En el archivo encontraréis 3 ficheros.
- bmplib.h
- bmplib.c
- conversionS.c

Los dos primeros son la librería en sí. Tiene los métodos para cargar y guardar imágenes de 24 bpp y 8 bpp respectivamente. conversionC por tanto tiene el código para realizar la transformación.
Están en ANSI C, así que son totalmente comprensibles. Si queréis conocer exactamente la cabecera hay muchas páginas en internet sobre el tema. Lo interesante además de esa librería es ver como la cabecera de escala de grises incluye la paleta de colores (para 8bpps) y sin embargo los true-color no llevan paleta porque cada píxel ya lleva las componentes RGB del píxel. (Notad que en la estructura "struct" de 24bpp los colores están invertidos (BGR) porque Windows lo guarda todo al revés, ya sabéis).

Compilad con cualquier compilador, en Win o Linux, probado y funciona en ambos (aunque según el compilador o SO, el redondeo de la función de transformación puede hacer que algún píxel sea distinto en gris , imperceptible para el ojo humano).

Para ejecutar ya lo dice, pasadle un fichero true-color por parámetro y el nombre de la imagen gris de salida y listo.

Bajadla de:
Enlace directo

Espero que sea algo útil. Al final saqué un 9 (pero eso incluía todo el análisis paralelo en PVM, etc, etc, etc y poca nota sería de esos ficheritos)

Es muy sencillo y está bastante explicada, si aún así queréis preguntar algo u os interesa la parte paralela en PVM no tenéis más que pedir. ;)

SrDurden

 Hola!

Al final ayer por la noche encontré un libro que tenía hace tiempo por casa, "Cómo programar videojuegos en Windows", y el segundo ejemplo era más o menos lo que buscaba, implementaban bajo directX 8.0 una función PutPixel en la que dibujabas un pixel en pantalla. He hecho otra basándome en esta llamada ColorPixel, en la que le pasas unas coordenadas de la pantalla y te dice que Color tiene ese pixel.

A partir de ahí he hecho este código:


for (WORD jy=479; jy>0; jy-- ) {
for (WORD ix=639; ix>0; ix-- ) {
 
 //CODIGO DE LOS FOR  
 if (jy<350) { if (ColorPixel(ix,jy+1)==0xFFFF) PutPixel(ix,jy,0xFFFF);
 if ((rand()%3==1)&&(ix<639)&&(ColorPixel(ix+1,jy+1)==0xFFFF)) { PutPixel(ix,jy,0xFFFF); PutPixel(ix-1,jy,0xFFFF); }
 if ((rand()%3==1)&&(ix>0)&&(ColorPixel(ix-1,jy+1)==0xFFFF)) { PutPixel(ix,jy,0xFFFF); PutPixel(ix+1,jy,0xFFFF); }

 else { if (rand()%9000==1)  PutPixel(ix,jy,0xFFFF);  } }
 



 //SE CIERRA EL CODIGO DE LOS FOR
 }

SrDurden

 Se me ha fastidiado todo y encima no me ha dejado reeditar, vuelvo a copiar todo el post:

Hola!

Al final ayer por la noche encontré un libro que tenía hace tiempo por casa, "Cómo programar videojuegos en Windows", y el segundo ejemplo era más o menos lo que buscaba, implementaban bajo directX 8.0 una función PutPixel en la que dibujabas un pixel en pantalla. He hecho otra basándome en esta llamada ColorPixel, en la que le pasas unas coordenadas de la pantalla y te dice que Color tiene ese pixel.

A partir de ahí he hecho este código:


for (WORD jy=479; jy>0; jy-- ) {
    for (WORD ix=639; ix>0; ix-- ) {
if (jy<350) { if (ColorPixel(ix,jy+1)==0xFFFF) PutPixel(ix,jy,0xFFFF);
 if ((rand()%3==1)&&(ix<639)&&(ColorPixel(ix+1,jy+1)==0xFFFF)) { PutPixel(ix,jy,0xFFFF); PutPixel(ix-1,jy,0xFFFF); }
 if ((rand()%3==1)&&(ix>0)&&(ColorPixel(ix-1,jy+1)==0xFFFF)) { PutPixel(ix,jy,0xFFFF); PutPixel(ix+1,jy,0xFFFF); }

 else { if (rand()%9000==1)  PutPixel(ix,jy,0xFFFF);  } }
 
 }


La pantalla tiene una resolución de 640*450, con 16 bits de color (de ahí el WORD).

Lo que pretendo es pintar una imagen en blanco y negro que sea la máscara del terreno. Es decir, la forma del terreno. Los pixeles blancos (0xFFFF) son la parte del mapa que no formara parte del terreno, para entendernos, donde irá el cielo  :P Como la pantalla empieza siendo de color negro, lo único que se tendría que hacer es ir añadiendo pixeles blancos creando el cielo.

Para crear la forma del terreno, la función mira si el pixel inferior al actual (justo el de debajo) es de color blanco, si es de color blanco el pixel se pinta de color blanco. Esto acabará creando una tira blanca hacia arriba. Si sólo hiciera esto, quedarían un montón de rallitas blancas en la parte superior de la pantalla, en diferentes alturas, por lo que sería un terreno injugable. Así que a veces (sólo a veces, para darle más aletoriedad al terreno) mira si el pixel inferior derecho o izquierdo del actual es de color blanco, si es de color blanco pinta el pixel actual de color blanco. Esto hace que se vayan creando elevaciones de terreno rectas, para que el jugador pueda caminar. Si no tiene un pixel blanco cercano a él, hay una posibilidad sobre 9000 ((rand()%9000==1)) para que el pixel actual se pinte de blanco.

Por tanto acaba quedando el terreno con unos 7 u 9 picos, a diferentes alturas, formando una especie de triangulos. Vamos, esto:

   
 

Cada vez que se ejecuta el programa sale una forma diferente.

En principio esto ya me sirve, pero alguien se le ocurre como mejorar el algoritmo para que queden formas más redondeadas, en plan montes? Quiero decir, en vez de acabar en un pico acabar en un pico más suavizado, más redondeado.

Saludotes y gracias,

SrDurden (mola)

SrDurden

 Perdón, soy un novato, la acabo de volver a cagar  (nooo)

el mensaje que se me ha quedado a medias me es imposible editarlo, lo dejo por perdido.

Saludotes! (mola)

seryu

 puede utilizar cualqier tipo de suavizado 2d que existe, como el 2xsai, haz una busqueda de los filtros que usan emuladores como zsnes y puedes obtener el codigo fuente.






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.