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

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ů

24.10.2014 7:33 /MaReK Olšavský
Vyšlo Ubuntu 14.10 a spiny s dalšími desktopy Kubuntu 14.10, Xubuntu 14.10 a poprvé i Ubuntu-Mate (Lubuntu 14.10 bude opožděno). Změn je poměrně málo, nestihli zařadit aktuální GNOME a je bez convergence části.
Přidat komentář

24.10.2014 7:33 /MaReK Olšavský
Přípravy na vydání Debianu 8 jsou v plném proudu a nejednoho potenciálního uživatele by mohla zajímat připravovaná podpora multimédií pro novou verzi (jinak dosti konzervativní distribuce). Asi nebude potřeba používat obskurdní repozitáře kvůli podpoře přehrávání audia/videa a hudebníky nejspíše také potěší.
Přidat komentář

23.10.2014 7:13 /MaReK Olšavský
CERN používá OpenStack přibližně rok. Jaké je aktuální používání při výzkumu ukazuje článek na OpenSource.com. Vyprodukovaných dat, z měření, není malé množství a pro jejich zpracování je potřebný výkon několikatisíců serverů a pracovních stanic.
Přidat komentář

23.10.2014 7:13 /MaReK Olšavský
Prodejce starších her; jež jsou často hratelnější, než moderní grafické orgie; Good Old Games dosáhl milníku 100 her připravených pro Linux (nejde o portace, ale připravené konfigurace DOSBoxu/Wine).
Přidat komentář

23.10.2014 7:13 /MaReK Olšavský
O malou reklamu pro Ubuntu se postaral Andy Swan, se svým laptopem, při analýze počasí pro tragickou Velkou Cenu Japonska 2014 (Formule 1).
Přidat komentář

22.10.2014 7:19 /MaReK Olšavský
Programovacímu jazyku Swift, jenž nedávno zveřejnil Apple a je uzavřený, vzniká svobodná odpověď Phoenix (repozitář). Jazyk bude stejný, takže lze očekávat, že se Apple bude bránit i soudně. Název Phoenix už nejspíše také někdo používá, starší pamatují, že se tak chvíli jmenoval dnešní Mozilla Firefox.
Přidat komentář

22.10.2014 7:19 /MaReK Olšavský
Programátorům v PHP je určen nástroj RIPS, který jim pomůže odhalit zranitelnosti v jejich kódu. Pokud znáte další nástroje, podělte se o ně v diskusi.
Přidat komentář

22.10.2014 7:18 /MaReK Olšavský
HDMI sticků, které povyšují možnosti TV, je na trhu nepřeberné množství, ale Apec Electronics se nepokouší zaujmout nejlevnější cenou. Za US$ 110 dostanete Android běžící na 4 jádrovém Atomu (takže platformu x86), přičemž místo Androidu lze pořídit verzi s MS Windows 8.1.
Přidat komentář

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

> Poslední diskuze

16.10.2014 7:56 / Leo
Sanba

13.10.2014 7:20 / MaReK Olšavský
Re: PDF a podpis

10.10.2014 8:01 / Hynek Beran
PDF a podpis

10.10.2014 7:41 / Dusan Hlavac
Re: Takže nic.

10.10.2014 6:36 / MaReK Olšavský
Re: Může, ale nemusí

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