Programování pro hračičky/Andělé/Lekce 3: Porovnání verzí

Z Wikiverzity
Smazaný obsah Přidaný obsah
Řádek 93: Řádek 93:
Jakmile jsme zvládli udělat prvních pár virtuálních detailů, můžeme se se získanými zkušenostmi vrhnout do klonování skutečných programátorských objektů. I ty budeme vkládat do místností (což je, podobně jako u virtuálních detailů, zdaleka nejčastější způsob jejich použití).
Jakmile jsme zvládli udělat prvních pár virtuálních detailů, můžeme se se získanými zkušenostmi vrhnout do klonování skutečných programátorských objektů. I ty budeme vkládat do místností (což je, podobně jako u virtuálních detailů, zdaleka nejčastější způsob jejich použití).


Nejprve si ve složce <code>/obj</code> a v jejích podsložkách vybereme, který z již předpřipravených objektů chceme použít. Pak si ze svých místností zvolíme tu, do které má být objekt umístěn.
Nejprve si ve složce <code>/obj</code> a v jejích podsložkách vybereme, který z již předpřipravených objektů chceme použít (pro následující příklad předpokládejme, že se rozhodneme pro batoh). Pak si ze svých místností zvolíme tu, do které má být objekt umístěn. S touto místností pak bude dotyčný objekt spjat jako s objektem, který jej vytvořil a do kterého byl počátečně umístěn.


V programu místnosti nyní provedeme několik úprav. Především někde v úvodu souboru (ale až za různá <code>inherit</code> a <code>#include</code>) deklarujeme proměnnou typu objekt, která bude odkazovat na vytvářený objekt. Tuto proměnnou bychom mohli nazvat klidně <code>Franta</code> nebo <code>x3356762</code>, ale je dobrým zvykem nazývat věci tak, aby byly podle názvu rozpoznatelné, tedy ji nazvěme třeba <code>batoh</code>:
...

<source lang="c" >
object batoh;
</source>

Od této řádky dále pak můžeme v programu místnosti používat proměnnou <code>batoh</code> a ukládat do ní odkazy na objekty.

Jako další úpravu vložíme do programu místnosti novou funkci <code>reset()</code>. Funkce tohoto jména se u objektů, které se právě nacházejí ve hře, volá automaticky přibližně jednou za 40 minut, a slouží k tomu, aby se tyto objekty mohly vždy znovu uvést do nějakého kýženého základního stavu. Základním stavem naší místnosti ovšem bude, aby obsahovala batoh, a proto, pokud objekt <code>batoh</code> neexistuje nebo už není v místnosti přítomen, naklonujeme nový batoh z <code>/obj/batoh.c</code> a přemístíme ho do této místnosti:


<source lang="c" >
<source lang="c" >
Řádek 107: Řádek 115:
}
}
</source>
</source>

Tato funkce <code>reset()</code> se musí nacházet ''za'' deklarací proměnné <code>batoh</code> (protože v ní tuto proměnnou používáme) a ''před'' funkcí <code>create()</code>.


...
...

Verze z 31. 10. 2012, 00:25

Tato stránka není ještě hotová.

Opakování a probrání domácího úkolu

Projděme si místnosti, které jsme kdo vytvořili (zejména máme-li něco, co bychom rádi ukázali ostatním).

Podívejme se, jaký herní předmět hodlá kdo vytvořit. (Dnes se do tohoto tvoření dáme.)

Základní programátorské rozlišení objektů

Objekty, s nimiž se setkáváme ve hře, mohou být trojího základního druhu: Mohou to být jednak jedinečné objekty, které se dále neklonují a ve hře proto vystupuje přímo jejich prototyp, jednak klonované objekty, jejichž prototyp zůstává mimo hru, zatímco ve hře se vyskytují jeho klony, jednak virtuální objekty, které se hráčům jako objekty jeví, ale z programátorského hlediska nejsou objekty, nýbrž víceméně jen soubory hlášek, jimiž se má reagovat na určité hráčské příkazy.

Jedinečné objekty

Některé objekty se ve hře z logiky věcí mají vyskytovat jen jednou a jsou natolik složité, že se vyplatí mít jejich program uložen ve zvláštním souboru. Týká se to jednak všech místností, které nejsou generovány automaticky podle map (například celý Dům, a za prvním Prahem téměř všechny místnosti ve městech, mimořádná zákoutí atd.), jednak nehráčských postav majících nějakou osobnost (například Josef nebo Lída, které můžeme potkat hned na začátku hry), jednak předmětů nadaných mimořádnými možnostmi, jejichž častější výskyt ve hře by mohl dost změnit její náladu (například buřič trempů Kundrápa a Žahoura, který může být velmi mocnou zbraní). K těmto objektům vystupujícím přímo ve hře pak můžeme připočítat též objekty, které nějakou část hry spravují nebo koordinují, aniž by byly pro hráče přímo viditelné (tzv. mastery neboli řídicí objekty, například řídicí objekt počasí pro tu či onu doménu, řídicí objekt legionářských hlídek v Oikúmené atd.).

