Az idő kerekéhez kötve

Egyáltalában nem mindegy, hogy egy kalandjátékban miféle ütemhez igazítva telik-múlik az idő. A legegyszerűbb megoldás, különösen az egyszereplős kalandjátékokra leginkább jellemző, hogy mindig egy-egy sikeres parancs végrehajtása lépteti tovább az egész rendszert egyetlen időegységgel, mintha valamiféle, változékony hosszúságú órajelet adna neki ezzel. Ameddig gépelünk, a következő mondatunkat szerkesztjük, addig a játékban áll az idő – mihelyst azonban leütjük az ENTER-t (és be is írtunk neki valamit), egycsapásra mindenki öregebbé válik, mondjuk egy negyed órával. Tulajdonképpen nem is időhöz, hanem lépésszámhoz vannak szinkronizálva egy ilyen játék történései – pl. olyan időzítéseket alkalmaznak bennük, hogy – mondjuk egy kopogtatást követően – öt lépés múlva kinyitja nekünk az ajtót valaki. Tetszőleges ideig lehet töprengeni a pillanatnyi helyzet megoldása fölött, és hiába ugrik a nyakunkba egy vérszomjas démon, nyugodtan elmehetünk megvacsorázni, mielőtt végképp az arcunkra fagyna az az utolsó vigyor… A program belső számlálóit, amelyek az eljövendő események titkos előhírnökei, a végrehajtott utasítások csökkentik rendszeresen eggyel. És ez nagyon helyesen van így! Egy elsősorban képzeletre és gondolkodásra épülő játéknál ez egy ideális helyzet – tökéletesen megengedhető és elfogadható, hogy ki-ki a saját belső ritmusa szerint haladjon előre a feladatok megoldásában. (Hogy is nézne ki, ha egy gyakorlott gyors- és gépíró illetéktelen előnyre tenne szert a lassúkezűvel szemben…)

Csakhogy egy többszereplős kalandjátékban már egyszerűen tarthatatlanná válik ez az állapot. Ha a program mondjuk hat különböző játékos parancsait fogadja párhuzamosan, akik mind eltérő ritmus szerint gépelnek, akkor mégis melyikükhöz alkalmazkodjon a többi? Amikor az egyik semmit nem csinál, hanem csak karbatett kézzel és összeráncolt homlokkal bámulja a képernyőt, akkor is kötelessége a programnak, hogy pontosan a történések idejében haladéktalanul értesítse őt a másik lépéseiről, ha az éppen akkor halad el mellette, vagy ugyanazon a helyszínen tevékenykedik. Az efféle programokban eszerint nem tehetünk mást: valós idejű időzítéseket vagyunk kénytelenek alkalmazni bennük. Ez viszont maga után vonja, hogy a bevitel és kiírás funkcióját az eddigieknél sokkal élesebben el kell határolnunk egymástól – mert mi történjék, hogyha véletlenül éppen akkor érkezik valakihez egy fontos kiírandó üzenet, amikor ő saját mondata szerkesztésének a kellős közepénél tart; esetleg föl sem pillantva a képernyőre, keresi a megfelelő billentyűt? Nem lehet csak úgy otrombán kettévágni a félig begépelt mondatot, és a közepébe belenyomtatni a szöveget! (De lehet: a TELNET-es játékok sajnos pontosan ezt teszik…) Okvetlenül kétfelé kell bontanunk a képernyőt, úgy, hogy külön legyen egy felület a kiírás és szintén külön a bevitel számára (utóbbinak két-három sor is elég lesz). Így azok már nem zavarják egymást – vagy mégis?! Mit tehetünk akkor, ha a megjelenítés mezejében egy különösen hosszú leírás kezd el szépen, megfontoltan kibontakozni az ismeretlenség homályából, mialatt mi szorgosan a parancsunkat gépeljük? Bevett gyakorlat, hogyha egy szöveg hosszabb annál, mint amennyi a képernyőre egy adagban kifér, akkor oldalanként meg-megszakítva, minden oldal végén egy billentyű-lenyomásra várakozva fokozatosan léptetjük azt tovább (<More> vagy magyarul <Tovább> funkció). De még ha ez az eset nem is forog fenn, akkor is az ablak görgetése több másodpercig is eltarthat, és rendkívül illúzióromboló lenne, ha erre az időre hirtelen megakadna az alsó sorokban a bevitel. Másik probléma: mi van, ha a kiírás-ablakban egy félig megjelenített szöveg éppen ENTER-rel való továbbléptetésre vár, de mi nem törődünk vele, és zavartalanul csak a mondatunkra figyelünk – hol várakozzon addig a szöveg hátralevő része, és ha kiírás közben újabb üzenetek érkeznek, azokat miképpen várakoztassuk? Meg kell oldanunk tehát azt is, hogy a kétféle funkció ne csak térben, de időben is egymástól teljesen független és párhuzamos legyen: mialatt gépelünk, tényleg aközben folyjon odaát a kiírás! A még kiíratlan, de a küldőtől már átvett „szűz” szöveget pedig addig is egy átmeneti pufferban kell tárolnunk, ahol egy bizonyos határig gyűlhetnek és halmozódhatnak a sorok és a mondatok, de ha a puffer betelt, akkor haladéktalanul ki kell görgetnünk őket a képernyőre – akár tetszik a felhasználónak, akár nem. Különösen mókás tud lenni, amikor a szereplőt a játékban egy súlyos baleset érte, de ő még valahol tíz oldallal följebb tart a szövegek olvasásában, miközben a többiek már réges-régen értesültek róla, hogy ájultan hever a földön, és apránként kipakolják a hátizsákjából az értékesebb cuccokat…

