[Grafika] [WebTip] [Fotografování] [Galerie] [MujMac] [Printing]
  Redakce: info (at) builder.cz   Inzerce: reklama (at) grafika.cz
Diskuzní fóra
.Net (68471)
ASP (1591)
ActiveX (168)
Allegro (136)
Assembler (3926)
C++ Builder (23160)
C/C++ (44499)
Databáze (30680)
Delphi (78807)
DelphiX (1655)
DirectX (1464)
Java (39508)
JavaScript (12598)
Matematické programy (2178)
OOP a UML (732)
OpenGL (6920)
Php (65224)
PowerBuilder (464)
Problémy a algoritmy (10473)
Programování v Linuxu (2000)
Právo a programování (3384)
Python (1353)
Ruby (136)
Visual Basic (12078)
Visual C++ (12956)
Wap (56)
Web (10895)
Web servery (5549)
Win32 (13553)
Windows CE (865)
XML/XSL (1860)
Textová inzerce
Služby Builder.cz
  • Bazar - koupím(0)
  • Bazar - prodám(0)
  • Hledám práci(0)
  • Nabízíme práci(0)
  • Projekty(0)
  • Bludiště v DelphiX
    Chcete se dozvědět, jak v DelphiX nakreslit kruhový oblouk, nebo rovnou celé bludiště ? V tom případě je dnešní článek určen právě vám !
    Tvorba her v DelphiX
    Předchozí díl: Tvorba her v DelphiX - 5.díl

    Následující díl: Kolize ve hrách v DelphiX
    Autor: Václav Krejčí
    Rubrika: Delphi
    Publikováno: 27.08. 2001
     Tisk článku
    Poslat odkaz emailem
     



    Při brouzdání internetem jsem našel celkem zajímavou soutěž inspirovanou demoscénou. A to velikostí - podle 4kB dem se tvoří 4kB velký webdesing (html, java a flash), přesně tedy 4096 bajtů. Podle toho má soutěž i název - WEB4096 a je na adrese http://web4096.message.sk.


    Při takovýchto podmínkách jdou tvůrci většinou až na samou hranici prohlížečů, a tak není divu, že vznikají obdivuhodná díla. Co mě ale zaujalo byla tvorba v javě s názvem dynamic labyrint, kde labyrint v prohlížeči postupně měnil svůj tvar. A jelikož mě to zaujalo opravdu hodně, zkusil jsem něco podobného udělat v Delphi s DelphiX. Jak na to se vám pokusím popsat v dnešním článku.

    Hlavní činnost programu bude spočívat v kreslení kruhovách výsečí, proto byschom si měli říct, jakým způsobem něco takového nakreslit. Použijeme k tomu funkci Arc která má osm parametrů. Lépe než nějaký text vám určitě k pochopení poslouží tento obrázek:


    Opravdu to není nic složitého. Nesmíme hlavně zapomenout na to, že se oblouk kreslí proti směru hodinových ručiček od bodu 3 do bodu 4.
    Budeme tedy kreslit řekněme třeba devět oblouků, každý bude od předchozího vzdálen o deset pixelů, přičemž první bude od středu o dvacet (to aby nebyl tak malý). V každém oblouku bude jednen průchod široký 20° (později toto ještě upravíme). Dále se bude každý lichý oblouk točit po směru a každý suchý proti směru hodinových ručiček (jestli je to přesně naopak tak se omlouvám). Víc toho ani znát nemusíme a můžeme se pustit do programování.

    Nejprve si definujeme proměnnou kruhy jako pole typu TPoint, ve které bude uložen první a druhý úhel oblouku (nechtělo se mi definovat nový typ, proto jsem použil TPoint, jelikož jsem potřeboval dvě čísla. Nenechte se proto prosím zmást).

    
       kruhy : array [1..10] of TPoint; // uhel 1 a uhel 2
    


    Dále vytvoříme proceduru Form1.OnCreate a v ní si hned všechny úhly nastavíme:

    
    // ====== FORM CREATE ========================
    procedure TForm1.FormCreate(Sender: TObject);
    var i:integer;
    begin
     Randomize;
     // nastavení úhlů
     for i:=2 to 10 do
      begin
       kruhy[i].x:=Random(36)*10; // první úhel - náhodně
       kruhy[i].y:=kruhy[i].x-10; // druhý úhel
      end;
    end;
    


    Dále si vytvoříme proceduru DXTimer1.OnTimer. V ní si nejprve zjistíme střed plochy, který uložíme do proměnných cx a cy. Dále vymažeme plochu bílou barvou (všechno nemusí být černé :), vypočteme body pro průchody v kruhu (pt1 a pt2 typu TPoint), upravíme pro naše souřadnice (bod 0,0 odpovídá levému hornímu rohu zatímco ve skutečnosti je bod 0,0 vlevo dole). Dále každý oblouk pootočíme a nakonec nám nezbývá nic jiného než oblouky nakreslit. Výpis celé procedury je zde:

    
    procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
    var cx,cy,pol:integer;
    pt1,pt2,pt3,pt4:TPoint;
    i:integer;
    begin
     // vymazat pozadí
     DXDraw1.Surface.Fill(clWhite);
    
     // střed DXDraw...
     cx:=DXDraw1.SurfaceWidth div 2;
     cy:=DXDraw1.SurfaceHeight div 2;
    
    for i:=2 to 10 do
     begin
       // poloměr kruhu
       Pol:=i*10;
    
       // začátek "díry" v kruhu
       pt1.x:=Trunc(cos(DegToRad(kruhy[i].x))*pol);
       pt1.y:=Trunc(sin(DegToRad(kruhy[i].x))*pol);
    
       // konec "díry" v kruhu
       pt2.x:=Trunc(cos(DegToRad(kruhy[i].y))*pol);
       pt2.y:=Trunc(sin(DegToRad(kruhy[i].y))*pol);
    
     // sudý kruh otáčíme naopak než lichý...
     if i mod 2 = 1 then
      begin
       Dec(kruhy[i].x,1);
       Dec(kruhy[i].y,1);
      end
     else
      begin
       Inc(kruhy[i].x,1);
       Inc(kruhy[i].y,1);
      end;
    
     // posuneme body na naše souřadnice - cx,cy...
     pt1.x:=pt1.x+cx;
     pt1.y:=cy-pt1.y;
     pt2.x:=pt2.x+cx;
     pt2.y:=cy-pt2.y;
    
     with DXDraw1.Surface.Canvas do
      begin
       Brush.Style:=bsClear;
       Pen.Color:=clBlack;
    
       // vlastní kreslení oblouku
       Arc(cx-pol,cy-pol,cx+pol,cy+pol,pt1.x,pt1.y,pt2.x,pt2.y);
    
      end;
    
    end; // end for
    
     // nakonec ještě otazník
     with DXDraw1.Surface.Canvas do
      begin
       with Font do
        begin
          COlor:=clBlack;
          Name:='Arial';
          Size:=10;
          Style:=[fsBold];
        End;
    
       TextOut(cx-3,cy-7,'?');
       release;    // !!
      end;
    
     // a už jen flip... 
     DXDraw1.FLip;
    end;
    


    Pokud program spustíme, bude vypadat nějak takto:


    Na první pohled je však zřejmé, že tím, že jsme nastavili každý průchod pevně na úhel 20° vznikl celkem nehezký efekt. A to ten, že u nejmenšího kruhu je průchod sotva patrný, zatímco u největšího je opravdu velký. To samozřejmě nechceme, proto si teď ukážeme, jak nastavit šířku průchodu pevně například na dvacet pixelů, což znamená, že u každého oblouku bude jiný úhel.

    Opět to nebude nic jiného, než trocha matematiky:


    Pokud známe tento vzorec, není žádný problém vytvořit nový pro výpočet úhlu alpha a poté přidat do procedury OnCreate. První úhel necháme opět náhodně a druhý pracně dopočítáme. Výsledek bude vypadat nějak takto:

    
    // ====== FORM CREATE ========================
    procedure TForm1.FormCreate(Sender: TObject);
    var i:integer;
    alpha,a,pol:integer;
    begin
     Randomize;
     // nastavení úhlů
     for i:=2 to 10 do
      begin
       kruhy[i].x:=Random(36)*10; // první úhel - náhodně
    
       // kruhový oblouk                     .
       //      2pi * r                       .
       // a = ---------  * alpha             .
       //        360                         .
    
       a:=20;  // velikost průchodu bludiště
       pol:=i*10;
       alpha:=Trunc(a/((2*pi*pol)/(360)));
    
       kruhy[i].y:=kruhy[i].x-alpha; // druhý úhel
      end;
    end;
    


    Program můžete znovu spustit a opravdu - všechny průchody jsou již stejně široké.


    Když už jsme u toho, proč si nepřidělat ještě nějaké ty čáry mezi jednotlivými oblouky ? Řekněme, že každá čára bude začínat u bodu pt2 a půjde pod stejným ůhlem až k druhému oblouku (tedy k bodu pt4 který si vypočítáme). U posledního, tedy desátého samozřejmě kreslit čáru nebudeme. Zde je kód který musíme přidat pro správné fungování:

    
    ...
       // p4 - čára mezi kruhy
       pt4.x:=Trunc(cos(DegToRad(kruhy[i].y))*(pol+10));
       pt4.y:=Trunc(sin(DegToRad(kruhy[i].y))*(pol+10));
    ...
    
    ...
     // posuneme body na naše souřadnice - cx,cy...
     pt4.x:=pt4.x+cx;
     pt4.y:=cy-pt4.y;
    ...
    
    ...
       // kreslení čáry
       if i <> 10 then
        begin
         MoveTo(pt2.x,pt2.y);
         LineTo(pt4.x,pt4.y);
        end;
    ...
    


    Jako obvykle si program přeložíme a spustíme, výsledek bude zřejmě podobný tomuto:


    A tím bychom mohli i dnes skončit. Pokud však opravdu chcete ještě něco extra, zkuste místo nastavení barvy pera na čarnou přidat tento řádek:

    
       // barva podle vzdálenosti od středu...
       Pen.Color:=RGB(i*22,i*22,i*22);
    


    Výsledek bude ještě hezčí. A to je pro dnešek opravdu vše.


    Download

    Zde si můžete stáhnout dnes vytvořený příklad a zdrojáky (192 kB).

    Relevantní články

    Seriál - Tvorba her v DelphiX
    Seriál - Tvorba hry Had v DelphiX
    Zobrazení části obrázku v DelphiX
    Komponenta DXImageList
    Simulace sněžení v DelphiX
    Zobrazení kurzoru v DelphiX
    Posuvný text v DelphiX
    Isometrický engine v DelphiX
    Sprity v DelphiX (C++ Builder)




    Hodnocení článku
    1 | 2 | 3 | 4 | 5
    Aktuální známka: 2.54
    (Počet známek: 3651)

    Komentáře k článku
    -- Žádné příspěvky --
    Přidat příspěvek




    info@builder.cz
    Vydává Grafika Publishing, s.r.o.
    Copyright (c) 1997-2002 Všechna práva vyhrazena