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)
Lo suyo sería que primero nos dijeras que librería o api vas a usar (uoh) .
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)
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.
Ok, pos voy a mirarme alguna API sencillita para ir probando cosas, ya os iré explicando ;)
Muchas gracias por todo,
SrDurden (mola)
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.
Warchief a mi me interesaría verlo :).
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.
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));
}
}
}
};
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)
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 directoEspero 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. ;)
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
}
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:
(http://img36.exs.cx/img36/6942/mapa2.jpg)
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)
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)
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.
puedes usar un perlin y después aplicarle una función no lineal tipo x^2 o x^3
un saludo
¿que es un perlin?
He estado leyendo sobre perlin.. ¿Es un tipo de ruido, verdad?
Teniendo en cuenta que lo único que quiero es suavizar un poco los bordes.. me saldría a cuenta utilizar el perlin noise?
Aparte que únicamente utilizo dos colores.. ¿Vale la pena?
Y.. ¿alguien me podría explicar de manera sencilla en que consiste?
Saludotes! (mola)
PD=Alguien sabe pq no puedo por ejemplo editar el mensaje anterior?
Cita de: "SrDurden"PD=Alguien sabe pq no puedo por ejemplo editar el mensaje anterior?
Cuando pasan 15 minutos no te deja ;) .
Me refería a obtener el terreno mediante perlin aunque yo creo que la base que tienes hecha está muy bien. Busca info de filtros (como bien te dijo seryu), es muy fácil hacer uno promediador por ejemplo
saludos y ánimo
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); } }
}
Algunos tips:
Cuidado con ix>0 del for, jamas escribes en ix=0 y tampoco en jy=0
te queda una linea salteada a la izquierda y arriba
Tambien es estandart llamar i, j y k a las variables de un bucle.
En realidad el codigo es original, pero bastante raro tambien.
Te sugiero:
Para empezar solo te interesa la altura del terreno, con lo que puedes agarrarte mejor con
una tabla de alturas.
Este codigo lo escribí al vuelo, pero creo te será util.
int TablaDeAlturas[Resolucion_X];
for(int i=0; i<Resolucion_X; i++) TablaDeAlturas[i]=rand()%Resolucion_Y;
// algun tipo de filtro
// este es de lo mas torpe, puedes investigar al respecto
for(j=0; j<10; j++) // j variable muda de iteración, variando esto deberia variar la redondez.
{
for(i=1; i<Resolucion_X-1; i++)
{
TablaDeAlturas[i+1]+=TablaDeAlturas[i];
TablaDeAlturas[i-1]+=TablaDeAlturas[i];
}
for(i=0; i<Resolucion_X; i++) TablaDeAlturas[i]/=3; // promedia las alturas
}
for(i=0; i<Resolucion_X; i++)
{
// Lo ideal es usar lineas
// Line(i, 0,i, TablaDeAlturas[i], 0xFFFF);
// Line(i, TablaDeAlturas[i]+1, i, Resolucion_Y-1 , 0x0000);
// pero lo haremos poniendo pixels
for(j=0; j<TablaDeAlturas[i]; j++) PutPixel(i,j,0xFFFF);
for(; j<Resolucion_Y; j++) PutPixel(i,j,0x0000);
}
Pochaga, gracias por el aviso del >, no me había dado cuenta, cosa de las prisas :P Lo de ix y jy fue por las prisas, en principio iba a ser i y j como toda la vida ;)
Me ha gustado la idea de la tabla de alturas y el suavizado, con el código a saco se me sale de rango en alguna parte, pero mañana me pondré a buscar por donde me está petando :P
Con unas modificaciones del código de ayer hoy he conseguido esto:
(http://img84.exs.cx/img84/6942/mapa2.jpg)
Pero igualmente mañana probaré lo de la tabla de altura con el suavizador por promedio, me ha gustado la idea :P
Saludotes y gracias a todos,
SrDurden (mola)
PD=EDIT: Con lo que me has dicho y la imagen que he colgado, me he dado cuenta que me olvido dos pixeles a la derecha, uno encima y otro a la izquierda! Esas mates y esas prisas, jeje
for(i=1; i<Resolucion_X-1; i++)
{
TablaDeAlturas[i+1]+=TablaDeAlturas[i];
TablaDeAlturas[i-1]+=TablaDeAlturas[i];
}
Hablando de prisas, eso nunca puede andar bien.
Tenes que usar un double buffer para eso
int TablasDeAltura[Resolucion_X][2];
... // escries en TablasDeAltura[i][0] y luego
for j ...
for(i=1; i<Resolucion_X-1; i++)
{
TablaDeAlturas[i+1][j&1]+=TablaDeAlturas[i][(j+1)&1];
TablaDeAlturas[i-1][j&1]+=TablaDeAlturas[i][(j+1)&1];
}
...
...
}
Saludos
No entiendo pq se tiene que utilizar un double buffer..
y que es TablaDeAlturas[i+1][j&1]+=TablaDeAlturas[(j+1)&1]; ? y que es ese &1?
Saludotes,
SrDurden :(
Perdon por la confución que te cause. Aver si logro enmendar el error.
Si hago:
for(i=1; i<100; i++) t[i]+=t[i-1];
estoy haciendo:
t[1] = t[1] + t[0]
En el siguiente ciclo:
t[2] = t[2] + t[1] y como t[1] es ahora t[1] + t[0]
t[2] = t[2] + t[1] + t[0]
y asi
t[99]= t[99] + t[98] + t[97] + ... + t[0]
por eso es que no funciona, yo quiero que a cada elemento se le sumen los dos vecinos.
por eso mencione un doble buffer.
Un doble buffer consiste en tener dos tablas, una de escritura y otra de lectura
int Tabla1[100];
int Tabla2[100];
entonces leo los datos de la tabla 1 y los escribo en la tabla 2 y asi evito el acumulamiento.
Tabla2
= (Tabla1[i-1] + Tabla1 + Tabla1[i+1]) /3;
Luego los datos actuales que tengo quedan en la tabla 2.
y para vover a repetir el proceso debo
usar leer ahora en la tabla 2 y escribir en la tabla 1.
Tabla1 = (Tabla2[i-1] + Tabla2 + Tabla2[i+1]) /3;
Pero esto significa repetir el codigo que en definitiva es el mismo, por eso uso un arreglo bidimenisonal de esta manera
int Tabla[100][2];
cuando trabajo la primera vez me referire con el indice 0 a la tabla 1 y con el indice 1 a la tabla 2, ya que el c tiene como primer indice el 0 a diferencia del pascal que comienza con el 1
entonces me resulta de
...
Tabla[1] = (Tabla[i-1][0] + Tabla- + Tabla[i+1][0]) /3;
...
Tabla- = (Tabla[i-1][1] + Tabla[1] + Tabla[i+1][1]) /3;
...
lo cual puedo arreglar como
int Destino=1;
int Origen=0;
...
Tabla[Destino] = (Tabla[i-1][Origen] + Tabla[Origen] + Tabla[i+1][Origen]) /3;
...
Destino = 0;
Origen= 1;
...
Tabla[Destino] = (Tabla[i-1][Origen] + Tabla[Origen] + Tabla[i+1][Origen]) /3;
...
pero como vemos solo invierto los origen y destino asi que en muchas pasadas puedo calcular el valor de destino y origen cada vez.
si analizamos los numeros binarios:
0 = 0 B
1 = 1 B
2 = 10 B
3 = 11 B
4 = 100 B
5 = 101 B
6 = 110 B
7 = 111 B
Vemos que el utlimo bit se alterna entre 0 y 1, por eso al realizar la operacion logica AND ( & ), tenemos un filtrado del numero y me deja solo si es par o no.
23 & 1 = 1
12345 & 1 = 1
12342 & 1 = 0
12349 & 1 = 1
2340 & 1 = 0
2346 & 1 = 0
con esto puedo generar el origen y destino preguntando si es no es par el numero de la pasada.
for(j=0; j<Numero_de_pasadas; j++)
{
if(j & 1)
{
Origen = 1;
Destino =0;
} else {
Origen = 1;
Destino =0;
}
for(i=1; i<99; i++);
Tabla[i][Destino] = (Tabla[i-1][Origen] + Tabla[i][Origen] + Tabla[i+1][Origen]) /3;
}
y tambien como veras:
cuando j & 1 = 1 se cumple que Origen = 1 y cuando j & 1 = 0 se cumple de la misma manera que Origen = 0 por ende se deduce que Origen = j & 1;
Para destino es facil, destino vale 0 cuando origen vale 1 y 1 viceversa, de esta manera podemos decir que Destino = (j+1) & 1 de esta manera cuando j sea para j+1 sera par.
Entonces:
for(j=0; j<Numero_de_pasadas; j++)
{
Origen = j & 1;
Destino = (j+1) & 1;
for(i=1; i<99; i++);
Tabla[i][Destino] = (Tabla[i-1][Origen] + Tabla[i][Origen] + Tabla[i+1][Origen]) /3;
}
O si remplazo origen y destino por sus correspondientes valores:
for(j=0; j<Numero_de_pasadas; j++)
for(i=1; i<99; i++);
Tabla[i][(j+1) & 1] = (Tabla[i-1][j & 1] + Tabla[i][j & 1] + Tabla[i+1][j & 1]) /3;
Ten en cuenta que cuando j=0 , o sea la primera pasada se leera de Tabla[ ][0], o sea que es allí donde debes poner los datos en un primer lugar.
Numero_de_pasadas-1 es el ultimo valor de j valido antes de que salga del bucle, cuando esto ocurra habra escrito su ultima vez en Tabla[][ ((Numero_de_pasadas-1) +1) & 1 ] o sea en
Tabla[] [Numero_de_pasadas & 1], asi que si el numero de pasadas es par terminara en Tabla[][0] que es donde empezo.
Aun usando estos sistemas debes guardar casos especiales para Tabla[0][j &1] ya que no puedes hacer Tabla[-1][j&1] y lo mismo pasa del otro lado de la tabla, debes hacer el codigo especial para ese caso
for(j=0; j<Numero_de_pasadas; j++)
for(i=1; i<99; i++);
Tabla[i][(j+1) & 1] = (Tabla[i-1][j & 1] + Tabla[i][j & 1] + Tabla[i+1][j & 1]) /3;
Tabla[0][(j+1) & 1]= (Tabla[0][j & 1] + Tabla[1][j & 1]) /2;
Tabla[99][(j+1) & 1]= (Tabla[98][j & 1] + Tabla[99][j & 1]) /2;
Todo el codigo completo seria:
#define Numero_de_pasadas 10
#define Resolucion_X 500
#define Resolucion_Y 300
int Tabla[Resolucion_X][2];
int i,j;
for(i=0; i<Resolucion_X; i++) Tabla[i][0]=rand()%Resolucion_Y;
for(j=0; j<Numero_de_pasadas; j++)
{
for(i=1; i<Resolucion_X-1; i++);
Tabla[i][(j+1) & 1] = (Tabla[i-1][j & 1] + Tabla[i][j & 1] + Tabla[i+1][j & 1]) /3;
Tabla[0][(j+1) & 1]= (Tabla[0][j & 1] + Tabla[1][j & 1]) /2;
Tabla[Resolucion_X-1][(j+1) & 1]= (Tabla[Resolucion_X-1][j & 1] + Tabla[Resolucion_X-2][j & 1]) /2;
}
for(i=0; i<Resolucion_X; i++)
{
for(j=0; j<TablaDeAlturas[i]; j++) PutPixel(i,j,0xFFFF);
for(; j<Resolucion_Y; j++) PutPixel(i,j,0x0000);
}
Espero, haber ayudado esta vez.
Saludos y mucha suerte