Egyetlen megoldás létezik a legsimább párhuzamosság elérésére, az, ha a program központi, vezérlő része sohasem „ragad le” valamilyen szubrutinnál, hanem egy örökös végtelen ciklusban megállás nélkül kering három alapvető tevékenység: a beviteli mező szerkesztése, az események végrehajtása (beleértve természetesen a saját és a többiek által kiadott utasítások végrehajtásait is) és a szövegkiírás alapvető fázisai közt. Ehhez az szükséges, hogy valamennyi funkciót apró, szétválasztható és önállóan végrehajtható kis lépésekre tagoltan valósítsuk meg. A szövegkiírás esetében ilyen építőkocka lehet pl. az átmeneti puffer egyetlen sorának kiléptetése a képernyőablakba, vagy a beviteli rutin esetében egyetlen lenyomott billentyű beolvasása a billentyűzet-pufferből (ha van olyan), és annak megfelelően a beviteli mező módosítása. A program tehát úgy fog működni, hogy folyton figyeli, történnie kell-e valamilyen eseménynek, s ha igen, akkor végrehajtja azt, és a neki megfelelő szöveget a puffer alsó végéhez hozzácsapja (ez egyetlen szemvillanás alatt megvan); majd rögtön továbbadja a vezérlést a kiíró rutinnak, amelyik a szövegpuffer legfelső sorát kigörgeti a képre (hacsak nem üres a puffer éppen akkor); ezt követően a beviteli szubrutin lép színre, mely pedig egyetlen karaktert beolvas, ha képes; végezetül pedig vissza az elejére, és ez így megy tovább megállás nélkül… Nem kis feladat elérni, hogy ez az egész így egyben kellőképp összehangoltan fusson – különösen, hogyha grafikus képernyőt használunk a megjelenítéshez, ami már eleve alaposan lelassítja a kiírásokat. (Ajánlott az ASSEMBLY nyelv használata például.)

Többek között emiatt is számít, hogy mind az értelmező szubrutin, mind pedig a program más egyéb végrehajtó eljárásai igen-igen serényen végezzék a dolgukat – mert miért ne fordulhatna elő, hogy húsz különböző játékos egyszerre adja ki, egyenként hatszáz betűből és harminc parancsból álló mondatait? Amiből mindjárt egy másik szempont is következik, nevezetesen hogy az egyes játékosok teendőit is hasonló pufferokban kell előzetesen nyilvántartani – elvégre mindnyájan kiadhatnak több parancsból álló mondatokat is, amiből egyelőre még csak az első vagy a második hajtódik végre, amelyeket addig is tárolni kell valahol, de ő gonosz mosollyal az ajkán tüstént begépeli máris a következő adagot, és lehet, hogy ezt egyszerre akár többen is megteszik…

