Thursday, 30 July 2020

Játékfejlesztésem története


Játékfejlesztésem története

Az Emberkétől a Hungry Creature-ig

A 80-as évek vége felé írtam első „játékprogramomat”, amely az Emberke volt. A program négyszög alakú karaktereket véletlenszerűen szétszórt a képernyőn, az emberke alakú karaktert pedig a belső botkormánnyal lehetett mozgatni. Egy percünk volt, hogy minél több négyszöget összeszedjünk. A program még a négyszöggel való ütközést sem érzékelte, és ha kimentünk a játéktérből, hibaüzenettel leállt. De azért így is jól el lehetett szórakozni vele. Egy picit mindig szépítettem rajta, így idővel lett Emberke 10 is. Később nagyon megörültem, hogy a Hetedhéten túl című Enterprise-os könyvben a Hamikában volt ütközésérzékelés, így onnan el tudtam lopni a GET #102:A$ elvét, ami lekérdezi a kurzor pozíciójában lévő karaktert. Így már számolta az összegyűjtött négyszögeket, és a játéktér körül keretkarakterek (ez a szó visszafele olvasva is ugyanúgy van!) is voltak, a játéktéren belül pedig falak.
Hála a Zzzip-nek, rájöttem, hogy ebből még többet is ki lehet hozni, így megjelentek a pályán a szörnyek is. Innen egy kicsit komolyabbra fordult a programozás. A játék pályáit DATA sorokban tároltam. Hogy gyorsabb legyen, azt találtam ki, hogy a pálya kirajzolása után a program a képernyő tartalmát, az összes karaktert a képernyőről végignézi, és beolvassa egy tömbbe (a KEP$(X,Y) tömbbe), így a pálya falai abban a tömbben voltak benne. A szörnyek így nem a képernyőről olvasták ki, hogy hol van fal és merre lehet menni, hanem a tömbből, ez gyorsabb volt. Így csak azt kellett a képernyőről kiolvasni, hogy az emberkénk hova lép, szóközre, bogyóra, netalán a szörny karakterére.
Addig még csak-csak elvoltam a PRINT #102,AT utasítással, a GET #102:A$-gel, a JOY és az RND függvénnyel, viszont a szörnyek mozgása kicsit más volt. A pacman játékokban megfigyelhetjük, hogy a szörnyek általában egy adott irányba mozognak, amíg kereszteződéshez nem érnek, és ott újra felvesznek valamilyen irányt. Ezt próbáltam én is megvalósítani valahogy. Négy szörny volt a pályán, mindegyiknél figyelni kellett, hogy kereszteződéshez vagy zsákutcához érnek-e, és akkor új irányt kellett nekik meghatározni. Ezt először, kisebb küzdelmek árán így sikerült elérnem valamikor 1995 őszén, ha jól emlékszem:


 3750 LET UT,FEL,LE,JO,BA=0
 3760 IF KEP$(SZO1(A)-1,SZO2(A))=" " THEN LET UT=UT+1:LET FEL=1
 3770 IF KEP$(SZO1(A)+1,SZO2(A))=" " THEN LET UT=UT+4:LET LE=1
 3780 IF KEP$(SZO1(A),SZO2(A)-1)=" " THEN LET UT=UT+8:LET BA=1
 3790 IF KEP$(SZO1(A),SZO2(A)+1)=" " THEN LET UT=UT+2:LET JO=1
 3800 IF UT=5 OR UT=10 THEN GOTO 3970
 3810 IF FEL+LE+JO+BA=0 THEN LET I1(A),I2(A)=0:GOTO 3970
 3820 IF FEL+LE+JO+BA=1 THEN LET I1(A)=I1(A)*(-1):LET I2(A)=I2(A)*(-1):GOTO 3970
 3830 SELECT CASE RND(4)
 3840 CASE 0
 3850   IF FEL=1 THEN LET I1(A)=-1:LET I2(A)=0:GOTO 3960
 3860   LET I1(A)=1:LET I2(A)=0
 3870 CASE 1
 3880   IF LE=1 THEN LET I1(A)=1:LET I2(A)=0:GOTO 3960
 3890   LET I1(A)=-1:LET I2(A)=0
 3900 CASE 2
 3910   IF JO=1 THEN LET I1(A)=0:LET I2(A)=1:GOTO 3960
 3920   LET I1(A)=0:LET I2(A)=-1
 3930 CASE 3
 3940   IF BA=1 THEN LET I1(A)=0:LET I2(A)=-1:GOTO 3960
 3950   LET I1(A)=0:LET I2(A)=1
 3960 END SELECT
 3970 RETURN

Addig módosítgattam ezt az eljárást, amíg úgy nem működött, ahogy elképzeltem, utána meg már nem foglalkoztam vele, csak örültem, hogy működik. Pedig ez eléggé szedett-vedett, és lehetne rajta szépíteni. A 3760-3790-es sorokban megnézi a program, hogy az adott szörny alatt, fölött, tőle jobbra és balra szóköz van-e, azaz nincs-e fal, és ha szabad a pálya, akkor az UT változó értékét módosítja, és a túlbiztosítás érdekében a FEL, LE, JO, BA változók értékét is értelemszerűen 1-re módosítja 0-ról. Ezzel eltárolja a gép, hogy merre van lehetséges útirány a szörny számára. A 3800-as sorban megvizsgáljuk, hogy esetleg pont csak függőlegesen mindkét irányba, vagy csak vízszintesen mindkét irányba tudunk-e mozogni, és ha igen, akkor nem történik semmi, hanem tartjuk az irányt, tehát egyirányú folyosón tovább megyünk arra, amerre addig is tartottunk. A 3810-es sorban azt biztosítjuk, hogy ha a szörny mind a négy oldalról körül van véve fallal, akkor semerre ne mozduljon el. A 3820-as sorban azt ellenőrizzük, hogy zsákutcában vagyunk-e, vagyis csak egyetlen irányba mozoghatunk-e. Ilyenkor feltételezzük, hogy az egyetlen lehetséges irányból jöttünk, így az irányt megváltoztatjuk. Ez az irányváltás, és az előbb említett folyosón haladás is csak akkor lehetséges, ha már adott volt egy irány, tehát rögtön a játék indulásakor, amikor az irányt meghatározzuk, ez még nem működik. A pálya indulásakor mindig meg kellett határozni az irányt egy külön eljárással. A 3830-as sortól pedig akkor adunk egy véletlenszerű irányt a lehetséges irányok közül a szörnynek, ha se nem folyosón haladunk, se nem zsákutcába nem értünk, se nem volt a szörny körülvéve minden oldalról fallal.