Takovéto objekty jsou pak přímým obrazem svého programového souboru, který se načte do paměti buď v rámci programu funkcí touch(), nebo ve hře andělským příkazem probudiž. Tím vznikne prototyp, ze kterého se ovšem už nevyrábějí žádné další klony, nýbrž který sám účinkuje ve hře.

Aby byly jedinečné objekty odlišeny od klonovatelných, umisťujeme je v mudové knihovně zpravidla do podsložek touch (v hráčské oblasti tedy třeba /d/oikumene/jeruzalem/touch, ve vlastní programátorské složce třeba /w/mojejmeno/touch nebo /w/mojejmeno/bludiste/touch).

Klonované objekty

Jiné objekty se ve hře vyskytují opakovaně. Typicky jsou to běžné předměty (batoh, pochodeň, meč), ale také druhové bytosti (vlk, skřet, hlídkující legionář) a mapové místnosti (tedy například jednotlivé vzájemně podobné místnosti v určité krajině). Takovéto objekty pak mají společný programový soubor a z něho vytvořený prototyp, který ovšem sám ve hře nevystupuje, nýbrž se z něho vždy nejprve vyrobí klon, který se pak přemístí jako objekt do hry.

Klon objektu vyrobíme v rámci programu funkcí clone_object(), ve hře pak andělským příkazem budiž. Jedná se vlastně o paměťovou kopii všech proměnných, v nichž jsou uloženy vlastnosti objektu, zatímco metody objektu jsou zapsány jedinečně v prototypu. Z toho plyne, že vlastnosti jednotlivého naklonovaného objektu můžeme po naklonování nadále měnit, zatímco množina použitelných metod je pevně dána společným prototypem.

Aby se klonovatelné objekty nepletly s jinými, ukládáme jejich soubory buď do složky /obj a jejích podsložek (jako třeba /obj/nabytek nebo /obj/voda), nebo do podsložek obj v příslušné části hry (například /d/stredozeme/moria/obj) nebo ve vlastním programátorském adresáři (například /w/mojejmeno/obj).

Virtuální objekty

Některé objekty se vyskytují ve hře jen jako doplňky či detaily jiných objektů a jsou na tyto jiné objekty pevně vázané. Typicky se jedná součásti popisu místností, které je možno si zvlášť prohlédnout (stěny, strop, nebe, tráva), méně často o popisové detaily na předmětech (cenovka na svetru, držadlo u kbelíku) nebo na nehráčských postavách (vlasy, zuby).

Takovéto herní objekty pak z programátorského hlediska nejsou objekty, nýbrž jen v jiných objektech uložené seznamy základních vlastností a hlášek, které se projeví při jejich prohlížení či jiných základních úkonech. Chceme-li o takovýchto objektech-neobjektech mluvit, používáme označení virtuální objekty nebo virtuální detaily, nebo podle angličtiny vzniklé zkratky v-items.

Virtuální objekt tedy nemá žádný svůj soubor na disku ani prototyp v paměti, ale je uložen jako obsah nějaké proměnné v jiném objektu. Můžeme si už říci, že se jedná o proměnnou typu mapping, tedy tzv. asociativní pole, i když přesné vysvětlení tohoto pojmu si necháme na později.

Používáme virtuální objekty

Ze tří zmíněných druhů objektů už jsme programovali objekty jedinečné, když jsme vytvářeli první vlastní místnost, ovšem zatím to bylo spíše jen drobné předělávání podle hotového vzoru. Pro samostatnou tvorbu začneme virtuálními objekty.

Virtuální objekt můžeme přidat do jakéhokoli objektu, ale nejjednodušší bude začít jejich přidáváním do místností. (Ve své andělské pracovně máme ostatně ohnivá písmena, která jsou takovým přidaným objektem, takže i nyní se budeme moci opřít o určitý vzor.) Zvolme si tedy místnost, do níž chceme nějaký virtuální objekt přidat, a otevřme si její soubor.

Protože Prahy se odehrávají v češtině, budeme při vytváření objektů muset dbát též na správné skloňování jejich jmen. K tomu potřebujeme někde v úvodu souboru mít vloženu řádku:

