LECKÉK:              

Saját ablak

Directdraw1

Directdraw 2

Directdraw_3

Sprite_1

Üdvözöllek!

Ebben a leckében létrehozzuk az un. képernyőn kívüli felületeket,és betöltjük a bmp képeket sorra a memóriába. Én szoktam csinálni egy atom nevű bmp-t,mert  oda teszek minden sprite képet, amolyan elemi részeknek gondolom.

egy másik kép pedig lehet maga a pálya egy harmadik pl grafikus számok betűk stb..

Most csak egy háttér és egy sprite-os képet fogunk betölteni.

Ha a betöltés megtörtént,akkor a folyamat úgy zajlik, hogy átlapoljuk az egész háttérképet a hátsó képernyő felületére, ezzel minden sprite-ot letörültünk.Majd szépen egyesével felrajzoljuk a sprite-okat az új pozícióban. Ha minden rajzolással készen vagyunk, akkor jön a flip() függvény és kezdjük elölről. Régebbi lassabb gépeken azt a megoldást kell választani,hogy csak a sprite régi helyén

állítjuk vissza a hátteret, és úgy rajzoljuk ki az új helyre őket. Ezzel kb fél képernyőnyi ujra rajzolást meg lehet spórolni.... De a mai világ a sebességé.

A felmerülő probléma hogy egy sprite ritkán téglalap alakú, pedig átlapolni csak téglalapokat lehet.A megoldás, hogy a haszontalan területet egy átlátszó színnel kell feltölteni, aminek az értékét megadhatjuk. A load függvényt ketté választottam, mégpedig azért, mert elveszhetnek a képernyő felületek, és akkor a helyreállításra újból be kell tölteni a képet. Ezért lesz úgy megírva, hogy melyik képet hova, és lesz egy olyan függvény,ami mindet betölti. Tehát dekraláció:

protected:

void load_init(int melyiket=-1,int hova= 0); //üresen meghívva =inicializálja az összeset 
bool loadbmp(LPCTSTR nev,int hova); //ez tölti be a képet
DWORD szinkulcs; //az átlátszó szín tárolására

megvalósítás:

Konstruktorban inicializáljuk a színkulcs értékét: színkulcs=0x00ff00ff;//lila szín.

Hozz létre a projectben egy új mappát    map   néven és ide tegyél egy 800x600-as háttérképet

h8.bmp néven valamint a csatolt fájl-ból (lásd lent) az atom.bmp képet.

Megvalósítás:

/**/
void RAJZ::load_init(int melyiket,int hova)
{
int i=0,hossz;
LPCTSTR nevek[]={"map\\h8.bmp","map\\atom.bmp",""}; //itt tároljuk a neveket,utoljára egy üres sztring
if (melyiket ==-1)
{
while(1)
{
hossz= strlen( nevek[i]);//lekérdezzük a sztring hosszát
if(hossz==0)break; //ha nincs vagy üres asztring vége
hova=i;
loadbmp( nevek[i],hova);
i++;
}
return;
}
else
{
hossz= strlen( nevek[melyiket]);
if(hossz==0)return;
loadbmp( nevek[melyiket],hova);
}

}
//
//
bool RAJZ::loadbmp(LPCTSTR nev,int i)
{


if(kepek[i].kep) //volt e mér brtöltve kép?
{
kepek[i].kep->Release();kepek[i].kep=NULL; //Ha volt már betöltve töröljük
}
HRESULT hRet; //info a függvény lefutásáról
DDSURFACEDESC2 ddsd;
DWORD* lPSurface=NULL;
int lPitch=0;
FILE *fp;
DWORD szine=0,size=0;
unsigned long width,height,lineend;
short type;/*,lineend*/;
unsigned char *sor;
fp=fopen(nev,"rb"); //megnyitjuk olvasásra
if(fp==NULL)
{
MessageBox(NULL,"nem jó név vagy elérési út","",0); return false;
}
fread(&type, sizeof(short), 1, fp);//afile nem 0x4d42 vel kezdődik,akkor nem bmp
if (type != 0x4D42)
{
fclose(fp);
return false;
}
fread(&size,sizeof(DWORD),1,fp);//fájl mérete
fseek(fp, 18, SEEK_SET); //18.byte-on van a szélesség magasság adat
fread(&width, sizeof(long), 1,fp);
fread(&height, sizeof(long), 1,fp);
lineend=(size-54-(width*height*3))/height;//hossz-fejléc * 3 szin a végr
ZeroMemory(&ddsd,sizeof(ddsd));//mivel tudjuk az adatokat létre lehet hozni a felületet
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
ddsd.dwWidth =width;
ddsd.dwHeight =height;
ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
ddsd.ddpfPixelFormat.dwRGBBitCount = 32;
ddsd.ddpfPixelFormat.dwRBitMask = 0x00ff0000;
ddsd.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
ddsd.ddpfPixelFormat.dwBBitMask = 0x000000ff;
ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0x00000000;
hRet = obj->CreateSurface(&ddsd, &kepek[i].kep, NULL); //előállítjuk a felületet
if (hRet != DD_OK) //a video memóriában
{
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
hRet = obj->CreateSurface(&ddsd, &kepek[i].kep, NULL); //ha nincs hely,akkor a rendszerben
}
if (hRet != DD_OK)
return false;
DDCOLORKEY ddck;
ddck.dwColorSpaceLowValue = szinkulcs;//hozzárendeljük a felülethez at átlátszó színt
ddck.dwColorSpaceHighValue = szinkulcs;
kepek[i].kep->SetColorKey( DDCKEY_SRCBLT, &ddck );
ZeroMemory(&ddsd,sizeof(ddsd));
ddsd.dwSize=sizeof(ddsd);
if ((kepek[i].kep->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL)) != DD_OK)//zároljuk az adatfeltöltéshez
//a Lock() függvény egyben visszaadja felület memóriacímét a lpSurface adattagban
MessageBox(hwnd, "Failed to lock the surface", "Surface Error", MB_OK);
lPitch = (int)ddsd.lPitch;
lPSurface = (DWORD*)ddsd.lpSurface; //felület memóriája
fseek(fp,54,SEEK_SET); //ráállunk az adatok elejére
for(int k=height-1; k>=0; k--)
{

sor=(unsigned char*)calloc(3*width,sizeof(unsigned char));//helyfoglalás egy sornyi adatnak
fread(sor,width*3*sizeof(char),1,fp);//belvasunk szélesség*3 byte-ot
for(unsigned long i=0; i<width; i++) //
{
szine=(*(sor+i*3+2)<<16)|(*(sor+i*3+1)<<8)|(*(sor+i*3));//átkonvertáljuk DWORD-é
lPSurface[i+k*(lPitch>>2)]=szine;
}
free(sor);
if(!feof(fp)) fseek(fp,lineend,SEEK_CUR); //sorvége átlépése
}
fclose(fp); //file lezárása
kepek[i].kep->Unlock(NULL); //képfelület felszabadítása
kepek[i].oszlop= width; //eltesszük a szélességet,és a magasságot hátha még kell.
kepek[i].sor= height;
return true;
}

