LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> Perl (119) - Tk - CD man

Perl Zúročíme znalosti z předchozích dílů a naprogramujeme si zjednodušenou hru CD man.

29.10.2010 00:00 | Jiří Václavík | Články autora | přečteno 4745×

Na závěr minisérie o Tk využijeme naše dosavadní znalosti a napíšeme si hru.

O hře

CDman, PACman, Waka-waka, Pakuman; to jsou jen některé z názvů pro dnes již 30 let starou kultovní japonskou hru. Hra se hraje obvykle v bludišti. Hráč hraje za žluté kolečko a jeho cílem je projít všechny políčka, to jest sežrat na každém políčku tečku. Proti hráči hraje jeden nebo několik duchů, kteří se mu snaží ve žraní teček zabránit. Jakmile ho chytí, hra končí neúspěchem. Když se hráči podaří sežrat všechny tečky, hra končí.

Existuje obrovské množství variant této hry, mnohé přidávají speciální předměty, průchozí tunely nebo políčka se speciálními funkcemi. Informace o historii a možnostech různých variant hry lze nalézt na wikipedii.

Cíl

Naším cílem bude implementovat jednoduchou variantu CDmana. Vytvoříme tedy nějakou hrací plochu, na které bude žluté kolečko pro hráče a duch jako nepřítel, který se ho bude snažit dostihnout. V okně bude ještě informace o tom, kolik teček bylo již sežráno a dvě tlačítka - jedno pro start hry nebo pozastavení a druhé pro ukončení programu.

Implementace

Základní program se bude skládat ze čtyř příkazů. Nejprve vykreslíme obrazovku a aktivujeme klávesy tak, že je svážeme s událostmi. Na tyto obě činnosti si vytvoříme vlastní podprogramy.

my $m = MainWindow->new();
$m->title("CDman");

&vykresli_obrazovku();
&aktivuj_klavesy();

Vykreslení prvků je rutinní záležitost a proto není třeba se ji tolik zabývat. Nejprve vytvoříme grafickou plochu Canvas, do které vykreslíme mřížku pomocí opakovaného volání createLine. Dále vytvoříme podle požadavků dvě tlačítka a ještě přidáme stavový řádek, ve kterém bude vidět, kolik teček již bylo sežráno.

Tečky je třeba vykreslit a protože je budeme časem postupně mazat, ponecháme si jejich id, které jim přiřadila grafická plocha.

Dále vytvoříme CD mana a ducha. CD man je v podstatě oblouk vyplněný žlutou barvou a proto můžeme použít metodu createArc. Ducha pomocí takto jednoduché grafiky nenakreslíme, ale musíme jej importovat z nějakého obrázku.

sub vykresli_obrazovku {
  $canvas = $m->Canvas(-width=>$SLOUPCU*$TLOUSTKA, -height=>$RADKU*$TLOUSTKA, -relief=>"ridge",
    -background=>"green", -border=>0)->pack();
  $t1 = $m->Button(-text => "Start", -command => \&start)->pack(-side=>"left");
  $l = $m->Label(-text => "Hotovo: 1/$CIL_HRY")->pack(-side=>"left");
  $t2 = $m->Button(-text => "Konec", -command => sub{exit})->pack(-side=>"right");

  #mrizka
  foreach my $i (0..$RADKU){
        $canvascreateLine(0, $i*$TLOUSTKA, $SLOUPCU*$TLOUSTKA, $i*$TLOUSTKA,-fill => "lightgreen");
    }
  foreach my $i (0..$SLOUPCU){
        $canvascreateLine($i*$TLOUSTKA, 0, $i*$TLOUSTKA, $RADKU*$TLOUSTKA, -fill => "lightgreen");
    }

  #tecky
  for(my $i=2;$i<=$SLOUPCU-1;$i++){
    for(my $j=2;$j<=$RADKU-1;$j++){
      $m[$i][$j]=$canvascreateArc(($i-0.6)*$TLOUSTKA, ($j-0.6)*$TLOUSTKA, ($i-0.4)*$TLOUSTKA,
        ($j-0.4)*$TLOUSTKA, -fill=>"red", -outline=>"red");
    }
  }

  #cdman
  $cdman=$canvascreateArc($TLOUSTKA*($x-1)+$SP, $TLOUSTKA*($y-1)+$SP, $x*$TLOUSTKA-$SP,
    $y*$TLOUSTKA-$SP, -start=>30, -extent=>300, -fill=>"yellow");

  #nepritel
  my $obrazek = $m->Photo(-file=>"Ghost.gif");
  $nepritel=$canvascreateImage($TLOUSTKA*($nepritelx-.5)+$SP, $TLOUSTKA*($nepritely-.5)+$SP,
    -image=>$obrazek);

  #okoli
  $canvascreateRectangle($TLOUSTKA/2, $TLOUSTKA/2, ($SLOUPCU-.5)*$TLOUSTKA, $TLOUSTKA*($RADKU-.5),
    -outline=>"darkgreen", -width=>$TLOUSTKA);
}

