GO BACK

REALbasic教室 その8


「スプライトでアニメーションする」


■スプライトの考え方


 今回は、滑らかなアニメーションを実現するのに不可欠な「スプライト」について説明しましょう。

 スプライトというのは図形を高速表示するために考え出された機能のことです。通常、画面にグラフィックを表示してアニメーションをするのはかなり大変なのです。グラフィックと背景を合成したグラフィックを作りこれを転送して表示し、移動するときはそれを元に戻してから新たな移動先の背景とグラフィックを合成したものを作って転送し…と、かなり面倒な作業が必要となります。また同じグラフィックをいくつも表示させるとなると、処理は何倍も面倒になります。

 REALbasicでも、Canvasなどを使ってグラフィックを表示し、これをTimerなどで動かそうとしても、グラフィックがちらついて表示されたりしてなかなかなめらかなアニメーションができない、という経験をした人も多いことでしょう。

 スプライトは、あらかじめグラフィックを登録しておけば、それをいくらでも画面上に呼び出して表示できる機能です。キャラクタと背景の合成など自動的にやってくれるので、いちいちきれいに合成するプログラムなど書く必要もありません。またアニメーションする際、次の表示位置などを指定するだけで自動的にアニメーションが表示できるなどの機能も組み込まれています。

 このスプライト機能を使うための部品が「SpriteSurface」というものです。といっても、これ自体はスプライトではありません。これは、スプライトを自由に動かすための「舞台」となる部品です。

 REALbasicでは、このスプライトサーフェスとスプライトの2つの部品によってスプライトアニメーションが実現されます。スプライトサーフェスは、表示するスプライトを組み込んだり、スプライトアニメーションの速度を調整したり、次にスプライトを表示する際の表示位置を設定したりといった、舞台の設定を行ないます。

 では実際に表示するスプライトはどの部品なのか?というと、これは実はツールパレットには用意されていません。スプライトは、プログラムの中で作成して使う部品なのです。ですから、スプライトサーフェスにどのようにスプライトを組み込んで使うか、その基本手順を知っていないとスプライトはうまく使えないのです。

 では、スプライト利用の基本について整理しておきましょう。


1.表示するグラフィックを用意する。
2.スプライトサーフェスを用意する。
3.ボタンなどスプライトアニメーションを実行するための部品を用意し、そこにスプライトを作成してスプライトサーフェスに組み込む命令を用意する。
4.スプライトサーフェスに、スプライトを移動するためのプログラムを用意する。


 こんな感じになります。1と2はわかりますね? 重要なのは3と4です。スプライトアニメーションを行なうには、スプライトを作成して組み込むプログラムと、スプライトを動かすプログラムを最低でも用意しておかなければいけないのです。



■スプライトサーフェスの設定


 では、実際に簡単なスプライトアニメーションを作ってみましょう。まず、表示するグラフィックを1つ用意します。ここでは「UFO」という名前のグラフィックを作成し、ドラッグ&ドロップでプロジェクトに組み込んでみました。

 次にスプライトサーフェスの作成です。SpriteSurfaceを1つウィンドウ内に作成し、プロパティを設定します。スプライトサーフェスにはいくつかの重要なプロパティがあります。

 まず「Backdrop」というのがありますが、これはアニメーションの背景となるグラフィックを設定するためのものです。ここではとりあえずOFFにしておきますが(何も設定しないと黒バックになります)、背景にグラフィックを表示したい場合は、グラフィックをプロジェクトに取り込み、このBackdropに設定すればよいのです。

 もう一つ、「Frame」というものもあります。これはアニメーションの表示速度を設定するためのものです。スプライトアニメーションでは、スプライトの位置を設定してから画面を更新し、またスプライトを移動してから画面更新し、また…というように、スプライトの移動と画面更新を繰り返してアニメーションします。この「スプライトの移動」は、後述しますが「NextFrame」というサブルーチンで行なわれます。つまり、スプライトアニメーションがスタートすると、REALbasicはエンドレスでNextFrameイベントをスプライトサーフェスに送り続けます。ここでスプライトの処理をしてアニメーションさせるわけですね。

 このFrameプロパティは、NextFrameが何回呼び出されたら画面を更新するかを設定するものです。これを1にすれば、毎回画面更新されるので、滑らかなアニメーションになります。ただし画面表示はかなりCPUに負担のかかる作業ですから、遅いマシンではかなりつらいでしょう。5に設定すると、NextFrame5回に1回画面が更新されますから、アニメーションは多少ぎこちなくなりますが遅いマシンでも比較的快適に表示されるようになります。



■スプライト作成とユーザー定義プロパティ


 では、スプライトアニメーションをスタートするボタンを作りましょう。CommandButtonを1つウィンドウに作り、そこにソースコードを記述します。

