OPAS応用編2
スクロールとアニメーションの同時使用
応用編1ではOPASは複数の領域を書き換えることで多重スクロールが可能ということと1つの領域の書き換えでも一定量の多ライン同時スクロールが可能ということを書いたのですが、今度はさらにその応用となります。OPASにおいては1領域の書き換えではアニメーションとスクロールの排他使用しかできませんでしたが、アニメーションしながらスクロールという処理も可能なのです。
原理は単純で必要なアニメパターン数の背景をあらかじめ用意しておいて異なるパターンから取り出す部分を変更するだけです。パターン1→パターン2→パターン3と切り替えることでアニメーション表示ができなおかつドット単位で取り出す場所を変えることでドット単位のスクロールができるというだけです。
BFB66h〜BFC65の256バイトがパターン1、BFC66hからの256バイトがパターン・・・という感じで8パターンのアニメーションさせながらスクロールさせる場合は下記のようになります。
《 画面幅60ドット×1ラインでアニメーションさせながらスクロールする場合 》
※1ターンごとにアニメーションする場合
背景パターン1
| BFB66h | BFB6Eh | BFB76h | ・・・・・・ | BFBA1h | BFBA9h | BFBB1h |
1ターン目 | | | | | | | |
9ターン目 | | | | | | | |
17ターン目 | | | | | | | |
背景パターン2
| BFC66h | BFC67h | BFC6Fh | BFC77h | ・・・・・・ | BFCA2h | BFCA9h | BFCB2h |
2ターン目 | | | | | | | | |
10ターン目 | | | | | | | | |
18ターン目 | | | | | | | | |
背景パターン3
| BFD66h | BFD67h | BFD68h | BFD70h | BFD78h | ・・・・・・ | BFDA3h | BFDAAh | BFDB3h |
3ターン目 | | | | | | | | | |
11ターン目 | | | | | | | | | |
19ターン目 | | | | | | | | | |
背景パターン4
| BFE66h | BFE67h | BFE68h | BFE69h | BFE71h | BFE79h | ・・・・・・ | BFEA4h | BFEABh | BFEB4h |
4ターン目 | | | | | | | | | | |
12ターン目 | | | | | | | | | | |
20ターン目 | | | | | | | | | | |
※背景パターン5〜8は省略
リスト1 スクロールしながらアニメーションさせるサンプルプログラム
10 CLS :OPEN "SCRN:"FOR OUTPUT AS #1:Q=0:FOR P=0TO 195
20 POKE &BFC93,P,(Q AND 7)+243,11:LOCATE 0,0:PRINT #1,"アイウエオカキクケコサシスセソ"
30 Q=Q+0.5:NEXT :END
40 *SET A=&BF366:FOR I=0TO 7:Z=RND -1:FOR J=A TO A+254STEP 2:POKE J,0,2^(RND 8-1):NEXT
50 FOR J=A TO A+253:B=RND 8+I AND 7:IF B>4THEN B=8-B
60 B=2^B:POKE J,6*B,13*B,15*B,6*B:J=J+RND 7+4:NEXT :A=A+256:NEXT :GOTO 10
|
《 注意 》
あらかじめマシン語エリアとしてBF266h以降の2202バイトを確保しておいてください。
実行前にRUN *SETでデータ作成をしてください。データ作成には1分弱かかります。
1ラインのみのスクロールですが、単純なスクロールではなくアニメーションしながらスクロールしているというのが分かると思います。30行のQ=Q+0.5がアニメーションの速度であり、0.5の値を変えることでスクロール速度に影響を与えることなくアニメーション速度だけを変えることができます。(つまり、スクロール処理とアニメーション処理は独立している)
これを使ってマリオタイプの横スクロールのゲームを作ればドット単位でスクロールさせつつ画面内で空中ブランコやエレベータなどの動くオブジェクトが大量にあっても速度をほとんど落とすことなく動作させることが可能になります。
ただし、スクロールとアニメーションを同時使用すると飛躍的にデータが膨れあがります。
上記のリストを見てのようにスクロール256バイト分のデータ×アニメーションのパターンが8通りということで2048バイト分のデータとなっています。そもそも、OPASは無圧縮のグラフィックデータをメモリ上にあらかじめ展開しておくことで高速描画を実現しているのでデータ効率があまり良くありません。したがって、パターン数が増えればそれに比例して合計データ量も増えてしまいます。
あるキャラがパターン数4、あるキャラがパターン数6、あるキャラがパターン8でアニメーションする場合は4と6と8の最小公倍数である24パターンのアニメーションとしてデータを記録する必要があるからです。1パターンにつき256バイトであればその24倍ということで6KBになります。しかも、これは表示の横幅が60ドットの場合、スクロール範囲196ドット、1ラインのデータ量です。
これではあまりに効率が悪いためスクロールとアニメーションの同時使用をする場合は最もパターン数が多いキャラのパターン数の約数になるようにした方が良いでしょう。パターン数が最大のキャラが6の場合においては2、3、6のパターン数でアニメーションさせるとむやみにデータ量が増えずにすみます。
OPAS基本の復習で書いたようにOPASにおけるスクロールとアニメーションの違いは全く違うものを表示するのか否か(言い換えれば少しずつ位置をずらしているように見えればスクロールでそうでないならばアニメーション)ということなのでしたがそれをシームレスに行うことで上記のように同時に行うことが可能ということが分かったと思います。
応用編1-(3)では1領域書き換えるだけで多ライン同時スクロールをさせる方法を書きました。カナにおいては64文字(384バイト)制限によって表示枠が横60ドット×2ラインの場合は264ドット分しか最大でスクロールさせることができませんでしたが、このアニメーションと同時使用によってそれは無制限になります。
要は264バイト単位で別パターン扱いにするわけです。
パターン1、パターン2、パターン3・・・とリアルタイムで切り替えていけばスクロールしながらアニメーションが実現できるというのは分かったと思うのですがその背景のデータにおいてパターン1のスクロール終了画面、パターン2のスクロール開始画面を一致させることでシームレスにパターン1とパターン2を繋ぐことが可能になります。
《 画面幅60ドット×2ラインでスクロールする場合 》
1ライン目
| BF600h | BF601h | ・・・ | BF63Bh | BF63Ch | ・・・ | BF708h | ・・・ | BF743h | ・・・ | BF900h | ・・・ | BF93Bh |
1ターン目 | 背景パターン1 | | | | | | | | | | | | |
2ターン目 | | | | | | | | | | | | | |
(中略) | | | | | | | | | | | | | |
265ターン目 | | | | | | | | | | | | | |
266ターン目 | | | | | | | | | | | 背景パターン2 | | |
2ライン目
| BF744h | BF745h | ・・・ | BF77Fh | BF780h | ・・・ | BF84Ch | ・・・ | BF887h | ・・・ | BFA44h | ・・・ | BFA7Fh |
1ターン目 | 背景パターン1 | | | | | | | | | | | | |
2ターン目 | | | | | | | | | | | | | |
(中略) | | | | | | | | | | | | | |
265ターン目 | | | | | | | | | | | | | |
266ターン目 | | | | | | | | | | | 背景パターン2 | | |
《 メモリマップ 》
BF000h〜BF5FFh | グラフィックデータ作成用ワークエリア
60(表示枠)+264(パターン1スクロール用)+264(パターン2スクロール用)の588バイト その2ライン分(1176バイト)+空き領域 |
背景パターン1 |
BF600h〜BF63Bh | 1ライン目の開始時のグラフィックデータ格納場所 |
BF63Ch〜BF743h | 1ライン目のスクロール用のグラフィックデータ |
BF744h〜BF77Fh | 2ライン目の開始時のグラフィックデータ格納場所 |
BF780h〜BF887h | 2ライン目のスクロール用のグラフィックデータ |
背景パターン2 |
BF900h〜BF93Bh | 1ライン目の開始時のグラフィックデータ格納場所 |
BF93Ch〜BFA43h | 1ライン目のスクロール用のグラフィックデータ |
BFA44h〜BFA7Fh | 2ライン目の開始時のグラフィックデータ格納場所 |
BFA80h〜BFB87h | 2ライン目のスクロール用のグラフィックデータ |
リスト2 64文字(384バイト)制限を超えるスクロール
10 CLS :CLEAR :OPEN "SCRN:"FOR OUTPUT AS #1:A$=A$+31:FOR I=0TO 9:A$=A$+CHR$ 29:B$=B$+CHR$ (160+I):C$=C$+CHR$ (214+I):NEXT :Z$=B$+A$+C$
20 A=&7900:FORJ=0TO 1:FOR I=A TO A+264
30 POKE &BFC93,I AND 255,I/256+128,11:LOCATE 0,0:PRINT #1,Z$:NEXT :A=A+769:NEXT:END
40 *SET FOR J=0TO 1:Z=&BF000+J*600:FOR I=Z TO Z+588:POKE I,0:NEXT :FOR I=Z TO Z+588:I=I+RND 9+4:Y=2^(RND 5-1):POKE I,6*Y,13*Y,15*Y,6*Y:NEXT
50 FOR I=0TO 580STEP 20:POKE Z+I,255:NEXT :X=&BF600+J*324:FOR I=0TO 1:FOR H=0TO 324:POKE X+H,PEEK (Z+H):NEXT:X=X+768Z=Z+264:NEXT :NEXT:GOTO 10
|
《 注意 》
あらかじめマシン語エリアとしてBF000h以降の3072バイトを確保しておいてください。
実行前にRUN *SETでデータ作成をしてください。データ作成には約30秒かかります。
このサンプルでは264ドット×2の528ドット分スクロール可能になっていますがその場合1ラインあたり588バイト、2ラインの合計では1176バイトのデータ量になります。その2ライン分のデータを最初にBF000hからのワークエリアに作成していてそれを元に324バイト×2に分解しています。このように重なりあう部分を持つデータを複数パターン用意しておけば64文字(384バイト)の制限があってもメモリの許す限り横スクロールが可能になります。
またカナだけの書き換えにおいて3ライン同時スクロールでは102ドットしかスクロールできませんでしたが、この方法を使えばそれも緩和できます。ただし、102ドットあたり162バイトのデータが必要になります。3ライン同時なので必要データ量はその3倍となります。
同様にカナだけで4ライン同時スクロールも無理ではありません。しかし、48ドットあたり108バイトのデータが必要になってきます。4ライン同時であるため必要なデータはその4倍となります。カナの書き換えだけで288ドット分の4ライン同時スクロールを行うためには108×(288÷48)×4=1732バイトのデータが必要になってくるわけです。
この方法を使えば64文字(384バイト)制限があっても1領域(カナ)の書き換えだけで多ライン同時スクロールを制限なしに行うことが可能になるとはいえ、上記のように同時スクロールのライン数が増えるにしたがってメモリ効率は悪くなります。メモリ効率を重視して384バイト制限を超える4ライン同時スクロールを行う場合は20h〜7Fhを除いた3領域を書き換え、カナ(A0h〜DFh)は2ライン分を賄うという方法を取るのがベターかもしれません。
OPASが本来対応していない縦スクロールも工夫次第では可能になります。縦スクロールはアニメーション機能を応用すれば良いというだけですからね。ただし、1ドットずつずらしたデータ(1ドット分シフトしたデータ)をあらかじめ用意しておく必要があるためデータ量が非常に多くなります。
例えば、表示エリアが60ドット×4ライン(60×32ドット)でスクロール全体画面が60×63 ドットの場合は縦方向に31ドットスクロール可能になりますが、その場合において60×32の表示エリア(240バイト)の32倍(7680バイト)のデータが必要になります。(下記の(a)の方法)。しかし、それとは別の方法もあります。
それは、PRINT+フォント書き換えで1ドット単位のキャラ移動をする場合と似たような方法です。要は縦に1ドットずつずらしたデータを8種用意し、8ドットスクロールさせるごとに表示位置を変えることで断続的な縦スクロールが可能になるのです。(下記の(b)の方法)
この方法は上記(2)の方法の応用ともいえるかもしれません。
《 画面幅60ドット×4ラインで縦スクロールする場合 》
(a)縦スクロールさせるドット数分の全パターンを用意した場合
(※使用メモリ 1パターン240バイト×32パターン=7680バイト)
メモリマップ
BDE00h〜BDEEFh | 1ターン目の表示データ ※1つあたり240バイト |
BDEF0h〜BDFDFh | 2ターン目の表示データ |
(略) | |
BFB10h〜BFBFFh | 32ターン目の表示データ |
(b)1ドットずつずらした全体データを8パターン用意した場合
(※使用メモリ 1パターン420バイト×8パターン=3360バイト)
64-8=56ドット(=7ライン) 60バイト×7ライン=420バイト
メモリマップ1
BEEE0h〜BF083h | パターン1のグラフィックデータ ※1つあたり420バイト |
BF084h〜BF227h | パターン2のグラフィックデータ |
BF228h〜BF3CBh | パターン3のグラフィックデータ |
BF3CCh〜BF56Fh | パターン4のグラフィックデータ |
BF570h〜BF713h | パターン5のグラフィックデータ |
BF714h〜BF8B7h | パターン6のグラフィックデータ |
BF8B8h〜BFA5Bh | パターン7のグラフィックデータ |
BFA5Ch〜BFBFFh | パターン8のグラフィックデータ |
メモリマップ2
BEEE0h〜BEFCFh | 1ターン目の表示データ |
BF084h〜BF173h | 2ターン目の表示データ |
BF228h〜BF317h | 3ターン目の表示データ |
BF3CCh〜BF4BBh | 4ターン目の表示データ |
BF570h〜BF65Fh | 5ターン目の表示データ |
BF714h〜BF803h | 6ターン目の表示データ |
BF8B8h〜BF9A7h | 7ターン目の表示データ |
BFA5Ch〜BF69Bh | 8ターン目の表示データ |
BEF1Ch〜BF00Bh | 9ターン目の表示データ |
BF0C0h〜BF1AFh | 10ターン目の表示データ |
(略) | |
BEF58h〜BF047h | 17ターン目の表示データ |
(略) | |
BEF94h〜BF083h | 25ターン目の表示データ |
(略) | |
BFB10h〜BFBFFh | 32ターン目の表示データ |
メモリマップ2の解説
1ターン〜8ターン | グラフィックパターンを1つずつ変えていく ※アドレスに420(1A4h)プラスする |
9ターン | 1ターン目より1ライン分だけ変える ※アドレスに60(3Ch)プラスする |
10ターン〜16ターン | グラフィックパターンを1つずつ変えていく ※アドレスに420(1A4h)プラスする |
17ターン | 9ターン目より1ライン分だけ変える ※アドレスに60(3Ch)プラスする |
18ターン〜24ターン | グラフィックパターンを1つずつ変えていく ※アドレスに420(1A4h)プラスする |
25ターン | 17ターン目より1ライン分だけ変える ※アドレスに60(3Ch)プラスする |
26ターン〜32ターン | グラフィックパターンを1つずつ変えていく ※アドレスに420(1A4h)プラスする |
非常に複雑に見えますがFOR〜NEXTを使えば単純であることが分かるでしょう。
FOR A=0 TO 3:FOR B=0 TO 7:ADD=&BEEE0+A*60+B*420:NEXT :NEXT
変数ADD(表示データの開始アドレス)
(a)(b)2種類の方法を用意しましたが(a)の方は単純というメリットがあり(b)の方はデータ量を少なくできるというメリットがあります。表示エリアが縦に広い場合やその広さに対してスクロール量の割合が多いほど(b)の方法はメモリが節約できますが、表示エリアが縦8ドットの場合は(a)(b)に差はないので単純な(a)を選択するメリットが大きいでしょう。
今回は表示エリアが縦32ドットであるため(b)の方法を使ったサンプルプログラムを用意しました。(a)の方は単純なアニメーションであるため基本編を理解していれば簡単に作れると思います。
リスト3 縦スクロール サンプルプログラム
10 CLS :CLEAR :OPEN "SCRN:"FOR OUTPUT AS #1
20 FOR I=0TO 3:FOR J=0TO 7:A=28282+I*60+J*420:POKE &BFC93,A AND 255,A/256+128,11
30 LOCATE 0,0:PRINT #1,"アイウエオカキクケコ↓← ←←←←←←←←←サシスセソタチツテト↓←←←←←←←←←←ナニヌネノハヒフヘホ↓←←←←←←←←←←マミムメモヤユヨラリ":NEXT :NEXT:END
40 *SET Z=&BED00:FOR I=Z TO Z+479:POKE I,0:NEXT :FOR I=Z TO Z+479:I=I+RND 9+4:Y=2^(RND 5-1):POKE I,6*Y,13*Y,15*Y,6*Y:NEXT
50 X=&BEEE0:FOR I=0TO 419:POKE X+I,PEEK (Z+I):NEXT
60 FOR I=1TO 7:Y=2^-I:FOR J=0TO 419:POKE X+I*420+J,PEEK (Z+J)*Y+PEEK (Z+J+60)*Y*256AND 255:NEXT :NEXT :GOTO 10
|
《 注意 》
あらかじめマシン語エリアとしてBED00h以降の3840バイトを確保しておいてください。
実行前にRUN *SETでデータ作成をしてください。データ作成には2分弱かかります。
分かりにくいと思われる部分だけ解説しておきます。
まずは、20行の28282の意味です。
グラフィックデータの書き込み開始アドレスであるBEEE0hの上位部分を取ったEEE0h(61152)においてANDでアドレス演算を行うため一時的に8000h(32768)マイナスし、カナ表示においてA0hからではなく「ア」(B1h)から表示しているため開始アドレスが102バイトずれるため61152-32768-102=28282となります。
あとBED00h〜BEEDFhの480バイトは60ドット×64ドットの全体データとなっています。これをベースに1ドットずつ縦にずらした8パターンをBEEE0hから順に書き込んでいます。
これを実行すればスムーズに縦スクロールしていることが分かるでしょう。
縦スクロールは横スクロールの併用さらにアニメーションの併用ができます。ただし、横スクロールのデータには60文字(384バイト)制限があるためにそれを超える場合は(2)の方法を使ったり複数領域の書き換えが必要になります。
またアニメーションを利用する場合は縦スクロールだけで8パターンとなっているため4パターンのアニメーションを加えるだけで全体では32パターンに達してしまいます。仮に1パターン128ドット×64ドットであってもデータサイズは1KBになるため32パターンではグラフィックデータだけで32KBになります。
したがって、縦スクロールは可能とはいえ、横スクロールほどの利便性はなくどうしても必要な場合のみ使用すると良いかもしれません。
OPASを使用すれば工夫次第ではいくらでも凝った表現は可能になります。しかも表示速度もGPRINTよりは格段に速いのでいいことだらけとはいえ凝れば凝るほどそれに比例してメモリが必要になるため凝ったことをやろうとすればメモリはいくらあっても足りません。
基本編はあくまでOPASの使用方法のごく一部でありこの応用編ではそれを応用することで様々なことができるようになるということだけ分かって貰えれば良いのではないかと思っています。使うか使わないかは自由ですが、OPASの基本編で書いたように選択肢が増えるということだけでも有用ですからね。
基本編をマスターしそして今回の応用編をマスターすることで選択肢が増えるということはOPASが有効活用できるシーンも多くなりさらにOPASが便利になっていくということを意味します。
OPAS応用編1 多ライン同時スクロール
(1) OPASの基本の復習
(2) 多重スクロールの原理
(3) 1領域で多ライン同時スクロール
OPAS応用編2 スクロールとアニメーションの同時使用
(1) 1領域でスクロールさせながらアニメーション表示
(2) スクロールの制限を無くす
(3) 縦スクロール
RETURN