Elég hosszúra sikerült,de kommentezve van. Gyakorlatilag ddig olvas a sztringek között,amíg egy üreset be nem olvas. csak arra kell figyelni,hogy a dekralációban több legyen  a képek száma, mint amennyit betöltünk (   KEP    kepek[10];   )Ha elfogy a videomemória beteszi a rendszermemóriába.

Hova is tennénk a load függvényünekt, mint az init végére!

.....

 UpdateWindow(hwnd); //ablakfrissítés
hatter(0x00000080);
load_init();// mivel nincs bemenő adat mindet betölti.
return true;//ha eddig elér a progi,akkor van dx felületünk.

Most jön az egész RAJZ osztály legfőbb függvénye a rajzoló függvény.A bemenő paraméterek magukért beszélnek. Dekraláció:

void rajzol(int forrasfelulet,int forrasx,int forrasy,int forrassz,int forrasm,
int celfelulet,int celx,int cely);

Azaz Megadod melyik betöltött képfelületről akarsz rajzolni,ott kijelölöd a téglalapot,majd

megadod a célfelületet ez lehet első képernyő,hátső képernyő,és akármelyik betöltött képfelület.Tehát képet másolhatsz a képre (akár). Azonban,ha a célfelület = -1 akkor a háttérre rajzol. Megvalósítás:

void RAJZ::rajzol(int fsurf,int fx,int fy,int fsz,int fm,int csurf,int cx,int cy)
{
HRESULT hr;LPDIRECTDRAWSURFACE7 mut;
if(csurf==-1) mut=back;
else mut=kepek[csurf].kep;RECT f,c;
f.top=fy;f.left=fx;f.right=fx+fsz;f.bottom=fy+fm;
c.top=cy;c.left=cx;c.right=cx+fsz;c.bottom=cy+fm;
hr=mut->Blt(&c,kepek[fsurf].kep,&f,DDBLT_KEYSRC | DDBLT_WAIT,0);
}

2db RECT tipusú struktúát kell kitölteni a bemenő adatokbó számítjuk ki, utána átadjuk a Blt() függvénynek.

használata:

A legegyszerűbben most a flip() függvénybe tesszük,mert mielőtt lapozunk, előtte rajzolunk. Később más osztályból fogunk rajzolni.elsőnek a hátteret,majd egy sprite-ot, ami egy golyó.

.......

rajzol(0,0,0,800,600,-1,0,0);//a 0-dik képfelületről 800x600 pixelt
rajzol(1,0,0,18,18,-1,400,300);//
az 1.képfelületről 18x18 pixelt
kiirbetu("első szövegem",100,100);
kiirszam(0x00ff00ff,100,120);

fordít futtat. Most vége van a rajz osztályunknak, jöhetnek a sprite-ok. A sprite-ok -nak nevezzük  a képernyőn lévő mozgó bábukat.tárgyakat, amik aktívak, azaz elmozdulnak.

ez lesz a következő osztály.

Jó tudni! VC6.0 debug mappában csak úgy futtatható az .exe ha odamásolod a map nevű mappát.

itt a kód:

vissza.