Sub Action()
  SP = SpriteSurface1.newSprite(UFO,100,100)
  SP.Group = 1
  SpriteSurface1.Run
End Sub

 これでスプライトの組み込みとアニメーションスタートのプログラムはできました。が、実はこれだけでは動きません。実行させようとするとエラーが出るはずです。この他に、「ユーザー定義プロパティ」というのを作る必要があります。

 説明は後で行なうとして、まず作ってしまいましょう。まずコードブラウザウィンドウを開き、「Edit」メニューから「New Properties...」というのを選んで下さい。画面にダイアログが現れます。そこに、

SP As Sprite

――このように記述してOKして下さい。コードブラウザの一番下の「Properties」という項目の中に、「SP As Sprite」という項目が付け加えられるはずです。

 このユーザー定義プロパティというのは、このウィンドウ内の全サブルーチンから利用可能な値/オブジェクトです。サブルーチン内の変数というのは、サブルーチンが終わると消えてしまい、他のサブルーチンで利用したりできませんね。そこで、このユーザー定義プロパティを利用するのです。ここで設定したものは、変数やオブジェクトと同様のものとして全てのサブルーチンで使えるようになります。

 このプロパティの書き方は、変数定義などと非常に似ています。すなわち、

《プロパティ名》 As 《変数型/オブジェクトの種類》

――このようにすると、その種類の変数/オブジェクトとしてプロパティが用意されるのです。ここでは「SP As Sprite」としていますから、Spriteオブジェクトとして使えるSPプロパティを用意した、というわけです。

 REALbasicでは、このように変数だけでなくオブジェクトも変数と同じ感覚で使うことができます。ちょっと不思議な感じがするでしょうが、こうしてプロパティを用意し、ここにスプライトを入れてやれば、このSPというスプライトはどのサブルーチンからでも利用できるようになるのです。

 さて、肝心のコードの説明に進みましょう。ここでは、まずこんな命令を実行していますね。

SP = SpriteSurface1.newSprite(UFO,100,100)

この「newSprite」というのが、新しいスプライトを作成してスプライトサーフェスに組み込む命令です。これは、以下のような形で記述します。

《スプライトサーフェス》.newSprite(《グラフィック》,《横位置》,《縦位置》)

 この命令を実行すると、作成されたスプライトが返されます。ここで、このコードでは返されたスプライトをSPに設定しているというわけですね。

SP.Group = 1

 次の行は、できあがったスプライト(SP)のプロパティを設定しているものです。この「Group」というのは、スプライトのグループ分けをするためのものです。

 スプライトサーフェスには、スプライト同士の衝突を調べる機能があります。このGroupプロパティでグループの番号を設定しておくと、同じグループのスプライト同士が重なったときは、衝突を検出しないようになります。まあ、このGroupは実際に衝突を使ったプログラムを作るまではあまり考えなくてもよいでしょう。

SpriteSurface1.Run

 これが、スプライトアニメーションをスタートする命令です。このRun命令で、そのスプライトサーフェスを舞台としたアニメーションが実行されるわけです。



■スプライトの移動


 では、作成したアニメーションを動かしてみましょう。プログラムを実行し、ボタンを押すと、画面が真っ黒になり、左上にUFOのグラフィックが表示されるはずです。が、ただ表示されるだけで全く動かないですね? それを確認したら、クリックして下さい。スプライトアニメーションは、クリックすると自動的に終了します。

 なぜアニメーションは動かなかったのか。これは「まだ動きを設定する機能を組み込んでいないから」です。先に触れたように、スプライトアニメーションがスタートすると、REALbasicはエンドレスでスプライトサーフェスの「NextFrame」サブルーチンを呼び出しつづけるようになります。ですから、このサブルーチンに、スプライトの表示位置を変更するような命令を書いておけば、スプライトが動くようになるのです。

Sub NextFrame()
  SP.x = SP.x + 1
End Sub

 これが簡単なサンプルです。このように記述してから、もう一度プログラムを実行してスプライトをスタートしてみて下さい。今度はUFOが左から右へとなめらかに動くはずです。どうです、ちゃんとアニメーションしましたか?

 ここでやっていたのは、スプライトのxというプロパティを1増やすというだけのことです。スプライトにはいくつかのプロパティが用意されています。主なものをまとめておきましょう。


「x」――スプライトの横位置。数字で設定
「y」――スプライトの縦位置。これも数字で設定
「Group」――スプライトのグループ。数字で設定
「Image」――表示するグラフィック。グラフィックで設定


 つまり、NextFrameでスプライトのxとyを変更すれば、次に画面更新されたときにスプライトが移動しているというわけです。実に単純な仕掛けですね。

 また、Imageを利用すれば複数のグラフィックをぱたぱたと切り替えてアニメーションさせることもできます。そうすれば更にリアルなアニメーションがになりますね。

 これで、とりあえずスプライトを作り、アニメーションを実際に動かす基本がわかったことと思います。単にアニメーションを動かすだけなら、それほど難しくはないですね?