Použili jsme zde několik konstant, které je třeba nastavit na začátku programu. Zvolme je tedy například takto.

my $SLOUPCU=7;
my $RADKU=7;
my $TLOUSTKA=50;
my $KROK=0.1;
my $STARTX=2;
my $STARTY=2;
my $NEPRITELX=4;
my $NEPRITELY=5;
my $SP=2;
my $CIL_HRY=($SLOUPCU-2)*($RADKU-2);

Aktivace kláves spočívá ve volání metody bind. Vytvoříme 6 událostí - pro stisky šipek jako změnu směru CD mana a dále klávesy P pro pozastavení a s pro start hry.

sub aktivuj_klavesy{
  $m->bind("<Left>", \&doleva);
  $m->bind("<Right>", \&doprava);
  $m->bind("<Up>", \&nahoru);
  $m->bind("<Down>", \&dolu);
  $m->bind("<p>", \&pauza);
  $m->bind("<s>", \&start);
}

Nyní napišme čtyři metody použité pro změnu směru. Pokud uživatel stiskne nějakou kurzorovou klávesu, je třeba udělat dvě věci. Otočit CD mana příslušným směrem (tj. změnit vlastnosti oblouku) a dále si zapamatovat směr (to uděláme uložením do proměnné $smer).

sub doprava{
  $canvas->itemconfigure($cdman, -start=>30, -extent=>300);
  $smer="p";
}

sub doleva{
  $canvas->itemconfigure($cdman, -start=>210, -extent=>300);
  $smer="l";
}

sub nahoru{
  $canvas->itemconfigure($cdman, -start=>120, -extent=>300);
  $smer="n";
}

sub dolu{
  $canvas->itemconfigure($cdman, -start=>300, -extent=>300);
  $smer="d";
}

Dalšími podprogramy, na které jsme se odkazovali výše, jsou podprogramy pro obsluhu tlačítek.

Pokud uživatel klikne na start, spustíme časovač, který každý časový interval přednastavené délky obnoví obrazovku. Tím do aplikace dodáme pohyb, protože v podprogramu refresh můžeme periodicky manipulovat s objekty na grafické ploše.

sub start {
  $t1->configure(-text=>"Pauza", -command=>\&pauza);
  $timer=$canvas->->repeat($refresh, \&refresh);
}

Pokud uživatel pozastaví hru, volá se podprogram pauza. Ta zruší náš časovač, čímž hra ustrne.

sub pauza {
  $t1->configure(-text=>"Start", -command=>\&start);
  $timer->cancel;
}

Nyní je třeba dopsat hlavní část programu, kterou je podprogram refresh.

sub refresh{
  #pokud je blízko CD mana nějaká tečka, tak jí sežereme
  #zkontrolovat, zda nenastal konec hry
  #posunout CD mana o zadaný směr vpřed, pokud tedy nenarazil do překážky
  #posunout ducha směrem k CD manovi
}

Nejprve posuneme CD mana. Máme 4 možné směry. Každý z nich obsloužíme zvlášť. Cílem je posunout CD mana o daný krok, pokud již nenarazil do zdi. Řešením je například následující série podmínek.

  if($smer eq "p" and $x+$KROK<$SLOUPCU-1){
      $x+=$KROK;
      $canvas->move($cdman, $KROK*$TLOUSTKA, 0);
  }elsif($smer eq "l" and $x>2){
      $x-=$KROK;
      $canvas->move($cdman, -$KROK*$TLOUSTKA, 0);
  }elsif($smer eq "n" and $y>2){
      $y-=$KROK;
      $canvas->move($cdman, 0, -$KROK*$TLOUSTKA);
  }elsif($smer eq "d" and $y+$KROK<$RADKU-1){
      $y+=$KROK;
      $canvas->move($cdman, 0, $KROK*$TLOUSTKA);
  }

