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

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ů

19.12.2014 7:20 /MaReK Olšavský
Předvánoční dárek pro databázaře vyšel v podobě PostgreSQL 9.4. O novinkách napsal český článek Pavel Stěhule. Opravy chyb a drobná vylepšení jsou standardem, podpora datového typu JSON je velkým skokem vpřed.
Přidat komentář

19.12.2014 7:20 /MaReK Olšavský
Zdá se, že by se Intel mohl přecijen uchytit; vedle ARM; v segmentu chytrých telefonů. Čínské Lenovo plánuje pro rok 2015 nasazení Intelovského Atomu v nových smrtphonech.
Přidat komentář

19.12.2014 7:20 /MaReK Olšavský
Jazzový zpěvačka/pianistka Dinah Washington propůjčila jméno CMS Wordpress 4.1, jehož nejvýraznější novinkou je mód pro „nerušené psaní“.
Přidat komentář

18.12.2014 7:00 /MaReK Olšavský
Porovnání FreeBSD a OpenBSD (delší článek) vyšlo na blogu Network Filter. Asi nikoho nepřekvapí, že nelze jednoznačně určit vítěze a jednoznačné doporučení „nasaďte XYZ“.
Přidat komentář

18.12.2014 7:00 /MaReK Olšavský
Snad již poslední novinkou o vydání distribuce Fedora 21 jsou verze pro 64 bitové mikroprocesory ARM (oznámení) a pro mikroprocesory Power (oznámení). Obě verze budou mít asi poměrně malou cílovou skupinu ve správcích serverů. BTW: OpenPOWER Foundation se rozrostla o Rackspace.
Přidat komentář

18.12.2014 7:00 /MaReK Olšavský
Vznik další distribuce často komentuji slovy „kdybyste měli pocit, že distribucí je málo“, ale podle dlouhodobého sledování stránek DistroWatch naopak počet distribucí klesá. Lze to vnímat jako pozitivní jev, kdy se vývojáři spojují, místo vytváření bezpočtu derivátů.
Přidat komentář

17.12.2014 7:19 /MaReK Olšavský
Martin Malý napsal článek pro (nás) pamětníky o počítačích za železnou oponou. Zatím zvládl podchytit stav pouze někdejšího Česko—Slovenska :-).
Přidat komentář

17.12.2014 7:19 /MaReK Olšavský
National Geographic je známý svými populárně naučnými TV stanicemi, nebo vydáváním časopisu. Jak používá svobodný software prozradil Shah Selbe.
Přidat komentář

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

> Poslední diskuze

16.12.2014 3:59 / Jaroslav Kelt Kuchera
Download Perl

11.12.2014 6:42 / MaReK Olšavský
Po instalaci

10.12.2014 19:26 / Vladimir VASIL
Re: Sanba

11.11.2014 14:24 / Libor Suchý
Nekonečný while cyklus

10.11.2014 19:09 / Libor Suchý
Re: tabulka - bitovy sucet

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