#include <sklon.h>

Pokud jsme dotyčnou místnost vytvořili okopírováním workroom.c a následným předěláním, pak takovou řádku nejspíše někde na začátku souboru už máme. Pokud ne, tak ji vložíme buď na úplný začátek, nebo za rovněž někde na začátku se nacházející řádky, které začínají slovem nebo obsahují slovo inherit (o těch budeme také podrobně mluvit až později).

Do těla funkce create(), která se automaticky spouští při vytvoření objektu (v případě jednotlivé místnosti při jejím načtení do paměti), vložíme nyní volání funkce add_v_item(), jejímž jediným parametrem bude asociativní pole popisující virtuální objekt. Za vzor si můžeme vzít třeba poháry z Horepovy krčmy:

void create()
{
  ...
  add_v_item(([
    "name":"pohár",
    "plural":CISLO_MN,
    "gender":ROD_MI,
    "vzor":VZOR_STAN,
    "id":({"pohár","pohár","číše","číše","sklenice","sklenice"}),
    "vzor_id":({VZOR_STAN,VZOR_STAN,VZOR_NUSE,VZOR_NUSE,
      VZOR_ULICE,VZOR_ULICE}),
    "plural_id":({CISLO_J,CISLO_MN,CISLO_J,CISLO_MN,CISLO_J,CISLO_MN}),
    "long":"Poháry, kterých se v této krčmě užívá, jsou zhotoveny ze skla, "
      "zajímavého materiálu, oblíbeného právě v Egyptě. "
      "Mají jednoduchý válcový tvar a dole zesílenou podstavu.",
    "smell":"Přes všepronikající vůni egyptského dýmu cítíš z použitých "
      "pohárů vůně nápojů, které v nich ještě před chvilkou byly.",
  ]));
  ...
}

Identifikátory psané velkými písmeny jsou konstanty definované v souboru /sys/sklon.h, který jsme načetli oním řádkem #include <sklon.h>. Jsou to vlastně interní čísla různých rodů, čísel a vzorů, ale protože s čísly by se pracovalo podstatně hůř, jsou takto nahrazena aspoň přibližně zapamatovatelnými slovy. ROD_F, ROD_MA, ROD_MI, ROD_N znamenají po řadě rod ženský, mužský životný, mužský neživotný a střední, CISLO_J, CISLO_MN, CISLO_POMN, CISLO_HROM číslo jednotné, číslo množné, jméno pomnožné a jméno hromadné, identifikátory začínající na VZOR_ znamenají jednotlivé skloňovací vzory. Protože skloňovacích vzorů je v češtině ve skutečnosti mnohem více, než se běžně učí ve škole (například slova „hrad“, „stan“ a „padák“ se všechna řadí ke školskému vzoru „hrad“, ale při skloňování se v některých pádech liší), budeme se muset občas kouknout buď do souboru /sys/sklon.h (jde to například ze hry andělským příkazem more /sys/sklon.h), nebo si postupně zapamatovat možné vzory při zacházení s již hotovými virtuálními objekty.

Jednotlivé položky asociativního pole pak nastavují jednotlivé vlastnosti virtuálního objektu. Poměrně jasný nám je asi význam položek "long" a "smell" (obdobně bychom mohli definovat ještě položky "noise", "feel" a řadu dalších, které najdeme popsány v Podprahové encyklopedii v sekci Jak to funguje, podsekci Virtuální detaily). Položka "name" definuje, pod jakým hlavním jménem bude objekt vystupovat, tedy pod jakým se bude třeba objevovat v hláškách typu „Michael si prohlíží poháry.“ (jméno píšeme malými písmeny, případné velké písmeno u jmen vlastních řešíme jinak), "gender", "plural" a "vzor" udávají, jak se bude toto jméno skloňovat. Mohli bychom definovat ještě "adjektiv" pro přívlastek shodný a "attribut" pro přívlastek neshodný:

    "adjektiv":({"použitý","skleněný"}),
    "attribut":"na pultě",

Takové nastavení by pak způsobilo, že výše uvedená hláška by měla podobu „Michael si prohlíží použité skleněné poháry na pultě.“

