Az Entersprite animátor
| File-név: Enterspr.COM Program neve: EnterSprite | "a" Studio- 1985 Sprite-kezelő BASIC bővítés |
Amikor az ENTERPRISE "ellenségei" kifogásolták a gép adottságait, akkor leginkább a hardverből támogatott spritekezelés hiányát hangoztatták. Teljesen igazuk van, a gépben tényleg nincsenek beégetett sprite-ok úgy, mint mondjuk a C64nél. Csakhogy...
Egy 128 KB-nyi RAM-mal rendelkező gépre olyan sprite kezelő készíthető, amilyen csak tetszik! Ha a gép ráadásul olyan ügyesen kezeli a bővítéseket, mint az ENTERPRISE, akkor tényleg semmi akadálya nincs a dolognak. Helyzetünket még könnyebbé teszi, hogy az "a" Studio programozói már elkészítették saját sprite-animátorukat, az "EnterSPRITE"-ot. A Basic bővítőként inicializálódó program a sprite-ok kezelését, irányítását rendkívül leegyszerűsíti.
Az első ENTERPRISE programok egyike volt az EnterSPRITE, amely 8 sprite kezelését támogatja Basic-ben 11 utasítással és 2 függvénnyel. Az $$REL fejlécű, felhasználói áthelyezhető modulként inicializálódó programot eredetileg kazettán árusították, de lemezről is elindul. Az animátor 8 sprite vezérlését végzi el a "háttérből". Ráadásul egy sprite 8 fázisra tagolódik, így aztán még látványosabb és főleg gyorsabb programokat írhatunk Basic-ben. Kár, hogy az animátor alatt megáll az óra, ami játékprogramoknál igencsak gyakran használatos. A program az USER_ISR mutatón "lóg", így saját rutinunkat ez elé, korrekt módon kell beillesztenünk. A kezelendő sprite-okat egy másik programmal, a FINE PEN-nel kell elkészíteni.
A Basic bővítő parancsai, függvényei a következők:
| SLOAD <sorszám>, <$név> | |
sprite betöltése. A programban a sprite-okhoz egy-egy sorszámot kell rendelni, ez alapján hivatkozhatunk rájuk, a <sorszám> 1 és 8 között lehet. A <$név> azt a nevet jelenti, amellyel a sprite-ot a tervezés után rögzítettük. Természetesen itt megadható az eszköznév, a meghajtó, és az elérési útvonal is. Példa: SLOAD 4, "B:\SPRED\UMBRELLA.SPR" | |
| ANIMATE <sorszám>, [fázis_1], [fázis_2], ...[fázis_15]: | |
egy sprite-on belül az animáció során megjelenítendő fázisok sorrendjének megadása. A fázisok tetszőleges sorrendben követhetik egymást, megadásuk nem kötelező. A sprite tehát 8 fázist tartalmaz, ezzel a paranccsal a fázisok megjelenési sorrendjét állíthatjuk be. Ha az animátor az utolsóhoz ért, akkor elölről kezdi a fázisok kirakását. Példa: ANIMATE 4,5,4,8,6,4,3,1,6 | |
| SPEEDAN <sorszám>, <sebesség> | |
az animáció sebességének megadása egy sprite-ra vonatkozóan. A értékét egy 0-tól 255-ig terjedő számmal adhatjuk meg. A leggyorsabb mozgást az 1-es érték adja, a 0 gyakorlatilag leállítja az animációt. Figyelembe kell venni, hogy az animáció sebessége erősen függ a betöltött sprite-ok számától. Példa: SPEEDAN 4,10 | |
| ANIMON <sorszám> | |
| elindítja az adott sprite animációját. Példa: ANIMON 4 | |
| ANIMOFF <sorszám> | |
| leállítja az adott sprite animációját. Példa: ANIMOFF 4 | |
| DIRECTION <sorszám> ,<$irány> | |
az adott sprite mozgásirányának megadása. A mozgás 8 irányba történhet, az <$irány> az égtájak angol neveinek kezdőbetűjét jelenti:
Példa: DIRECTION 4,"NE" | |
| SPEEDSPR <sorszám>, <sebesség> | |
egy sprite sebességének megadása a mozgáshoz. A értéke itt is egy 0 és 255 közötti szám, az 1-es eredményezi a leglassabb mozgást, 0-ra megáll a sprite. Példa: SPEEDSPR 4,5 | |
| POSITION <sorszám>, <xpos>, <ypos> | |
adott sprite adott pozícióra helyezése. A képernyő bal felső sarka az origó. A paraméterek lehetséges értékei: 0<=xpos<=71, 0 < =ypos < =147. Példa: POSITION 4,71,147 | |
| SPRON <sorszám> | |
| adott sprite láthatóvá tétele. A parancs kiadása után a beállított jellemzőknek megfelelően megjelenik a sprite. Példa: SPRON 4 | |
| SPROFF <sorszám> | |
| adott sprite eltüntetése. Példa: SPROFF 4 | |
| INIT | |
| inicializálja a kezelőt (kiiktatja a megszakítási rutinját). Példa: INIT | |
| XPOS(<sorszám>) | |
visszaadja az adott sprite X irányú pozícióját. A visszaadott érték illeszkedik a POSITION parancsnál közölt tartományhoz. Példa: X4=XPOS(4) | |
| YPOS(<sorszám>) | |
visszaadja az adott sprite Y irányú pozícióját. A visszaadott érték illeszkedik a POSITION parancsnál közölt tartományhoz. Példa: Y4=YPOS(4) | |
Az EnterSPRITE inicializációja után elsőként az előzőleg már megtervezett sprite-okat kell betölteni (SLOAD). A sprite paraméterek (ANIMATE, SPEEDAN, ANIMON, DIRECTION, SPEEDSPR, POSITION) beállítását követően a GRAPHICS HIRES 16 parancs kiadása, majd a sprite-ok bekapcsolása (SPRON) következik. Ha a kezelőt ki akarjuk kapcsolni, akkor adjuk ki az INIT parancsot, és minden más "sprite-független" műveletet csak ezután végezzünk el.
Szerencsés lett volna egy sprite definiáló utasítást is beépíteni a parancsok közé. Valószínűleg a fejlesztők azért nem tették meg ezt, mert a színek kezelése a felhasználó szempontjából nehézkes lett volna (a sprite-ot alkotó összes pontról meg kellene mondani, hogy milyen színű legyen). Ilyen formán viszont az sprite animátor a FINE PEN nélkül nem használható. (Ügyes árukapcsolás!)
Az EnterSPRITE tehát csak a GRAPHICS HIRES 16 parancs hatására keletkező képernyőn működik helyesen. Sajnos hiába definiáljuk át a 101-es csatornát más méretűre, a program ezt nem képes lekezelni, marad hát a 40*20-as méret. A két-, négy-, kétszázötvenhat-színű képernyőkön pedig szemetet jelenít meg. Érdekes látvány az is, amikor bekapcsolt kezelő mellett 80 karakteres szöveges képernyőre váltunk át, ahol a szövegeken időnként "szöszmöszök" úsznak át.
A parancsoknál is tapasztalható némi inkorrektség. Az INIT például nem állítja alaphelyzetbe a sprite változókat, csupán a megszakítási rutint iktatja ki. Az INIT-nek ez a hiányossága előnynek is felfogható, hiszen ha egyszer beállítottuk a sprite-okat, majd valamilyen okból kikapcsoljuk a kezelőt, akkor a fáradságos munkával beállított paraméterek megőrződnek. Nagyobb baj a felhasználói megszakítási rutinnal való "garázdálkodása": ha valaki a Basic programja mellett még saját IT rutint is szeretne használni, akkor először le kell kezelnie az EnterSPRITE rutinját. Nem kellően átgondolt a sebességértékek jelentése sem: a SPEEDAN-nél az 1-es érték a leggyorsabb, ugyanez a SPEEDSPR-nél a leglassabb mozgást eredményezi. A POSITION az x és y pozíciónak a valóságban 16 bites értékeket vesz át, csak az MSB-t nem veszi figyelembe. Így aztán origónak a 256 többszörösei is megfelelnek. A POSITION ,65351,65427 hatására például a jobb alsó sarokba áll be a sprite.
A FINE_PEN ismertetésénél már említettem, hogy az EnterSPRITE működése közben megáll az óra. Hiába adjuk ki később az INIT parancsot, az óra ekkor sem indul el, a TIME$ konstans értéket szolgáltat! Mivel az EnterSPRITE-ot leginkább játékprogramok "alá" készítették, az ilyen programokban pedig gyakran van szükség az idő mérésére, az óra kikapcsolása súlyos hibája az EnterSPRITE-nak.
Az animátor nem kellően intelligens, csak meglehetősen egyedi környezetben működik. Célszerűbb lett volna rendszerbővítőként, vagy perifériakezelőként megírni, így sokkal univerzálisabban lehetne használni. Jó lenne, ha a kezelő a főprogramtól teljesen függetlenül figyelne bizonyos előre beállítható eseményeket (pl. sprite ütközés), és azt az esemény bekövetkezésekor szoftver interrupton keresztül értesítené. Hiányzik a sprite prioritás beállíthatósága is.
A program kezelésének megértését megkönnyíti, ha a mellékelt BASIC bemutató programot (DEMO.BAS) áttanulmányozzuk, valamint érdemes kísérletezni a mellékelt sprite-okkal is (SPR kiterjesztésű file-ok).
Már ismerjük a sprite tervezés menetét, a sprite-kezelő lehetőségeit, nincs más hátra, minthogy egy példaprogramot lássunk. A program 110-es és 120-as soraiban történik a sprite-ok betöltése. Ide tehát azokat a sprite neveket kell beírnunk, amelyeken rögzítettük azokat. Fontos tudnivaló, hogy elég csak egyszer betöltenünk a sprite-okat, azok a RUN vagy a START, de még a meleg reset hatására sem törlődnek. Tehát ha betöltöttük a sprite-okat, akkor a SLOAD utasításokat tartalmazó sorok elé nyugodtan kitehetjük a felkiáltójelet (REM).
A program semmi különlegeset nem csinál. A betöltést követben beállítja a sprite környezetet, bekapcsolja a HIRES 16 típusú képernyőt. Ekkor egy mozgó és egy időnként a mozgóra ugró sprite-ot láthatunk. A program egyébként azt akarja demonstrálni, hogy az ugráló sprite miért nem ugrik minden olyan esetben, amikor kellene neki.
Az álldogáló sprite akkor ugrik (ugrana) a másik sprite-ra, amikor X vagy Y pozíciójuk megegyezik. A program elindítását követben azonban azt tapasztaljuk, hogy jónéhány ilyen esetben nem történik semmi, az álló sprite nem hajlandó az ugrásra.
Mi lehet ennek az oka? A magyarázat egyszerű: a Basic programunk alatt futó sprite-kezelő sokkal gyorsabb, mint a főprogram. Így hiába egyezik meg a két sprite X vagy Y pozíciója, a Basic program ezt nem veszi észre, mert a pozícióegyezés pillanatában éppen mással foglalkozik. A program jól példázza két, aszinkron módon futó program nehéz összehangolhatóságát. A sprite-kezelőt beállítjuk, a sprite-okat elindítjuk, és igazából már el is veszítettük felettük az uralmunkat, az animátor csak fut, és fut... A példában csak két sprite-ot kezelünk, és már egy egyszerű pozícióegyeztetés is komoly problémákat okoz. Ha a sprite-ok ütközését szeretnénk figyelni, akkor még ennél is több bajunk lenne, hiszen ott több irányból kellene pozíciótartományokat figyelnünk. És mi történne, ha mind a nyolc sprite-ot egyszerre akarnánk kezelni...?
100 PROGRAM "SPRMINTA.BAS"
110 SLOAD 5,"SPR1"
120 SLOAD 6,"SPR2"
130 INIT :RANDOMIZE :SET 26,1
140 STRING EX$(0 TO 3)
150 LET EX$(0)="ne":LET EX$(1)="nw"
160 LET EX$(2)="se":LET EX$(3)="sw"
170 REM 5.sprite
180 ANIMATE 5,1,3,5,7:SPEEDAN 5,9
190 POSITION 5,36,72:SPEEDSPR 5,0
200 REM 6.sprite
210 ANIMATE 6,2,4,6,8:SPEEDAN 6,10
220 POSITION 6,71,0:SPEEDSPR 6,1
230 DIRECTION 6,"ne"
240 REM start
250 GRAPHICS HIRES 16
260 SET £102:SCROLL ON
270 ANIMON 5:ANIMON 6
280 SPRON 5:SPRON 6
290 WHEN EXCEPTION USE BUMMM
300 DO
310 IF XPOS(5)=XPOS(6) THEN CAUSE EXCEPTION 100
320 IF YPOS(5)=YPOS(6) THEN CAUSE EXCEPTION 100
330 LOOP
340 END WHEN
350 HANDLER BUMMM
360 IF EXTYPE=9229 THEN
370 INIT
380 END
390 END IF
400 IF EXTYPE=100 THEN
410 POSITION 5,XPOS(6),YPOS(6)
420 DIRECTION 6,EX$(RND(4))
430 RETRY
440 END IF
450 END HANDLER