petricak
24. 3. 2003 • 18:14

Při psaní těchto zdrojový textů a spuštění aplikace se mi zvírazní syntaxe jako chybná .Může to být tím že mám delphi" a delphi x pro 5? procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);".

Kvido Wohnout
15. 3. 2003 • 14:06


Programování her v Delphi, díl 1. - DirectX, úvod do DirectDraw
Kamil Foltin - 20.4. 2001
Asi si řeknete Co je to za hloupost - programovat hry v Delphi? Tak třeba v C++, to zní jinak, a přece, i v Delphi lze celkem dobře a jednoduše psát hry na současné grafické úrovni.

Asi si řeknete "Co je to za hloupost - programovat hry v Delphi?" Tak třeba v C++, to zní jinak, a přece, i v Delphi lze celkem dobře a jednoduše psát hry na současné grafické úrovni. A proč vlastně ne? Delphi obsahují velice dobrý kompilátor jazyka Object Pascal, který generuje skoro stejně rychlý kód jako třeba C++.

Připustíme-li tedy, že i v Delphi můžeme naprogramovat hry zbývá otázka: "Jak?" A právě tu se pokusím v následujícím článku zodpovědět. Pokud něčemu nebudete rozumět, klidně to přeskočte a vraťte se k tomu později.

Předpokládám, že alespoň trochu znáte prostředí Delphi a jazyk Object Pascal. K práci budeme potřebovat knihovny DirectX od Microsoftu. DirectX je mocný nástroj, s jehož pomocí můžete bez větších problému používat téměř jakýkoliv hardware; stačí k němu mít pouze příslušný ovladač a DirectX se o všechno postará. Ovšem psát jen tak čistě pod DirectX není žádná slast, a proto jednou jeden chytrý pán jménem Hiroyuki Hori napsal (dle mého názoru nejlepší) komponenty umožňující snadnou práci právě s DirectX. Tyto komponenty se jmenují DelphiX a můžete si je zdarma stáhnout na Hiroyukiho stránkách. Krom toho budeme samozřejmě potřebovat DirextX. Program, který si v závěru napíšeme si můžete stáhnout i v hotové podobě.

Pokud už máte stažené komponenty DelphiX, rozbalte je a měly by se vám vytvořit následující adresáře:

/Source: Zde je kompletní zdrojový kód k DelphiX (nesnažte se ho pochopit-netřeba).

/Samples: Ukázkové programy. Můžete si je projít, abyste viděli, co DelphiX umí.

/Help: Nápověda, která nefunguje . Musíte si stáhnout záplatu. Nápověda ale není upřímně moc dobrá, je celkem k ničemu.

/FFEffects: Přednastavené efekty pro ForceFeedbacková zařízení.