Egy probléma volt ezzel a pacman típusú játékkal: a képernyőn lévő bogyókat a szörnyek felülírták a mozgásukkal. Bonyolultnak láttam megcsinálni, hogy a szörnyek megjegyezzék, hogy bogyóra vagy szóközre léptek-e rá, és azt rakják ki maguk után. Emlékeztem, hogy általános iskolában talán számítógépes szakkör keretében, vagy ki tudja, mikor, előkerült a Plus/4-es Squirm című játék, ahol a pacmanhez hasonlóan bogyókat kell gyűjteni, a pályán kígyók mozognak, melyekkel nem szabad összeütközni. Ott úgy működött a játék, hogy az egyik kígyó mindig bogyókat hagyott maga után, a többi kígyó pedig szóközt, és 200 bogyót kellett összegyűjteni a pálya teljesítéséhez.

https://www.youtube.com/watch?v=aBVo64iLZn4

Innen jött az ötletem, hogy a Hungry Creature játékban két szörny mindig bogyókat, a másik kettő pedig mindig szóközöket hagyjon maga után, és bizonyos mennyiségű bogyó összeszedése kellett a szint teljesítéséhez. Ezt sokkal könnyebbnek láttam megvalósítani, mint hogy a szörnyek megjegyezzék, hogy bogyóra vagy szóközre léptek-e.

Nagy örömömre összejött ebből a Hungry Creature című játék, ami Zzzippel lefordítva pont játszható sebességgel működik. Igaz, az egész képernyő egyszínű, mert karakteres képernyőn fut a program, így csak egy tintaszín és egy háttérszín van, de legalább pályánként változik a paletta.
Szerettem zenéket komponálni DATA sorokba írt számok segítségével, így volt néhány szerzeményem. Ezek közül az egyiket betettem a menübe háttérzenének.



Gondoltam, toplista is kellene, hogy beírhassuk játék után a nevünket, a program pedig beillessze pontszámunk alapján a nevünket a megfelelő helyre a rangsorban. Ennek megvalósításáról nem sok fogalmam volt, viszont eszembe jutott, hogy a Felhasználói kézikönyvben volt egy példaprogram, amely 10 számot rendez nagyság szerint sorba:


140 NUMERIC TOMB(1 TO 10)
150 NUMERIC VALT,SZAM,MAX

250 LET VEG=10
260 FOR X=1 TO 10
270   LET MAX=0
280   FOR Y=1 TO VEG
290     IF TOMB(Y)>MAX THEN LET MAX=TOMB(Y)
300     IF TOMB(Y)=MAX THEN LET SZAM=Y
310   NEXT Y
320   LET VALT=TOMB(VEG)
330   LET TOMB(VEG)=MAX
340   LET TOMB(SZAM)=VALT
350   LET VEG=VEG-1
360 NEXT X
370 FOR X=1 TO 10
380   PRINT TOMB(X)
390 NEXT X
Ezt a programot addig módosítgattam, amíg el nem értem, hogy a 10 legjobb pontszámot rendezze sorba a pontszámokhoz tartozó névvel együtt. Így névbeírás után a megfelelő helyre kerültünk a toplistában. Itt is számokat kellett sorba rendezni, de ez annyiból nehezebb volt, hogy a számokhoz (pontszámokhoz) nevek is tartoznak, és a pontszámokat a nevekkel együtt kell mozgatni, a nevek pedig már nem számokként, hanem sztringként tárolhatók:


140 STRING * 15 N$(1 TO 10),MAX$,VALT$
150 NUMERIC SZAM

6080 LET VEG=10
6090 FOR X=1 TO 10
6100   LET MAX$="99999AAAAAAAAAA"
6110   FOR Y=1 TO VEG
6120     IF N$(Y)<MAX$ THEN LET MAX$=N$(Y)
6130     IF N$(Y)=MAX$ THEN LET SZAM=Y
6140   NEXT Y
6150   LET VALT$=N$(VEG)
6160   LET N$(VEG)=MAX$
6170   LET N$(SZAM)=VALT$
6180   LET VEG=VEG-1
6190 NEXT X
6200 LET MINPONT=VAL(N$(10))

Ahogy a MAX$ változóból látható, a pontszámok és a nevek egymáshoz kapcsolását úgy oldottam meg, hogy egyetlen sztringbe írtam bele a pontszámot és a nevet, elöl a pontszámmal.
Sztringeket is nagyság szerint sorba lehet rendezni, mint számokat, de ez kicsit máshogy működik. Sztringeknél elsősorban azt nézi a gép, hogy melyik hosszabb, és az lesz a nagyobb. Ha egyforma hosszúak a sztringek, akkor aszerint dönti el, melyik legyen a nagyobb, hogy az első karaktereknek a kódja melyiknek nagyobb. Hogy egyforma hosszúak legyenek a pontszámot és nevet tároló sztringek, azt találtam ki, hogy az első öt karakter a pontszámot, a következő tíz karakter pedig a nevet tárolja. Ha a pontszám ötnél kevesebb számjegyből áll, az elejére annyi nullát kell lenni, hogy meglegyen az öt számjegy. Ha pedig a név rövidebb tíz karakternél, a végére szóközöket, vagy esztétikai célból inkább pontokat kell tenni. Ezekkel a módosításokkal már a sztringekbe fűzött pontszám+név együttest is a pontszám nagysága szerinti sorrendbe lehet rendezni. A pontszámtábla képernyőre írásakor pedig először a neveket írjuk ki egymás alá, azaz a sztringet az ötödiktől a tizenötödik karakteréig, utána akár színt váltunk, és az új színnel a nevek után a pontszámokat, amelyek nullákkal az elejükön szebben is mutatnak.
A MINPONT változóra azért volt szükség, mert csak akkor ugrott a program a névbeírás részhez, ha az addigi legkisebb pontszámot meghaladta az új eredmény.