Pojďme nyní posunout ducha. Toho žádný uživatel neovládá, takže to musíme udělat sami. Porovnáme souřadnice CD mana a ducha a podle toho s ním pohneme.

Jsou (pro jednoduchost) dva možné směry, jak se může duch CD manovi přiblížit - buď vertikální nebo horizontální. My si jeden z nich vylosujeme.

  if(int(rand(2))==1){
    if($x>$nepritelx+.5){
      $nepritelx+=$KROK;
      $canvas->move($nepritel, $KROK*$TLOUSTKA*0.7, 0);
    }else{
      $nepritelx-=$KROK;
      $canvas->move($nepritel, -$KROK*$TLOUSTKA*0.7, 0);
    }
  }else{
    if($y>$nepritely+.5){
      $nepritely+=$KROK;
      $canvas->move($nepritel, 0, $KROK*$TLOUSTKA*0.7);
    }else{
      $nepritely-=$KROK;
      $canvas->move($nepritel, 0, -$KROK*$TLOUSTKA*0.7);
    }
  }

Ještě jsme se nepodívali na to, zda je v aktuálním okamžiku CD man na nějaké tečce, kterou by mohl sežrat. To uděláme tak, že spočítáme vzdálenost CD mana vzhledem ke každé z teček (pro jednoduchost) a pokud bude nějaká hodně blízko, tak ji smažeme.

Dále zde potřebujeme počítat, kolik teček jsme již sežrali. Pokud tedy sežereme nějakou tečku, uchováme si její souřadnice a počet sežraných teček zvýšíme o jednu.

Jakmile docílíme maximálního počtu sežraných teček, můžeme již zde ukončit hru.

  for(my $i=2;$i<=$SLOUPCU-1;$i++){
    for(my $j=2;$j<=$RADKU-1;$j++){
       if(sqrt(($i-$x)**2+($j-$y)**2)<1/3 and not (grep $_ eq "$i-$j", @sezrano)){
        push(@sezrano, "$i-$j");
        $canvas->delete($m[$i][$j]);
        $sezrano++;
        $l->configure(-text => "Hotovo: $sezrano/$CIL_HRY");
        &uspech if($sezrano==$CIL_HRY);
      }
    }
  }

Stejným způsobem jako u žraní teček zkontrolujeme, zda náhodou duch nesežere CD mana. Spočítáme tedy vzdálenost a pokud jsou oba objekty příliš blízko, ukončíme hru voláním podprogramu neuspech.

  if(sqrt(($x-$nepritelx-.5)**2+($y-$nepritely-.5)**2)<1/2){
    &neuspech;
  }

Nyní nám již zbývá pouze implementace podprogramů neuspech a uspech. Vytvoříme tedy vyskakovací okno, které se po zavolání těchto podprogramů objeví. Oznámíme tak výsledek hry. Tímto hra končí.

sub uspech {
  $timer->cancel;
  $t1->configure(-state=>"disabled");
  $m->messageBox(-message => "Hra dokoncena!", -type => "ok");
}

sub neuspech {
  $timer->cancel;
  $t1->configure(-state=>"disabled");
  $m->messageBox(-message => "Byl jsi sezran!", -type => "ok");
  $canvas->itemconfigure($cdman, -fill=>"black");
}

Závěr

Celou hru si můžete stáhnout v souborech cdman.pl a Ghost.png.

Nyní si hru můžeme obvyklým způsobem spustit. Zde je několik screenshotů.

Před zahájením hry *** V průběhu hry *** Po sežrání duchem

Jsou dvě možnosti, jak hra skončí. Buď prohrou nebo vítěztvím.

Prohra *** Vítězství

Tato varianta CD mana je velice jednoduchá a byla psána jen jako demonstrace PerlTk. Existuje řada návrhů na vylepšení. Mohli bychom pokračovat vytvořením bludiště. To už není tak jednoduché a bylo by to poměrně náročné na psaní kódu - potřebovali bychom vytvořit několik dalších objektů na grafické ploše, uchovat (například ve dvojrozměrném poli) pozice zdí a kontrolovat, zda se CD man pohybuje pouze v chodbách.

