プチコン3号 9日目 アニメーションとタッチパネルを使う

SmileBASICで特徴的なのが、スプライトのアニメーション機能です。
画像を切り替えてアニメーションするだけでなく、スケーリングや位置の変更も指定できます。

付属サンプルの8番目「技術デモ」を見ると、いろいろな機能を概観できます。
このサンプルのソースコードは以下のリンクに掲載されており、参考になります。

プチコン3号 – プログラムリスト

アニメーションの指定自体は、BGMと同様に、一度パラメータを設定するだけで、あとは何もしなくても勝手に進行していきます。

pc9-1.jpg

上のようにダイレクトモードで指定しただけで、アニメーションは勝手に動き続けます。
ここではSPANIM命令で、0番のスプライトのキャラ番号を
 2772(15フレーム)→2773(15フレーム)2774(15フレーム)2775(15フレーム)
と切り替えて、1秒で一周するようにしています。
最後のパラメータ「,0」は、このアニメーションを無限ループする指定です。

今回は、このアニメーション機能を使って、
「タッチパネルにタッチすると、その位置へキャラクタが歩いていく」
というプログラムを作ってみました。

ただ、このプログラム・・・今回は、うまく動作しない場合があります。
もしかするとプチコン3号のバグか、あるいはマニュアルに書かれていない仕様があるのかもしれません。
スマイルツール等を起動した後だと、画面に何も表示されないことがあります。
ACLSコマンドを実行しても変化が無いので、こういう場合はプチコン3号をいったん終了させてください。

プログラムは以下です。

pc9-2.jpg
XSCREEN 2,255,2
DISPLAY 1 'DISPLAY 0
GX=184:GY=104:GC=2764
C=GC+4:C_OLD=GC
SPSET 0,C
SPSCALE 0,2,2
@LOOP
SPOFS 0,GX,GY
IF C != C_OLD THEN
SPANIM 0,"I",15,C+1,15,C+2,15,C+3,15,C,0
C_OLD = C
ENDIF
IF MAINCNT MOD 12 ==0 THEN TOUCH OUT T,X,Y
IF T > 0 THEN
  DX=SGN(X-GX):DY=SGN(Y-GY)
GX=GX+DX:GY=GY+DY
ON (DY>=0)*(DX+2) GOTO @N,@W,@S,@E
@N:C=GC+12:GOTO @DONE
@W:C=GC+8 :GOTO @DONE
@S:C=GC+4 :GOTO @DONE
@E:C=GC+0 :GOTO @DONE
@DONE
  'C=(3-(DY>=0)*(DX+2))*4+GC
SPSTART 255 'SPSTART 0
ELSE
SPSTOP 255 'SPSTOP 0
ENDIF
VSYNC 1
GOTO @LOOP

まずタッチパネル側をディスプレイとして使用するため、XSCREENコマンドとDISPLAYコマンドを使います。
XSCREENのパラメータは、「モード,上画面で使うスプライト数,上画面で使うBG数」です。
スプライトは512枚、BGは4枚を、上画面と下画面で分け合って使います。
このプログラムはスプライトの半分の255枚を上画面に割り当てています。

DISPLAY命令は使用するディスプレイが上なら0、下なら1です。
ここで、コメントで

‘DISPLAY 0

と入れましたが、実はここが0か1かで、この後のプログラムの動作が異なってしまいます。
表示されるディスプレイが異なるだけのはずなのですが・・・

3行目、GXとGYはスプライトを表示する座標、GCはアニメーションに使うキャラクタのうち最小のものです。
今回は、
・2764~2767:右向き歩行
・2768~2771:下向き歩行
・2772~2775:左向き歩行
・2776~2779:上向き歩行
の、4組16種のキャラクターを使います。

4行目、CとC_OLDは現在の向きに応じたキャラクタ番号(の最小のもの)です。
向きが変化したかどうかを判定するため、直前の状態をC_OLDに保持しています。

9行目からのIF文が、その判定処理です。
CがC_OLDと異なる場合、SPANIM命令を実行し、新しいアニメーションを設定します。

13行目からは、タッチパネルの入力処理です。
ここはループの中で毎回実行するのではなく、12回に1回(1秒間に5回)だけ実行しています。
こうすることで、キャラクタの向きが頻繁に変化しすぎて絵がちらつくのを少し防いでいます。

タッチパネルの読み出しは

TOUCH OUT T,X,Y

です。X,Yはもちろん座標です。
Tは、タッチ開始時点で0で、タッチが続いている限り1ずつ増加していきます。
これによって時間軸とX,Yという3次元の情報を取れます。

そのあとの処理は、ややトリッキーです。
やりたいことは
・タッチされたポイント(X,Y)とスプライトの現在位置(GX,GY)の大小関係を見て
・(GX+DX,GY+DY)が(X,Y)に近づくように(DX,DY)を決める(DX,DYはそれぞれ-1,0,1のいずれか)
・(DX,DY)が表す向きに応じて、キャラクタ番号Cを決める
という処理になります。

関数SGN(x)はxの正、負、0に応じて1、-1、0を返します。これを使って

DX=SGN(X-GX):DY=SGN(Y-GY)

として上記の1点目、2点目は解決です。

DX、DYはそれぞれ3状態あるので、組み合わせは9つの状態があります。
しかしキャラクタは今回は4方向しか用意できませんので、9つの状態と4方向の対応付けは下図の左のように決めました。
そして、4つの方向は図右のような番号に対応させています。

pc9-3.jpg

この対応付けを17行目の

(DY>=0)*(DX+2)

で行っています。
「(DY>=0)」という式は、DYが負のとき0、DYが0以上のとき1になります。
この式で、図右のような結果が得られることは計算してみると分かると思います。

ON~GOTO文で、4つの方向に応じてジャンプしています。
ジャンプ先で、アニメーションに使用するキャラクタ番号をCに代入しています。
ラベルは東西南北(North,West,South,East)を表しています。

なお、今回はON~GOTO文を使いましたが、23行目のコメントにあるように

C=(3-(DY>=0)*(DX+2))*4+GC

とすれば、このON~GOTO文と同じ結果が1行で得られます。

このあと、「タッチしているときだけアニメーションさせる」ために、SPSTARTとSPSTOPを呼んでいます。
実はこの部分が、最初のほうで書いた「DISPLAYのパラメータが0か1かで動作が異なる部分」です。

アニメーションするスプライトは、5行目で指定したとおり0番なのですが、SPSTART/SPSTOPでは「255番」のスプライトを指定しています。
DISPLAYが0のときは、SPSTART 0で思ったとおりの動作をします。
DISPLAYが1のときは、どうも「SPSETで指定したスプライト管理番号+XSCREENで指定した上画面のスプライト数」が、SPSTART・SPSTOPでのスプライト管理番号になるようです。
ちょっと納得の行かない仕様ですので、もしかしたらプチコン3号のバグかもしれません。

コメント