スプライトの考え方


ゲームなどのプログラムでは、背景の上にキャラクタが重なって表示され、それがぐりぐりと動いている、というようなことをよくやっています。こうした「キャラクタを動かす」という処理はどうやっているのでしょう。

まず、誰もが思いつくのは、「キャラクタのImageをインスタンス変数などで保持し、その描画位置を変更しながら描きなおす」ということでしょう。毎回、背景を描いて、その上にキャラクタを描く、という処理を行っていけば、キャラクタの位置を自由に動かすことはできそうですね。

ただし、このやり方は、キャラクタの数が増えてくるとかなり煩雑になってきます。すべてのImageと、それを表示する場所をあらかじめ変数などで用意しておき、描画の際にそれを使って描いていくわけですから。もう少しすっきりとしたやりかたはないのか?と誰しも感じることでしょう。

また、こうしたキャラクタ利用のプログラムでは、ただ表示するだけで済むことは稀です。多くの場合、「衝突判定」というものが必要になります。これは、2つのキャラクタが衝突(接触)したかどうかを調べるものです。こうしたことまで手作業ですべて計算しないといけないとなると、これは少々やっかいですね。

こうした「キャラクタの表示と操作」を行うとき、非常に便利な機能がDoJaには用意されてます。それが「スプライト」と呼ばれるものです。とりあえず、実際に簡単なサンプルを動かしてみましょう。まず、表示するキャラクタのイメージ(縦横50ドットの大きさ、「char.gif」というファイル名)を、iappliToolプロジェクトの「res」フォルダに入れてください。そして以下のようにソースコードを作成しましょう。

import com.nttdocomo.ui.*;

public class SampleIApp extends IApplication {

  public void start() {
    Display.setCurrent((Frame)(new MainCanvas()));
  }

}

class MainCanvas extends Canvas {
  Image charImg;
  Sprite[] sprites;
  SpriteSet set;

  MainCanvas() {
    setSoftLabel(SOFT_KEY_1, "END");
    setBackground(Graphics.getColorOfName(Graphics.WHITE));
    try {
      MediaImage mi = MediaManager.getImage("resource:///char.gif");
      mi.use();
      charImg = mi.getImage();
      sprites = new Sprite[2];
      sprites[0] = new Sprite(charImg);
      sprites[1] = new Sprite(charImg);
      sprites[0].setLocation(50,50);
      sprites[1].setLocation(100,100);
      set = new SpriteSet(sprites);
    }catch(Exception e){}
  }

  public void paint(Graphics g) {
    g.lock();
    g.clearRect(0, 0, Display.getWidth(), Display.getHeight());
    g.drawSpriteSet(set);
    g.unlock(true);
  }

  public void processEvent(int type, int param) {
    switch(type){
    case Display.KEY_RELEASED_EVENT:
      int x = sprites[0].getX();
      int y = sprites[0].getY();
      switch(param){
      case Display.KEY_SOFT1:
        (IApplication.getCurrentApp()).terminate();
        break;
      case Display.KEY_UP:
        sprites[0].setLocation(x,y - 10);
        break;
      case Display.KEY_DOWN:
        sprites[0].setLocation(x,y + 10);
        break;
      case Display.KEY_LEFT:
        sprites[0].setLocation(x - 10,y);
        break;
      case Display.KEY_RIGHT:
        sprites[0].setLocation(x + 10,y);
        break;
      }
      repaint();
    }
  }

}