Položky "id", "vzor_id" a "plural_id" definují, pod jakými jinými jmény může hráč na daný předmět odkazovat, přičemž jednotlivé položky všech tří seznamů (či přesněji tzv. polí) k sobě patří. V daném případě je nastaveno, že hráč si může prohlížet „poháry“, „pohár“, „číše“, „číši“, „sklenice“ i „sklenici“ (zopakované „poháry“ v množném čísle ve skutečnosti nejsou zapotřebí, protože ty zajišťuje už položka "name", ale pro některého programátora může být takovéto zopakování přehlednější a praktičtější pro případ, že by se najednou rozhodl nastavit jako hlavní jméno místo "pohár" třeba "číše"). Pokud jsou nastaveny položky "adjektiv" a "attribut", je možno je používat i se všemi těmito vedlejšími identifikátory (tedy třeba „prohlédni si použitou sklenici“). Kromě toho je možno nastavit další použitelná přídavná jména položkou "plus_adjektiv".

Podle tohoto vzoru můžeme nyní všechny své místnosti ozdobit spoustou virtuálních detailů. Při tom nejspíše narazíme na různé nejasnosti a problémy, které pak můžeme řešit ve hře s ostatními anděly, nebo na diskusní stránce této lekce nebo letošního kurzu.

Klonování objektů v místnostech

Jakmile jsme zvládli udělat prvních pár virtuálních detailů, můžeme se se získanými zkušenostmi vrhnout do klonování skutečných programátorských objektů. I ty budeme vkládat do místností (což je, podobně jako u virtuálních detailů, zdaleka nejčastější způsob jejich použití).

Nejprve si ve složce /obj a v jejích podsložkách vybereme, který z již předpřipravených objektů chceme použít (pro následující příklad předpokládejme, že se rozhodneme pro batoh). Pak si ze svých místností zvolíme tu, do které má být objekt umístěn. S touto místností pak bude dotyčný objekt spjat jako s objektem, který jej vytvořil a do kterého byl počátečně umístěn.

V programu místnosti nyní provedeme několik úprav. Především někde v úvodu souboru (ale až za různá inherit a #include) deklarujeme proměnnou typu objekt, která bude odkazovat na vytvářený objekt. Tuto proměnnou bychom mohli nazvat klidně Franta nebo x3356762, ale je dobrým zvykem nazývat věci tak, aby byly podle názvu rozpoznatelné, tedy ji nazvěme třeba batoh:

object batoh;

Od této řádky dále pak můžeme v programu místnosti používat proměnnou batoh a ukládat do ní odkazy na objekty.

Jako další úpravu vložíme do programu místnosti novou funkci reset(). Funkce tohoto jména se u objektů, které se právě nacházejí ve hře, volá automaticky přibližně jednou za 40 minut, a slouží k tomu, aby se tyto objekty mohly vždy znovu uvést do nějakého kýženého základního stavu. Základním stavem naší místnosti ovšem bude, aby obsahovala batoh, a proto, pokud objekt batoh neexistuje nebo už není v místnosti přítomen, naklonujeme nový batoh z /obj/batoh.c a přemístíme ho do této místnosti:

void reset()
{
  if (!batoh || !present(batoh))
    {
      batoh=clone_object("/obj/batoh");
      batoh->move(this_object());
    }
}

Tato funkce reset() se musí nacházet za deklarací proměnné batoh (protože v ní tuto proměnnou používáme) a před funkcí create().

...


Do funkce create() pak přidáme zavolání této funkce reset(), aby se objekt vytvořil hned při vytvoření místnosti:

void create()
{
  ...
  reset();
}

...

void reset()
{
  if (!stud)
    {
      stud=clone_object("/obj/voda/studna");
      stud->set_name("kašna");
      stud->set_gender(ROD_F);
      stud->set_vzor(VZOR_PANNA);
      stud->add_id(({"skruž","sloupek","socha","nymfa","víla","džbán",
          "ornament","ornament"}),
        ({VZOR_JABLON,VZOR_STOLEK,VZOR_ZENA,VZOR_ZENA,VZOR_ZENA,VZOR_HRAD,
          VZOR_STAN,VZOR_STAN}),
        ({CISLO_J,CISLO_J,CISLO_J,CISLO_J,CISLO_J,CISLO_J,
          CISLO_J,CISLO_MN}));
      stud->set_adjektiv("kamenný");
      stud->set_long("Kašna, kterou vidíš před sebou, sestává z velké "
        "kamenné skruže, uprostřed níž se tyčí právětak kamenný sloupek, "
        "nesoucí sochu nymfy, tedy vodní víly. Víla drží v rukou veliký "
        "džbán, z něhož vytéká voda a naplňuje kašnu. Sloupek i skruž "
        "jsou zdobeny tesanými ornamenty.");
      stud->move(this_object());
    }
}


...

Práce na vlastním objektu

...

Pomocné stránky