És ne gondoljuk azt sem, hogy mindezek a szörnyűségek kizárólag hálózatos kalandjátékokban fordulhatnak elő! Ha egy olyan kalandot készítünk, amiben ugyanazt az egyetlen számítógépet használó játékos több szereplőt is irányíthat egymással párhuzamosan, mondjuk ESC-pel vagy TAB-bal kapcsolgatva az egyik vagy a másik között (esetleg osztott képernyőn megjelenítve egymás mellett egyidejűleg akár többet is), miközben valós idejű megjelenítést alkalmaztunk benne, az pontosan ugyanakkora galibákat teremthet, mintha ezren küldözgetnék az utasításaikat a komputernek egyszerre! De megéri a belefektetett munkát a dolog, mert rendkívül látványos lesz a végeredmény.

Ezáltal tehát elértük, hogy – elméletileg – akárhány játékos ténykedését le tudjuk kezelni egyidejűleg, miközben sem a végrehajtás, sem a folyamatosan a háttérben zajló szövegkiírás nem zavarja egymást, és főképpen pedig a bevitel mindeközben zökkenőmentes marad. De nyitva maradt még egy probléma: a különböző játékosok különböző sebessége. Ha valaki gépír, mint a villám, annak a parancsai is fokozott ütemben hajtódnak végre, amire még ráfoghatjuk, hogy megérdemli ezt a kis előnyt, még ha a többiek nemhogy reagálni rá, de még csak figyelemmel követni se nagyon bírják közben; de ha egy több parancsból álló mondatot írt be valaki – erre ugyebár egy lassúbb illető is képes –, akkor már igazán tisztességtelenül manőverező vágtázásba kezdenek az utasításai – ennek egymást követő lépéseit a program mindenfajta késleltetés nélkül, teljesen egybefolyva, mondhatni szinte egyszerre vágja a többiek képébe. Fokozott mértékben áll ez a számítógép által irányított szereplőkre (ún. NPC-k: ez a „Non Player Character” – „nem játékos szereplő” – angol nyelvű kifejezés rövidítése): őnáluk tudniillik abszolúte semmiféle gépírásról nincsen szó – az illető fickó cselekvési szándékai a másodperc törtrésze alatt alakulnak ki egy külön e célra berendezett „műhelyben”. Ennek eredményeképpen aztán ezek olyan követhetetlen ámokfutásba kezdenek, hogy szinte látni se nagyon fogják őket a többiek, amint nagyritkán föltünedeznek egy-két tizedmásodpercre itt-ott… A megoldás kézenfekvő: minden egyes élőlénynek – függetlenül attól, valódi-e vagy NPC – osszunk ki valamilyen maximális sebességértéket, amivel haladhat. Ez pl. úgy néz ki, hogy mindenkihez tartozik egy-egy számláló, melyeket bizonyos időközönként csökkentünk, s ha nullára csökkent, akkor következik lépésre az az illető. Ezeket egytől néhány másodpercig terjedő tartamokra célszerű beállítani, miáltal mindenkinek személyre szabott sebessége lehet – bizonyos játékosokat vagy NPC-ket tetszőlegesen fölgyorsíthatunk vagy lelassíthatunk, amivel a helyzetek nehézségét is lehet némiképpen állítani. Az említett értékeket akár dinamikusan is változtathatjuk: pl. minél jobban meg van pakolva súlyos tárgyakkal valaki vagy minél fáradtabb és kimerültebb, annál jobban lelassul a mozgása stb.


Következő: „Néhány jótanács és további lehetőségek”

 

 

A kalandjáték fogalmának tisztázása

Kalandjáték és mitológia

A számítógép beszélni tanul

A szavaktól a mondatok felé

Helyiségek összefüggő labirintusa

Barangolás a térképen

Lakberendezővé változunk

Hogyan találjunk meg valamit

„Sokasodjatok és növekedjetek”

Az idő kerekéhez kötve

Néhány jótanács és további lehetőségek

A program működésének leírása

Használati útmutató