Dále bychom mohli vytvořit nějaké speciální objekty, které by CD man mohl sežrat a získat nové (ačkoliv třeba časově omezené) schopnosti - například se v mnoha variantách vyskytují v rozích speciální tečky, které umožňují CD manovi po několik sekund prohodit role s duchy a sežrat je.

Verze pro tisk

pridej.cz

 

DISKUZE

Nejsou žádné diskuzní příspěvky u dané položky.



Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

21.8.2014 7:09 /MaReK Olšavský
Mezi významné uživatele GNU/Linuxu patří i Evropská Vesmírná Agentura (ESA), která používá 390 serverů se SLES, ale openSUSE je zde „doma“ už delší dobu.
Přidat komentář

20.8.2014 7:02 /MaReK Olšavský
Lehký úvod pro nasazení Dockeru přinesl web Opensource.com. Autor vysvětlil nejen první kroky v nasazení Dockeru, ale i filosofii kontejnerů.
Přidat komentář

20.8.2014 7:02 /MaReK Olšavský
AMD se snaží konkurovat Intelu i na poli SSD disků, ohlásila Radeon R7 Series SSD (oznaření Radeon může mást, tentokrát nejde o GPU). SSD obsahuje MLC NAND čipy Toshiba A19, s kontrolerem Barefoot 3 M00 a základní verze (120 GB) se prodává za US$ 100.
Přidat komentář

19.8.2014 16:39 /Miloslav Ponkrác

C++ schválilo standard C++14.. Ještě je třeba dokončit editační práce na finální verzi dokumentů standardu.

Takže C++ bude mít velmi brzy 3 základní standardy: ISO C++98/03, ISO C++11 a ISO C++14. Všechny novější standardy jsou vzájemně výborně zpětně kompatibilní se staršími (až ne velice nepodstatné drobnosti), takže C++ programátor je může vnímat pouze jako vzájemné rozšiřování.


Přidat komentář

19.8.2014 7:53 /MaReK Olšavský
Rusko to evidentně myslí s odklonem od velkých dodavatelů software vážně. Přechod začalo ministerstvo zdravotnictví, jež nahrazuje produkty Microsoftu a Oracle řešeními na bázi GNU/Linuxu a PostgreSQL,
Přidat komentář

19.8.2014 7:53 /MaReK Olšavský
Nostalgie za původním vzhledem a chováním desktopu GNOME, které bylo uživatelsky mnohem lepší, vedla k vytvoření nového desktopu MATE. Ubuntu, jakožto nejpopulárnější distribuce a původně i „vlajková loď“ GNOME, má i fork s MATE, jenž se stane oficiální větví, čímž se zařadí po bok Kubuntu, Xubuntu a Lubuntu.
Přidat komentář

9.8.2014 14:32 /František Kučera
Programovací jazyk Java přináší ve své 8 verzi řadu zajímavých novinek a také rozšíření možností jazyka směrem k funkcionálnímu programování. Zejména lambda výrazům a funkčním rozhraní se věnuje autor úvodního článku Java 8: novinky jazyka na blogu Frantovo.cz.
Přidat komentář

7.8.2014 7:15 /MaReK Olšavský
Velká změna se dotkne vývoje Qt, jež bude oddělen od společnosti Digia do nové firmy. Zájem je čistě komerční, 85 % nákladů na vývoj nese Digia a nová společnost má zapracovat i na sjednocení stávajícího stavu, kdy Qt konkuruje samo sobě v komerční i open source verzi.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

19.8.2014 11:02 / Le-Ze
Python s Lighttpd

15.8.2014 3:12 / Miloslav Ponkrác
Re: Kdyby autoři BeoSu nebyli blbci

15.8.2014 3:01 / Miloslav Ponkrác
Re: WIFI ůprava paketů připojených zařízení

15.8.2014 2:56 / Miloslav Ponkrác
Re: Linus tedy střílí do unixové architektury

13.8.2014 18:58 / Aleš Hakl
Re: Linus tedy střílí do unixové architektury

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2014) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze | zákony online