/Bin: Zde jsou uloženy 3 instalační soubory, které zaregistrují komponenty do prostředí Delphi. Spusťte Install_for#.exe, kde # je verze Delphi, kterou používáte. V Delphi by se měla objevit nová paleta DelphiX s následujícími komponentami:



  • DXDraw: Slouží k obsluze DirectDraw, Direct3D, zajišťuje komunikaci s grafickou kartou a přímý přístup do videopaměti.
  • DXDib: Komponenta na uložení jedné bitmapy (Device Independent Bitmap-DIB).
  • DXImageList: Ukládá několik DIB.
  • DX3D: Původně byla tato komponenta určena ke komunikaci s Direct3D, nyní je implementována v DXDraw.
  • DXSound: Obsluha DirectSound.
  • DXWave: Slouží k uložení jednoho wav souboru.
  • DXWaveList: Více wav souborů...
  • DXInput: Obsluha DirectInput a příšerek podporujících ForceFeedback.
  • DXPlay: Komunikace po místní síti a internetu (pro hry s multiplayerem).
  • DXSpriteEngine: Komponenta (plus několik dalších tříd) pro zacházení se sprity-animované objekty.
  • DXTimer: Podobná komponenta jako Timer, ale asi 50x rychlejší (klasický Timer se časuje zhruba 18x za sekundu ale DXTimer téměř 1000x)
  • DXPaintBox: Jako PaintBox z VCL, ale přes DirectX.
  • Takže to bylo něco málo k seznámení s DelphiX a teď se vrhneme na asi nejzajímavější část DirectX:



    DirectDraw

    Něco k teorii: v drtivé většině her je plynulost animace založena na neustálém překreslování scény. Tu "neustálost" bude zajišťovat DXTimer při volání své události OnTimer, ve které bude kód vykreslující bitmapy a jiné objekty. Takže jeden DXTimer dejte na prázdný Form. Má pouze 3 (nepočítám Tag a Name) vlastnosti, tak se na ně podíváme:

    ActiveOnly: Nastavíte-li na True, pak se bude událost OnTimer provádět pouze, pokud je aplikace v aktivní; tj. zmáčknete-li za běhu programu Alt+Tab, DXTimer se deaktivuje a zároveň se volá událost OnDeactivate. Po obnovení aplikace z pozadí začne DXTimer opět časovat a volá se událost OnActivate. Je-li nastavena na False, DXTimer časuje furt.

    Enabled: Zapnut/vypnut - klasika.

    Interval: Prodleva mezi jednotlivými volání procedury OnTimer. Poznámka: VCL Timer nedovoluje do této vlastnosti dát 0, ale DXTimer to umožňuje a pokud tak učiníte, nebude prodleva žádná a aplikace tak poběží jak nejrychleji to půjde.

    Krom toho je tu ještě jedna run-timeová vlastnost FrameRate, ve které se dozvíte, kolikrát byla za poslední sekundu volána procedura OnTimer (FPS).

    Jak jsem již napsal, k obsluze DirectDraw slouží komponenta DXDraw. Některé její vlastnosti:

    Display: Určuje v jakém režimu bude DXDraw pracovat. První dvě čísla určují velikost povrchu, na který budeme kreslit (má smysl jen ve FullScreen(viz níže)) a třetí je barevná hloubka v bitech.

    Options: Nastavení DXDraw. Vyjmenuji jen ty nejdůležitější, k ostatním se když tak vrátím později.

  • FullScreen – je-li True, aplikace se po spuštění přepne na celou obrazovku.
  • WaitVBlank – nevím, k čemu je to dobré, ale dáte-li tam False běhá hra daleko rychleji.
  • DoHardware – zda-li se má použít hardwarově urychlené vykreslování grafické karty.
  • Rychlé a netrhané animace v DirectDraw jsou založeny na tzv. doublebufferingu. Znamená to, že ve videopaměti jsou vyhrazeny 2 stejně velké(velikost záleží na rozlišení) buffery(úseky), z nichž první je zobrazován na obrazovku a do druhého se kreslí. První se nazývá primary surface a druhý back surface. Jakmile je kreslení do back surface dokončeno, přepne se zobrazování mezi primary a back surface voláním metody TDXDraw.Flip. Oba tyto buffery jsou třídy TDirectDrawSurface, což je obecně třída sloužící k uložení grafiky, ale nemusí se přímo zobrazovat na obrazovku - v tom případě se nazývá offscreen surface. Připravíte si tam obrázky, textury apod. a teprve když je chcete vykreslit, prostě je zkopírujete do back surface, ale o tom později. Zatím nás budou zajímat tyto dvě položky:

    TDXDraw.Surface: Ukazuje na back surface.

    TDXDraw.Primary: Ukazuje na primary surface.



    Barvy

    K určení barvy se v DelphiX používá barevný systém RGB888 v 24 bitovém režimu, tj. 8 bitů pro červenou, 8 pro modrou a 8 pro zelenou složku barvy, nebo RGB565 v 16ti bitovém režimu, tj. 5 bitů pro červenou a modrou a 6 bitů pro zelenou složku (lidské oko je na tuto barvu nejcitlivější). Model RGB565 je ovšem docela složitý na editaci a proto se při rozlišení menší než 24 bitů díky barevným maskám DelphiX dá použít bez větší deformace barvy model RGB. A ještě k zápisu barvy: doporučuji používat hexadecimální zápis, ve kterém každou složku barvy reprezentuje číslo 00-FF. Znakem "$" dáme najevo překladači, že se jedná o hexadecimální zápis a pak vypíšeme barvu. tj $FF0000 - 100% červená, $008000 - 50% zelená, $000040 - 25% modrá, $FFFFFF - bílá apod.

    Třetí a poslední komponenta, kterou budeme v tuto chvíli potřebovat je DXImageList. Slouží pouze k uložení bitmap,nemá žádné události a nabízí několik metod na vykreslení bitmap do DXDraw. A její vlastnosti:

  • DXDraw: Sem nastavíte DXDraw, který jste dali na Form.
  • Items: Pokud kliknete na ty tři tečky napravo, otevře se vám editor kolekce. Insertem vložte novou položku (TPictureCollectionItem). Má několik vlastností, které nás budou zajímat.
  • PatternHeight, PatternWidth, SkipHeight, SkipWidth: Jsou potřeba, pokud chceme zobrazit pouze část bitmapy. Budu jim věnovat samostatnou kapitolu v některém z příštích dílů.
  • Picture: Těma třema tečkama otevřete OpenDialog, kde stačí jen vybrat obrázek, který se zařadí do DXImageListu. Používejte pouze bitmapy(BMP,DIB), komprimované formáty typu JPEG nebo GIF nejsou podporovány (nevykreslí se), přestože jsou ve filtru uvedeny.
  • SystemMemory: Má-li se pro obrázek rezervovat systémová paměť.
  • Transparent: Je-li True, pak je každý pixel obrázku barvy TransparentColor průhledný.
  • Takže si vytvoříme Form s jedním DXDraw (ještě bych nastavil jeho vlastnost Align na alClient – budeme chtít použít pro vykreslování celou plochu formuláře), DXTimerem (ujistěte se, že je zapnut) a DXImagelistem, do kterého jsme nahráli jednu bitmapu. Dvakrát poklepeme na událost OnTimer DXTimeru a otevře se procedura do které vypíšeme tento kód:

    procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
    begin
      if not DXDraw1.CanDraw then exit;
      // otestuje, zda DXDraw povoluje kreslení
      DXImageList1.Items[0].Draw(DXDraw1.Surface,10,20,0);
      // metoda, která vykreslí položku 0 z DXImageListu1 do back surface DXDraw1 na
      // souřadnice 10,20. Poslední číslo je PatternIndex; budu se mu věnovat v příštích dílech,
      // zatím dávejte 0.
      DXDraw1.Flip;
      // přepnutí mezi primary a back surface
    end;

    Nyní už můžete aplikaci spustit a měli byste vidět obrázek na souřadnicích 10,20 (přepočítat !!! )

    Jistě byste asi rádi aby to taky něco dělalo, třeba hýbalo. Není problém. Definujte 4 globální proměnné X,Y typu integer, inX,inY typu boolean a upravte předcházející kód:

    begin
        if not DXDraw1.CanDraw then exit;
        DXDraw1.Surface.Fill($0);
        // Tato metoda vymaže povrch daného surface barvou uvedenou jako parametr
        if x>DXDraw1.SurfaceWidth-50 then inX:=false else if x<0 then inX:=true;
        if y>DXDraw1.SurfaceHeight-50 then inY:=false else if y<0 then inY:=true;
        if inX then inc(X) else dec(X);
        if inY then inc(Y) else dec(Y);
        // Aby se bitmapa odrážela od stěn. SurfaceWidth,SurfaceHeight určují
        // výšku a šířku surfacu
        DXImageList1.Items[0].Draw(DXDraw1.Surface,X,Y,0);
        DXDraw1.Flip;
    end;

    Tak spusťte a na obrazovce by měla být vidět bitmapa odrážející se od stěn. Rychle a bez blikání.

    A co říci na závěr? Doufám, že vás DelphiX nadchlo stejně tak jako mě. Pokud ano, tak se máte na co těšit, protože toto je pouhý zlomek toho, co DelphiX umí a co si v příštích dílech ukážeme...

    Milan P.
    15. 10. 2002 • 7:07

    Mohli by ste mi nekdo prosim vas napsat podrobnejsi navod na DXSpiriteEngine

    (Mila.Prokop@seznam.cz)

    Activer
    4. 8. 2001 • 0:33

    Cau.
    Mel bych mensi dotaz. Nevite jak vytvorit gamesu v DelphiX, aniz by se
    jeji rychlost odvijela od toho, jak mas rychlej komp - priklad : muj komp
    zvlada v pohode, a tudiz se FPS odviji podle refresh rate monitoru. kdyz ji
    nastavim mensi jede to pomaleji nez kdyz ji povolim na vetsi. pokud to
    pustim na pomalejsim pocitaci, ktery to zvlada treba na 10 FPS tak vse pohne
    v praxi 10x za vterinu, coz je dost neprakticky.

    activer


    Mare Minařík
    4. 5. 2001 • 8:45

    Po spuštění Vašeho prvního příkladu se mi místo obrázku ukáže pouze černé okno.......

    marz
    29. 5. 2006 • 13:47

    taky mi to dela a nemuzu prijit an to, proc, nevite nekdo, cim by to mohlo byt, odepiste prosim, dekuji

    Ales Berka
    29. 4. 2001 • 16:49


    Reakce na prvni odstavec:

     

    Proc by ne, Original War je programovanej v Delphi :)

    Lopin
    25. 4. 2001 • 22:41

    Nejde mi stáhnout hotový program.

    Vaclav Krejci
    25. 4. 2001 • 18:47

    Zdravim autora...

    Měl bych pouze pár připomínek ke článku...

    1) ...kompletní zdrojový kód k DelphiX (nesnažte se ho pochopit-netřeba) - pro ty, kteří to z programováním myslí vážně - není na škodu si jej párkrát cvičně projít, budete svým programům víc rozumět.

    2) nápověda funguje, jde pouze o to, kterou verzi DelphiX máte

    3) Nápověda ale není upřímně moc dobrá, je celkem k ničemu - neberu autorovi jeho názor, pro ostatní - mně osobně hodně pomohla, najdete v ní dost věcí...

    4) dle poznámek 1 a 3 je jisté, že autor nepoužívá nápovědu, ani nestuduje zdrojové kódy komponent. Je tedy otázkou, kde získal příslušnou znalost problematiky, jelikož cizojazyčných článků je opravdu pomálu. Nepočítám samozřejmě možnost četby microsoft directX manuálu, jelikož, jak autor sám píše není pro něj psaní programu čistě pod DirectX žádná slast...

    5) WaitVBlank – nevím, k čemu je to dobré, ale dáte-li tam False běhá hra daleko rychleji. - tak tato poznámka mě opravdu dostala. Nevím k čemu to je, ale když to funguje, tak pro to tam nenechat... Stačí se podívat do nápovědy, která je "celkem k ničemu" - Vertical scanning lines are waited for when the Flip method is called so that the screen should not flicker, aneb RTFM !

    6) Tak spusťte a na obrazovce by měla být vidět bitmapa odrážející se od stěn. Rychle a bez blikání. - tak toto jsem již někde viděl...


    Na závěr ještě pár linků, které autor raději nenapsal. Bůh ví proč, ti, kdo chtějí něco v DelphiX spáchat se bez nich neobejdou:

    http://turbo.gamedev.net
    http://www.builder.cz
    http://www.prog.cz

    Petr Holcz
    25. 4. 2001 • 18:47

    Samochvála smrdí...

    Kamil
    2. 6. 2003 • 2:15

    Autor clanku je kokot zahledeny do Microsoftu, ktery nic jineho nezna a neuznava, tak se priste neobtezujte nejak reagovat na jeho vylevy demence.

    vasa
    25. 4. 2001 • 18:47

    WaitVBlank je cekani na vertikalni zatemneni (doby, kdy se paprsek na monitoru vraci do vychozi polohy). Pouziva se to k synchronizaci vykreslovani sceny s vykreslovanim na monitoru (jinak tam vznikaji kazy). A je jasne, ze kdyz se na neco ceka, tak je to pomalejsi :). Toto si urcite pamatuje kazdy, kdo programoval nejakou real-time grafiku (napr. pod DOSem, ba Amize atd...)

    jimiii
    25. 4. 2001 • 18:47

    Program napsany v textu mi po spusteni vyvolal vyjimku "DDraw.dll not loaded"

    Azazel
    25. 4. 2001 • 18:47

    Zkus si nainstalovat Directy

    Ivo
    25. 4. 2001 • 18:47

    Programovat hry ve 3D lze i v prostředí 3DMORFIT, a to pro C++, Delphi i Visual Basic. Osobní zkušenost zatím nemám.

    Jan Kozusznik
    25. 4. 2001 • 18:47

    Myzslim, ze kazdemu kdo nekdy napsal pod windowsem neco vetsiho nez je program typu krizek honi kolecko je asi jasne,ze tezko se v DelphiX da napsat neco rychlecho a konkurence schopneho. Je to komponenta dobra tak na obcesne kratochvile s grafikou pod woknousy, pokud chceme sahat na nizsi vrstvy nez je winapi. Ale jinak docela dobry clanek.

    Ivo Skalický
    25. 4. 2001 • 18:47

    Já si zase myslím, že ty myslíš špatně! DelphiX je přímý využívaní DirectDraw, tak nechápu co na tom máš pomalýho. Už jsem v tom pár her udělal tak mi věř. Třeba menu Becherovky Race je dělaný v tom. A nebo Photo destructor je dělanej celej v tom. No a pokud chceš vědět o něčem v čem uděláš v Delphi hru (trojdimenzionální) jak víno, tak tady máš link. GLScene To by mohl být i apel na autora článku, ať se vykašle na DelphiX, protože to je starý a všichni už v to uměj a ať radši nakousne GLScene, protože to je fakt dobrý a profesionální. Ať žije OpenGL. Mimochodem nevíte někdo jak vložit parametr rotace objektu podle vektorové osy? Nějak mi to nejde!

    tempsoft
    3. 5. 2001 • 13:28

    Musím souhlsit s autorem reakce "Je to úplně jasné" v tom pohledu, že využití komponent typu DelphiX je skutečně vysoce neefektivní způsob práce s DirectX. Uznávám, že pro mnohé, kdo se nechtějí otravovat s učením se DirectX, je tato varaianta vytváření "her" stravitelná, ale nezdá se mi ani trochu rozumná. Dále bych reagoval na onen autorův výstižný slovní výplod charakterizující úroveň celého článku: "nevím co to dělá, ale dáte-li tam False, tak hra bvěží daleko rychleji." ... kupodivu, že? To je ale novinka, že nám hra poběží rychleji při zakázání synchronizace vykreslování s vertikálním paprskem, že? Taky proč by měla... nechci tady na někoho jakkoli plivat ani snižovat úroveň článku (ostatně, s prominutím, mám dojem, že už to nelze...), jde mi jen o to, že po přečtení článku jsem neměl ani ten nejmenší důvod domnívat se, že tento člověk někdy programoval hry jiným způsobem než využitím GDI. Článek, který se tváří, jakoby byl o DirectX, by dle mého názoru měl obsahovat nejen zběžné informace o komponentách pro Delphi, a to ještě pohledem, který by se dal přirovnat k pohledu z letadla... odpusťte mi tuto snad příluišnou kritiku, ale pod ti¨tulkem, který článek nesl, jsem skutečně čekal víc.

    Radek
    25. 4. 2001 • 18:47

    Boží... konečně budu moct napsat multidimenzionální piškvorky :o)

    Určitě si přečtěte

    Články odjinud