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:

  • "n" (north, észak) fel
  • "s" (south, dél) le
  • "e" (east, kelet) jobbra
  • "w" (west, nyugat) balra
  • "ne" jobbra fel
  • "nw" balra fel
  • "se" jobbra le
  • "sw" balra le
  • "" nincs mozgás

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
Az EnterSPRITE végül is kezdetnek nem rossz, de még sokat lehet csiszolni rajta. De vajon van-e valaki, aki hajlandó erre?