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 4846×

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ů

18.9.2014 7:07 /MaReK Olšavský
Uživatelé RHELu 5.x by už opravdu měli migrovat na novou řadu, RH oznámil vydání RHEL 5.11, jenž je poslední velkou aktualizací distribuce.
Přidat komentář

18.9.2014 7:07 /MaReK Olšavský
Firma Longmont připravila další SBC s mikroprocesorem AllWinner A20, jež by mohla udělat radost těm, kteří sní o malém, úsporném, domácím/vývojovém serveru. Vedle SATA konektoru pro standardní HDD disponuje i 1 Gbps konektivitou.
Přidat komentář

17.9.2014 14:44 /MaReK Olšavský
SAP otevřel svou jQuery UI knihovnu OpenUI5 (kódové jméno „Phoenix“) pod licencí Apache 2.0. Nadstavbě jQuery UI přibyl silný konkurent.
Přidat komentář

17.9.2014 7:29 /MaReK Olšavský
Vyšel Minix 3.3.0, pro uživatele GNU/Linxu důležitý tím, že právě na Minixu začal vývoj jádra Linux. Mezi zajímavými novinkami je podpora architektury ARM Cortex-A8 (třeba BeagleBoard/BeagleBone), nebo vylepšená kompatibilita s aplikacemi z NetBSD, ale zatím není dostupný X11 server. Najde své uživatele?
Přidat komentář

17.9.2014 7:29 /MaReK Olšavský
Vývojáři Mozilly pracující na novém programovacím jazyku Rust mají plán pro verzi 1.0 i pro kroky následující. Asi se blíží vydání první „finální“ verze.
Přidat komentář

17.9.2014 7:29 /MaReK Olšavský
oddělení „The Qt Company“ do samostatné firmy, plně vlastněné mateřskou Digií, píše LinuxGizmos. Vývoj Qt změnil několik vlastníků, za poslední roky, a uvedl i nové produkty za příznivější cenu.
Přidat komentář

16.9.2014 5:08 /MaReK Olšavský
VESA uvolnila technický standard DisplayPort 1.3. DP 1.3 má šířku pásma 32,1 Gb/s, což je dostatečný tok na 5k display při frekvenci 60 Hz. Technicky by se mohlo HDMI, populární především u spotřební elektroniky, stát historickou kapitolou (DP není zatížen licenčními poplatky).
Přidat komentář

16.9.2014 5:08 /MaReK Olšavský
SUSE (a další značky včetně Novellu) mají zase jiného majitele, Attachmate byla koupena společností Micro Focus za US$ 2,3 mld. Micro Focus se dosud věnoval enteprise sféře a nástroji Visual COBOL.
Přidat komentář

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

> Poslední diskuze

16.9.2014 3:49 / MaReK Olšavský
Re: Těžko

15.9.2014 14:35 / Petr Ježek
Těžko

14.9.2014 11:04 / Petr Ježek
DE, ne WM

12.9.2014 12:09 / Thomas Jones
Great

9.9.2014 15:58 / František Kučera
Re: Díky za článek

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