■キーボードによる移動


 では、スプライトを自由に動かしたいという場合はどうすればいいのでしょうか。まず頭に入れておくことは「アニメーション表示中はマウスは使えない」ということです。マウスは「クリックしたら終了」という機能がスプライトサーフェスに組み込み済みとなっていますから、ユーザーは利用できません。となると、キーボードで動かすということになります。

 スプライトサーフェスには、「押しているキーを検知する」という機能があります。これは「keyTest」というものです。これは指定のキーが押されているかどうかを調べるもので、押されていればTrue、押されていなければFalseを返します。

《スプライトサーフェス》.keyTest(《キーコード》)

 このようにして利用します。パラメータの《キーコード》というのは、それぞれのキーに割り当てられているコード番号のことです。コンピュータでは、全てのキーに番号が割り振られており、プログラミングの世界ではその番号で押されているキーを検知するようになっているのです。

 例として、i,j,k,lでスプライトを上下左右に動かすように、NextFrameを修正してみましょう。

Sub NextFrame()
  if SpriteSurface1.keyTest(34) then    
    SP.y = SP.y - 1
  end if
  if SpriteSurface1.keyTest(38) then 
    SP.x = SP.x - 1
  end if
  if SpriteSurface1.keyTest(40) then 
    SP.y = SP.y + 1
  end if
  if SpriteSurface1.keyTest(37) then 
    SP.x = SP.x + 1
  end if
End Sub

 こんな感じですね。キーボードのi,j,k,lキーのキーコードは、それぞれ34,38,40,37となります。ifを使ってそれぞれのキーについて1つずつkeyTestを調べ、それによってSPのxとyの値を変更しているというわけです。

 このようにすると、一度に1つのキーを押した処理も行なえるようになります。例えばこの例では、iを押すと上に、jを押すと左にスプライトは移動するようになっていますが、iとjを両方押せば、左斜め上へとスプライトは移動してくれます。同時に複数のキーを検知して動かせるというのは、プログラムの幅が広がりますね。



■スプライトの衝突検知


 最後に、スプライト同士が重なった場合の「衝突検知」についても説明しておきましょう。これはスプライトサーフェスに用意されている「Collision」というサブルーチンを利用します。スプライト同士が接触すると、REALbasicはCollisionイベントを発生させ、スプライトサーフェスのサブルーチンを呼び出すのです。

 このサブルーチンには、2つのパラメータがありますね。s1とs2で、いずれもスプライトです。つまり衝突した2つのスプライトがここに入れて送られてくるわけですね。ですから、この2つのプロパティなどを変更することで、衝突したときに変化するアニメーションが作れるわけです。

 では、簡単に衝突するアニメーションのサンプルを作ってみましょう。まず、「New Properties..」メニューを選んで、もう一つスプライトのプロパティを作っておきます。定義は「SP2 As Sprite」としてください。これでSP2というスプライトが用意されます。

 次に、スプライト実行のボタンのコードを修正する必要があります。これは以下のようになるでしょう。

Sub Action()
  SP = SpriteSurface1.newSprite(UFO,100,100)
  SP.Group = 1
  SP2 = SpriteSurface1.newSprite(UFO,300,200)
  SP2.Group = 2
  SpriteSurface1.Run
End Sub

 見ればわかるように、SPとSP2にそれぞれ新しいスプライトを割り付けていますね。2つのGroupが1と2に設定されています。同じGroup同士は衝突は検知されないので、別々の番号にしておく必要があるのです。

 後は、スプライトサーフェスのCollisionサブルーチンを書き加えるだけです。

Sub Collision(s1 As Sprite, s2 As Sprite)
  s1.x = 100
  s2.y = 100
End Sub

 これで完成! プログラムを実行してスプライトアニメーションを動かしてみて下さい。キーボードで1つのUFOを動かし、もう一つのUFOと衝突すると、その瞬間にUFOは左上にジャンプしてしまいます。ちゃんと衝突してスプライトが変化していることがわかりますね?


◆    ◆    ◆


 ざっと説明してきましたが、スプライトを使えば簡単にアニメーションが作れることはわかったことと思います。が、同時に、スプライトの限界も見えてきたかも知れません。現状のスプライトではマウスが使えませんし、画面も全て黒くなり、一定領域内だけしか使えません。ウィンドウ中心のREALbasicのプログラムの中では違和感のある表示です。もう少し機能強化され柔軟な表示ができるようになって欲しいものです。

 が、ともかくも滑らかなキャラクタアニメーションができ、キーボードを使えばインタラクティブな操作もできる。簡単なゲームなども作れてしまいますから、ビジュアル派のプログラマには必須の機能といえるでしょう。


GO NEXT


GO HOME