Pályaszerkesztőt is készítettem a játékba, a készített pályákat el lehet menteni, és választhatunk, hogy a beépített vagy a kimentett pályákkal akarunk-e játszani. Ez magnós gépnél nem annyira jó, floppys gépnél elmegy, SD-s gépnél pedig akár egészen előnyös is lehet.
Nagyjából így állt össze a Hungry Creature.

https://www.youtube.com/watch?v=-ck2h2ih6fo

A Dot Collector is bejön a képbe!

Egyszer valamikor, én se tudom, mikor, talán a 90-es évek második felében eszembe jutott a Dot Collector játék, hogy az milyen rövid, magnóról betöltődik két füttyre a fejléc után, és hogy az is valamiféle karakteres képernyőn fut, legalábbis karakterekből épül fel a képernyő, hiszen a mozgás is karakteres.

http://www.ep128.hu/Ep_Games/Pic/Dot_2.gif 

Arra gondoltam, mivel rövid program, talán nem lesz nehéz benne megtalálni azokat a részeket, ahol a pályák tárolódnak. Meg is találtam, ASMON-nal átírva a kód megfelelő részét a pálya is módosult, aminek ugyancsak nagyon megörültem. Persze így kissé nehéz lenne áttervezni a pályát. Mivel a program rövid, arra gondoltam, egy basic programmal beolvasom magát az egész játékot, egy tömbben letárolom bájtonként, és onnan megjelenítem a pályákat és megcsinálom, hogy lehessen a pályákat szerkeszteni. Biztos eltartott egy darabig, mire ez meglett, de már nem emlékszem a részletekre.
Azonban sajnos tragédia történt. Nem sok floppylemezem ment tönkre, de amin a Dot Collector pályaszerkesztő volt, az pont tönkrement, így elveszett minden. Nem hagyott azonban nyugodni a dolog, és a 21. században újra nekiálltam megírni a Dot Collector pályaszerkesztőt, ami szép lassan kész is lett. Így aztán lett Dot Collector 2, Dot Collector 3, Dot Collector 4, többé-kevésbé újszerű pályákkal. (Az ep128.hu oldalról letölthető a Dot Collector 2., 3., 4. része, és a pályaszerkesztő is: http://ep128.hu/Ep_Games/Leiras/Dot_Games.htm)

 http://www.ep128.hu/Ep_Games/Pic/Dotdes.gif
A Dot Collector pályaszerkesztője












Szöget ütött a fejembe az is, hogy ha már ki tudom nyerni a Dot Collector pályáit, akár fel is használhatnám azokat basic programban, így akár a Hungry Creature-höz hasonló játékot lehetne írni úgy, hogy a szörnyek a Dot Collector pályáin mozognának. A Dot Collectorban a szörnyek mozgása meglehetősen egyszerűen van megoldva: mindig az emberkénk irányába próbálnak mozogni, arra, ahol éppen nincsen fal. Ezért a Dot Collector némiképp logikai jellegű játék, a szörnyek nem mozognak folyamatosan, ahogy általában a pacman típusú játékokban. Nem tudni, a játék készítői miért így oldották meg, hiszen a véletlenszerű, pacman játékokból ismert szörnymozgás megvalósítása sem lett volna annyira bonyolult, ha már nagy nehezen én is meg tudtam csinálni. De lehet, hogy direkt írták meg így a programot, bár dobhatott volna rajta, ha dinamikusabb a játék. A lényeg, hogy elhatároztam, összeeresztem a Dot Collector pályáit a dinamikusan mozgó szörnyekkel. Ki is cseréltem a Hungry Creature játékban a pályákat a Dot Collector pályáira. Sajnos sokáig nem tudtam folytatni a nagy művet, mert valami probléma volt valamelyik szörny koordinátáival, hiszen a játéktér kb. feleakkora, mint amekkora az egész képernyőn elférne, és a Hungry Creature pályáiban más volt a szörnyek startpozíciója. Sokáig nem jöttem rá, miért nem tudom átírni a szörnyek startpozícióját, hogy most már az új pályákon mozogjanak. De elhatároztam, hogy ha addig élek is, megcsinálom. Emlékszem, valamikor a 2010-es évek közepén lett laptopom, amire természetesen az EP128Emu-t is feltettem. Időnként Pestre utaztam, ami majdnem egy óra vonatozás, és kipróbáltam, milyen lehet utazás közben programozgatni Enterprise-on az emulátorral. A mai napig emlékszem, hogy ott a vonaton sikerült megvalósítani, hogy a szörnyek a Dot Collectorból kiszedett pályán mozogjanak. Nagyon boldog voltam, de a kalauznak nem számoltam be a sikeremről, hiszen nem értette volna, mit jövök én Enterprise emulátorokkal. (Igaz, ki tudja, akár neki is lehetett régen Enterprise-a.) A lényeg, hogy meglett végül a Dot Collector Turbo Edition becenévre keresztelt játék, ahol a szörnyek dinamikusan mozognak, bár a képernyőn még mindig csak két szín volt, az egyik a háttér színe. A Dot Collector pályáin varázstabletták is vannak, melyek egy kis időre sérthetetlenséget adnak, és egy számláló jelzi (a jobb oldali kijelzőn a HELP mellett), hogy meddig tart a hatása. Ezt elsőre bonyolultnak gondoltam megcsinálni. Helyette azt találtam ki, hogy plusz energiát adnak a varázstabletták, így a szörnyek nem nyiffantják ki egyből hősünket. Ahogy a program fejlesztésével haladtam, mindig feltöltöttem az újabb verziót az Enterprise Forever fórumra. Ott Ferro73 fórumtárs is elkezdett foglalkozni a programmal, javaslatokat tett a módosításokra, több részt át is írt benne. Tett bele többek között karakteres animációt, a varázstabletták már villogtak. Javaslatára már nem mentette el tömbbe a játékteret a program, hanem a képernyőről olvasta be a karaktereket, a szörnyek mozgásához. A karakterek beolvasásához már nem GET #102:A$, hanem SPEEK került bevetésre, valamint a szörnyek és az emberkénk képernyőre írása is már nem PRINT AT, hanem SPOKE segítségével történt:

Régi módszer:
PRINT #102,AT oszlop,sor:;
GET #102:A$
IF A$=blablabla

Új módszer:
IF SPEEK(255,VM+(sor*36)+oszlop)=blablabla
LET VM=(SPEEK(255,14644)+((SPEEK(255,14645)-128)*256))-35

Ez persze még csak 128-as gépen működik, Enterprise 64-en nem. Az új módszer programozásánál arra is figyelni kell, hogy a kép videomemória-beli helye nagyon sok mindentől megváltozhat. Ezért fixre nem szabad állítani, ki kell olvasni az LPT táblából, csak úgy lesz jó mindenhol. Ehhez én persze nem értek, Ferro73-ék megoldották ezt is a programban:


 5515   LET LPBADDL=SPEEK(255,16372):LET LPBADDH=SPEEK(255,16373)
 5516   LET LPBADDH=LPBADDH-128:LET LPBSZ=255
 5517   LET LPBADD=LPBADDL+(256*LPBADDH)
...
 5530   OPEN #102:"VIDEO:"
...
 5555   LET CIM=LPBADD+(3*16) !
 5556   LET GETAH=SPEEK(LPBSZ,CIM+5)-128
 5557   LET VM=SPEEK(LPBSZ,CIM+4)+(256*GETAH)-35

Így a Dot Collector Turbo Edition már egy feljavított változata lett a Hungry Creature-nek, azon túl, hogy új pályákat tartalmazott. Az új pályák többé-kevésbé eltértek a Dot Collector eredeti pályáitól, mivel az újfajta szörnymozgás bezavarhat ebbe: vagy pillanatok alatt végigszáguld a szörny egy folyosón, vagy pedig egy nagyobb, üres részen szöszmötöl sokáig.



A képernyő jobb oldalát a kijelzők foglalják el (pontszám, életek száma, stb.) Ennek az alsó részén van egy kis hely, ahol eredetileg csak egy árva Dot Collector felirat virított. Pihenésképpen megpróbáltam ide más szöveget írni, vagy a játéktéren belülihez hasonló falakat rajzolni. Láttam, hogy ezek a falak akár a játéktér meghosszabbításai is lehetnének, és azt találtam ki, hogy a negyedik varázstabletta felvételekor megnyílik ott egy kapu, vagyis szóközt rak a gép a játéktér jobb alsó részén a falba, és át lehet menni a kijelzők alá. Ezt a lehetőséget SlashNet, ukrán fórumtársunk először bugnak nézte. A későbbi fejlesztéseknél nagy szerepe lesz még ennek a kapunak, ugyanis csak így juthatunk majd el a pálya bizonyos részeire, de ne rohanjunk még annyira előre!


Tervben volt, hogy attribútum képernyősre átírjuk ezt a játékot, ez azonban elmaradt, mert nagyon sok mindent másképp kellene megcsinálni benne, ráadásul attribútum képernyőn a karakteres animációtól is érzékeny búcsút kellene venni.

Egy kis kitérő: a Hamika kígyós játék is berobban a színpadra

Valamikor a 2010-es évek második felében előkerült a téma a fórumon a karakteres-grafikus (Endi által GraCha-nak nevezett) videomódokról. Eltartott egy darabig, mire felfogtam, hogy ez mi is tulajdonképpen, amiről a fórumban a profik írnak. (Erről az Enterpress 2019/3-4. számában már volt egy cikk.) Tehát, a háttér színével együtt egyszerre 4 szín lehet a karakteres képernyőn, egyetlen karakteren belül is lehet variálni a színeket, viszont a karakterek 8 pixel helyett csak 4 pixel szélesek. Ha még karaktersoronként külön videolapokat nyitunk, mindegyiken külön-külön beállíthatunk más palettát, így látványos programokat lehet írni, hiszen a 256 színből van mit válogatni. Születtek is ilyen játékok, a Bricky Prise és a Treasure Cave (by Geco), profi, gépi kódban írt játékok. Engem pedig nem hagyott nyugodni a gondolat, hogy ha már kiderült, hogy van ilyen karakteres-grafikus üzemmód, meg lehetne csinálni a Hamikát is így és akár sok más játékot is. A Hamikát végül megcsináltam, ez lett az Entersnake, erről már volt szó, ugyancsak az Enterpress 2019/3-4 számában.
Volt egyszer egy ismeretlen szerzőtől származó, fel-le scrollozó, karakteres képernyőn futó basic játék, ahol egy labirintusból kellett kitalálni. A neten sehol nem találtam, csak nekem volt meg, még anno egy cserepartnerem küldte. Előástam nagy nehezen valahonnan a süllyesztőből ezt a játékot, de érdemben nem is foglalkoztam vele. Inkább az ütött szöget a fejembe, hogy milyen érdekes ez a függőleges scroll basicben, ilyet még máshol nem igazán láttam (kivéve Endi Mega Pac Man, Zzzippel lefordított játéka), pedig egészen egyszerű megcsinálni, és ehhez négyszínű karakteres lapot is lehetne használni. Elég nagy videolapot létre lehet hozni basicből, többszörösét annak, mint ami a képernyőre egyszerre kifér, és könnyen, gyorsan lehet állítani, hogy ebből mi látsszon éppen. Így egészen egyszerű megcsinálni, hogy egy függőlegesen scrollozó pályán kóvályogjon az emberkénk. Az emberkének középen kell lennie, és mindig fölötte és és alatta is kb. 10 karakternyit kell mutatni a képernyőből a DISPLAY utasítás segítségével, akkor is, ha fel-le mozgunk. Ezen az egyszerű ötleten felbuzdulva megcsináltam a Hamikának a scrollos változatát, amikoris a kígyóval egy nagyobb pályán kell bolyonganunk, mint ami a képernyőn egyszerre látszik. Pontosabban csak az első három pályát csináltam meg ebből, a többi még várat magára, ez lenne majd az Entersnake 2.





Vissza a Pacmanhez!

2020 eleje felé valamiért nem nagyon hagyott nyugodni a dolog, hogy kéne egy olyan pacman játékot írni, ahol a szörnyek dinamikusan mozognak, és jó nagy a pálya, scrollozik fel-le. Érdekes volt belegondolni, hogy a szörnyek talán a labirintus másik felében lófrálnak, amit mi nem is látunk, majd egyszer csak odatévednek a képernyőbe. Fogtam hát a Dot Collector Turbo Edition-t és elkezdtem átalakítani. Az első talán az volt, hogy a videomódot átállítottam karakteresről karakteres-grafikus (4 színű) módra. Így a karakterek eléggé értékelhetetlenül néztek ki eleinte. A pályát vízszintesen kibővítettem egy kicsit a kijelzők alatt, és az egész pályát kb. 15 karakterrel lejjebb toltam. Utóbbira azért volt szükség, mert az emberke mindig függőlegesen a képernyő közepén van akkor is, ha a játéktér legtetejére megyünk, és még ilyenkor is látszik még kb. 10 karaktersornyi terület fölötte - ha pedig ott vége a videolapnak, nincs mit megjeleníteni, hibaüzenetet kapunk. Nagyon egyszerű megoldani, hogy függőlegesen mindig a játéktér közepén maradjon az emberke és fel-le mozgásnál scrollozzon a képernyő, egyszerűen csak minden fel-le mozgatásnál ki kell adni a DISPLAY AT 1 FROM X-10 TO X+10 utasítást, ahol X az emberke függőleges koordinátája.
A pálya tehát kb. 15 sorral lejjebb kezdődött (bár talán 10 is elég lett volna, de a túlbiztosításból gond sose lehet), így az emberke függőleges startpozíciójához is 15-öt kellett hozzáadni. A szörnyekéhez is ennyit kellett volna elméletileg, gyakorlatilag azonban SPOKE-kal lett definiálva már korábban a startpozíciójuk, és emiatt valamiért automatikusan ők is lejjebb kerültek, amikor a pályát lejjebb kezdtem kirajzoltatni a géppel. Sokáig agyaltam, miért nem jó, ha 15-öt hozzáadok az ő startpozíciójukhoz is, de az LPT-vel bűvészkedés nem hétköznapi embereknek való.

Tehát, a Dot Collector Turbo Editiont továbbfejlesztettem, karakteres helyett grafikus-karakteres képernyőt kapott, scrollozósra megcsináltam a pályát, és nagyobb pályát rajzoltam hozzá DATA sorokba, ahol lefele tovább lehet menni. Ebből lett a Dots and Gems című játék. A játék a nevét onnan kapta, hogy egyrészt bogyókat (dots) kell gyűjtenünk, másrészt a Dot Collectorban varázstabletták szerepét betöltő karakterek itt most új szerepet kaptak, drágakövek (Gems) lettek belőlük. A feladatunk most is az, hogy össze kell gyűjtenünk 200 bogyót, de ezen kívül a drágaköveket is össze kell gyűjtenünk mind. Az utóbbinál már egy kicsit elővigyázatosnak kell lenni. Ahogy már előre utaltam rá a Dot Collector Turbo Edition-ben, a varázstabletták kinyitnak egy kaput, így a pálya újabb részeibe is beléphetünk. A varázstabletták energiánkat növelik, és ha elérjük a 4 egységnyi energiát, a kapu kinyílik. Újabb varázstabletta felvételekor azonban a kapu becsukódik, még újabb felvételekor kinyílik, és így tovább. Ha energiát vesztünk, akkor 4-nél kevesebb lesz az energiánk, így a kaput már nem fogjuk tudni egyből kinyitni, és ha nem jól taktikázunk, nem tudunk bejutni a kapu mögötti részbe. Az első pályákon a kapu mögötti részen csak egy varázstabletta van, amit ha azonnal felvennénk, ahogy a kapu kinyílt, a kapu bezáródna, és nem tudnánk visszajutni a többi varázstablettát felvenni.
Először valamiért nehézkesnek tűnt megoldani, hogy a program figyelje a bogyók és a drágakövek felvételekor is, hogy megvan-e a 200 bogyó és az összes drágakő, hogy átmehessünk a következő szintre. Ehhez ki kellett volna ugrani egy ciklusból, ami nem túl szép. Ezért azt találtam ki, hogy a szörnyekkel való érintkezésnél nézze meg a program, hogy összeszedtünk-e már mindent, és ha igen, akkor engedjen a következő szintre, hiszen a szörnyekkel érintkezés és esetleges életvesztés amúgy is kiugrasztja a ciklusból a játékot. Így hát úgy alakult, hogy miután mindent összeszedtünk, neki kell mennünk egy szörnynek. Viszont a scrollozás miatt a kijelző, mely azt is jelzi, összeszedtünk-e mindent, néha kikerült a képernyőről. Ezt a problémát már az elején is láttam és tudtam, hogy ezzel csinálni kellene valamit, és a kijelzőt máshol, a játéktéren kívül kellene elhelyezni a képernyőn. Végül azonban úgy tűnt, érdekesebb úgy a játék, ha fel kell menni a játéktér tetejére, hogy lássuk, összeszedtünk-e mindent és nyugodtan nekimehetünk a szörnynek.

Ferro73 az Entersnake fejlesztését is aktívan figyelemmel kísérte, sőt több javaslattal, módosítással is hozzájárult a végleges verzióhoz. Többek között rámutatott arra, hogy a Hungry Creature-ből átvett, pontszámokat sorba rendezős részt egyszerűbben is meg lehet csinálni. Ugyanis a pontszámok alapból is nagyság szerinti sorba vannak rendezve, nem kell az új pontszám miatt az egészet újra sorba rendezni, csak az új pontszámnak megkeresni a megfelelő helyet, és az alatta levő pontszámokat eggyel lejjebb kell tolni. Arra is felhívta a figyelmem, hogy nem kell a nevet és pontszámot tartalmazó sztringben az elejére tenni a pontszámot, mert a sztring adott karakterétől nézve is sorba lehet rendezni a pontszámokat. Így a pontszámokat sorba rendező rész egyszerűsödött:

 3890   FOR X=9 TO 1 STEP-1
 3900     IF VAL(N$(X)(12:15))>=SCO THEN 3940
 3910     LET CS$=N$(X)
 3920     LET N$(X)=N$(X+1)
 3930     LET N$(X+1)=CS$
 3940   NEXT X
 3950   LET MINPONT=VAL(N$(9)(12:15))


A Hungry Creature-ben és a Dot Collector Turbo Edition-ben a játék közbeni alapzajt a szörnyek koordinátáiból rakta össze a gép. Ez kicsit vicces hangzást ad, például amikor lefelé halad egy szörny, egyre mélyebb hangot ad, közben egy másik szörny felfele halad, annak meg egyre magasabb a hangja, és a négy szörny pozíciójából folyamatosan, gyorsan állítja elő a zajt a játék. A scrollozós pálya már nagyobb, így ha nagyon lemennek a szörnyek, már annyira magas hang generálódik, ami nem hangzik jó. Így ezeket a hangokat le kellett cserélni valami másra, írtam egy egyszerű zenét, ami játék közben szól (egyébként pont 64 hangból áll, ha a szüneteket is beleszámítjuk). A zene egyszólamú, de két csatornát használ, majdnem ugyanaz a hangmagasság szól a két csatornán, és a csatornák gyűrűmodulációval vannak összekötve. A majdnem ugyanaz a hangmagasság azt jelenti, hogy egy kicsit különböző, pontosan 0.1 PITCH értékkel. Azonban a Zzzip nem kezel nem egész értékeket, így a 0.1 értékből adódó kellemes hangzás ugrana. Erre még a Hungry Creature játéknál azt találtam ki, hogy a Zzzip basic betöltőjébe beleteszek egy ENVELOPE NUMBER 1;.1,63,63,1;... kezdetű burkológörbét, ahol már az elején eltéríti a hangmagasságot, ami azért jó, mert a Zzzippel betöltött programban a korábban létrehozott burkológörbék megmaradnak. Felfedeztem azonban egy újabb lehetőséget: ha fájlba mentjük a burkológörbét escape szekvenciaként, azt a Zzzippel fordított program vissza tudja tölteni egy az egyben. Ezért, hogy kisebb legyen maga a program is, külön elmentettem a program által használt összes ENVELOPE NUMBER-t escape szekvenciaként:

CLOSE #103 ! sound: eszköz bezárása
OPEN #103:"gems.env" ACCESS OUTPUT
ENVELOPE NUMBER 1;........
CLOSE #103
OPEN #103:"sound:"

A játék, betöltés után beolvassa ezeket:

OPEN #106:"gems.env" ACCESS INPUT
COPY FROM #106 to #103
CLOSE #106

https://www.youtube.com/watch?v=H8Jna7vn0bY

Endi régebben megtervezte a nagybetűket és a számokat a négyszínű karakteres módhoz. Így tehát ilyen üzemmódban is lehet feliratokat kiírni a képernyőre, a betűk és számok mindössze négy pixel szélesek, ebből egy pixelnyi hely üres kell, hogy legyen, hogy a betűk ne folyjanak egybe. Endi gondoskodott arról is, hogy mind a három szín előforduljon egy karakteren belül esztétikusan. Ezeket a karaktereket már az Entersnake-ben is felhasználtam mindenféle szöveg kiírására. Ugyanezt a karakterkészletet használja a Dots and Gems is, erre feltétlen szükség is van, hiszen a kijelző a játéktérrel egy videolapon van, ahogy az a Dot Collectorban is volt eredetileg, ott pedig az eredeti, kétszínű karakterek krikszkrakszként jelennének meg.



A négyszínű módhoz való betűk és számok karakterdefiníciói sok helyet foglalnak el egy basic programban, így az egyébként is terjedelmes játékhoz azt találtuk ki már az Entersnake-nél közösen a fórumon, hogy elmentjük egy fájlba a karakterkészletet, amit a program egyszerűen visszatölt. Volt egy korábbi program, amely így töltötte be a karaktermátrixot:


1 ALLOCATE 9
2 CODE CHAR=HEX$("3E,01,01,80,04")
3 CODE =HEX$("EB,F7,06,C9")
4 LET FONT=(SPEEK(255,16372)+SPEEK(255,16373)*256)-1152
5 OPEN #1:"CHRSET.BIN" ACCESS INPUT
6 CALL USR(CHAR,FONT)
7 CLOSE #1

A játékban ez nem bizonyult működőképesnek. Hogy miért nem, annak az okát azóta is kutatjuk. Helyette a rafinált fórumtársak a következő módszert dolgozták ki a karaktermátrix betöltésére (assembly rajongók előnyben):



   11 ALLOCATE 40
   12 CODE LDCHAR=HEX$("DB,B2,F5,3E,FF,D3,B2,2A")
   13 CODE =HEX$("F4,BF,3E,06,85,6F,5E,23")
   14 CODE =HEX$("56,06,07,CB,13,CB,12,10")
   15 CODE =HEX$("FA,CB,B2,01,80,04,3E,6A")
   16 CODE =HEX$("F7,06,F1,D3,B2,C9,00,00")
 4850   OPEN #106:"GEMS.CHR" ACCESS INPUT
 4860   CALL USR(LDCHAR,0)
 4900   CLOSE #106


Felmerült, hogy a szűk folyosókon nehéz betalálni, hogy karakterre pontosan oda kell állni, hogy tovább tudjunk menni. Ez egyébként a Dot Collectorban is így volt még. Tomato77 (aki a Banana 1-2 szerzője) és ergoGnomik (aki gyakran ír hasznos, programozással kapcsolatos tanácsokat mindenkinek) fórumtársak javaslatai alapján megcsináltam, hogy ha egy karakterpozícióval arrébb van az emberkénk és úgy akarunk bemenni a kapun, akkor egy karaktert arrébb ugorjon, és menjen be. A módszer lényege, hogy ha nem tudunk menni az adott irányba, mert fal van ott, meg kell nézni a két szomszédos pozíciót is, hogy ott is fal van-e, és ha nem, akkor arra menni. A fórumtársakkal közösen sikerült ezt a részt úgy megírni, hogy ne legyen minden irány vizsgálatánál hatalmas terjedelmű programrész, hanem csak a lehetséges irányokat írja be egy-két változóba, és egy későbbi programrész megvizsgálja, hogy azokban az irányokban mi a helyzet, és aszerint mozgassa az emberkénket. Így sokkal játszhatóbb a játék, és ez a módszer jól fog jönni még esetleges későbbi pacman-típusú játékok írásakor.

A szörnymozgást 1995-ben a Hungry Creature-ben meglehetősen toldozott-foldozott módszerrel oldottam meg, a lényeg csak az volt, hogy működjön. (Lásd feljebb.) Szúrta a szemem, hogy az ahhoz képest szép színes, scrollozó játékban még mindig ez van. Többféleképpen is meg lehetett volna oldani más módszerrel ezt, végül Tomato77 ismertetett a fórumon egy frappáns módszert arra, hogyan vizsgálja meg a program, merre mozoghatnak a szörnyek, és milyen irányba menjenek. A MERRE() tömbben az 1 és -1 a vízszintes mozgást jelenti, a 34 és -34 pedig a függőlegest, mivel 34 karakter széles a játéktér:

NUMERIC MERRE(0 TO 3),LEHET(0 TO 3)
MERRE(0)=-1:MERRE(1)=1:MERRE(2)=-34:MERRE(3)=34
...
  LEHETDB=0 ! Ez mutatja, hány irány lehet
  ! Körbenézi négy irányból, ami jó, beteszi a LEHET tömbbe
  FOR J=0 TO 3
    IF SPEEK(255,SZOR(A)+MERRE(J))<46 OR
       SPEEK(255,SZOR(A)+MERRE(J))=112 THEN
      LEHET(LEHETDB)=J ! Ide teszi, hogy mely irányok jók
      LEHETDB=LEHETDB+1
    END IF
  NEXT J
  ! Itt már megvan, melyik irányokba mehet, válasszon ki egyet
  I(A)=MERRE(LEHET(RND(LEHETDB)))

Módszeremet lecseréltem az ő módszerére. A program ugyanazt csinálja, mint eddig, ugyanúgy működik, de mégis csak elegánsabb ez a módszer.
Ha felkerülünk a pontszámtáblára, a program elmenti az eredményünket. Belegondoltam, hogy magnós gépnél erre talán nincs szükség. Geco azt mondta, Spectrum és CPC átiratoknál a pontszámtábla csak akkor kerül elmentésre, ha lemezes a gép. Volt egy kis tanakodás, hogyan lehetne megvizsgálni, hogy lemezes vagy magnós-e a gép. Például, egy WHEN blokkon belül kiadunk egy EXDOS parancsot, és ha nincs EXDOS a gépben, az hibát okoz, a hibakezelő pedig megváltoztatja egy változó értékét - ez kicsit hosszadalmas. Végül Zozosoft mondta meg a tuti módszert:

ASK 3 XDOS

Az XDOS változó értékének függvényében tehát a gép eldönti, mentse-e a ponttáblát vagy ne.

A játék fut Enterprise 64-en is, de lassabban. Alapból a sebesség túl gyors lenne, ezért a játék állandóan meghív egy lassító ciklust. A megoldás, hogy 64-es gépen ez a ciklus kevesebbet lassítson, mint 128-on. Ehhez a programnak tudnia kell, milyen gépen fut. Ezt az IN(176) értékének segítségével ellenőrzi. Másik lehetőség lenne a VERNUM változó vizsgálata, mely a BASIC verziószámát tárolja (EP64-en 2.0, EP128-on 2.1). Azonban a Zzzip ezt nem szereti, mivel csak egész számokat kezel. Viszont ott van még a VER$ szöveges változó, amiben szintén benne van a BASIC verziószáma, a string részeként, és az is kiolvasható.

A játékba kerültek karakteres animációk. Nem csak a drágakövek villognak, hanem a bogyók is, és a szörnyek is változtatják kicsit az alakjukat. A vízszintes vonalakra is készítettem karakteres animációt. Ezeket nem a SET CHARACTER paranccsal írja át a program, hanem SPOKE-kal, az gyorsabb. Ehhez természetesen figyelembe veszi azt is, hogy 64-es vagy 128-as-e a gép (EXOS kompatíbilis), ami már nem is nehéz, mert a karaktermátrix betöltéséhez is szükség van ezekre a címekre. „Természetesen" sem a karakterek alakja, sem az LPT kezdőcíme nem ugyanott van 64-es és 128-as gépen.

Végezetül egy kis érdekesség: A szörnyekkel ütközéskor a program a LOST nevű eljárást hívja meg. Ha ezt akarjuk kilistázni, a LIST LOST parancsot kell kiadni. Ha az utolsó sort akarjuk a programból kilistázni, ahhoz a LIST LAST kell. Ha a LOST eljárás és az utolsó sor is kell: LIST LOST,LAST.



Wednesday, 1 July 2020

Mondd csak! A SAY című Enterprise program


Biztos sokan emlékeznek még Devilsoftnak 1990-ben készült SAY című beszélő programjára. Vagyis, beszélő programnak kicsit túlzás nevezni, inkább mondjuk azt, hogy megpróbálja a beszédet utánozni. A mai világban, amikor a Google felolvasója már több nyelven tud felolvasni, mint bármelyik ember, ez nem túl érdekes, de a 90-es években nagyon is fel lehetett kelteni az emberek érdeklődését ezzel: beírunk valamiféle szöveget a :SAY után idézőjelek közé, és azt „felolvassa” a gép a maga gépies hangján, ez fantasztikus! Talán voltak, akik a 90-es években elszórakoztak ezzel a programmal, mindenféle szavakat, szöveget beírtak és jót szórakoztak azon, hogy a gép hogyan „ejti ki” azokat.
Kicsit teszteltük a programot, megkérdeztem néhány embert, mi a véleményük róla. Beszédes Elemér azt nyilatkozta, a brekegésimitátor még járhatna kicsit logopédushoz, hogy emberibb hangja legyen, de zajgenerátornak elmegy. Élesben is kipróbáltuk: Szó Ödön megkérte egy családtagját, álljon háttal a képernyőnek, míg beír néhány szót, amit a gép felolvas. Sokadik felolvasás után értette meg a szavakat az, aki háttal állt. Itthon mi is tettünk néhány próbát. Az „iskola” szót valamiért nagyon érthetően „ejti” a program, az is megértette, aki nem látta, hogy ezt írjuk be. Ellenben a „mit sütsz, kis szűcs?” mondat már nem volt érthető. Aki nem tudta, mit írtunk be, sokadik hallgatás után is úgy értette, hogy „virslit tessék”. Ennek ellenére érdekes, szórakoztató a program.
Valóban használható a program zajgenerátornak is. A szóközökhöz érve kis szünetet tart, így megfelelően váltogatva a betűket és a szóközöket akár jó, ritmusos „zenét” is kaphatunk. Egy kis ízelítő a program működéséből:


A program fonetikusan olvas fel, de sem a magyar, sem más nyelv kiejtési szabályait nem követi igazán. Öt magánhangzót ismer (a, e, i, o, u), az ékezettel jelölt magánhangzóinkat (pl. é, ö) nem. Minden egyes betűt „kiejt”, így a „cs” vagy az „sz” két grafémáját is külön-külön, és nincs is külön „sz” és „cs” hang. „Sz” helyett is „s”-t, „cs” helyett is „c”-t írhatunk be. Emberi beszédben feltűnő lenne, ha valaki az s-t és az sz-t, illetve a c-t és a cs-t is ugyanúgy ejti, de a múlt század vége felé egy számítógéptől ez elfogadható volt.
A program tehát rendszerbővítőként használható, bármilyen basic programból meghívható (Zzzippel fordított programból azonban nem). Sajnos nem készültek olyan basic programok, melyek ezt kihasználják. Használatáról annyit érdemes tudni, hogy a :SAY parancs után idézőjelbe kell írni a szövegünket, és a kezdő idézőjel után hagyni kell egy szóközt. Talán nem sokan tudták, hogy lehet a beszéd sebességét is állítani, ehhez az idézőjel előtt egy 1 és 256 közötti számot kell megadnunk, az 1 a leggyorsabb, a 256 a leglassabb tempó. Az alapértelmezés 33. Ha a tempót elállítjuk, akkor az úgy is marad, ha nem adjuk meg külön. A tempó változtatásának lehetőségét kihasználva például a következő program nyújthat kulturált kikapcsolódást:

100 FOR A=1 TO 48
110   EXT ”say ”&STR$(A)&””” iskola”””
120   GOTO 130
130 NEXT A

Ha Zozosoft által továbbfejlesztett EXOS van a gépünkben, akkor a 120-as sor természetesen elmaradhat.
Két másik beszélő program is készült Enterprise-ra, de pontosan olyan hangminőségben „olvasnak fel”, mint a SAY, csak a kezelésük tér el. Míg a SAY 1.0 rendszerbővítő, a Super Talk 2.0 programban egy csatornát kell megnyitni a say: eszközre (pl. OPEN #1:"say:"), és a PRINT utasítással arra kell küldeni a hallani kívánt szöveget (pl. PRINT #1:"keretkarakterek na mi van"). A Mikrobi című programba pedig indítás után beírhatjuk a szövegeinket és meghallgathatjuk, basic programból nem hívhatjuk meg.
A teljesség kedvéért meg kell említeni a hardveres beszédszintetizátort, a Speakeasy-t is. Ezt a nyomtatókimenetre kell csatlakoztatni. Ennek sajátossága, hogy a nyomtatásra szánt szövegeket rezgésekké alakítja, így a papír helyett a dobhártyánkat örvendezteti meg produktumával. Ez már valamivel érthetőbben olvas fel, mint az előbbi szoftveres megoldások. Sajnos ezt sem használja ki túl sok program, egyedül az Eat It Up boldogítja szövegelésével a Speakeasy-vel rendelkező játékosokat, ha a játék indulásakor azt választjuk ki, hogy mi bizony még Speakeasy-vel is rendelkezünk.