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.
|