例えば、
『移動しているSpriteの画像をマウスでクリックできたら、その移動を止める』
とか、
『スプライトがある位置に移動したら異なるアクションをする』
、またシューティングゲームなどに使うの衝突検出
などの処理で使える機能です。
画面に表示するSpriteは、SprateTreadオブジェクトのインスタンス変数
subSpriteのArrayListで管理されています。
subSpriteの定義位置はスーパークラスのSpriteクラスなので、そこに作るのがよいでしょう。
しかし、Spriteクラスは汎用のクラスなので、ある作品に特化した仕様で作るわけにはいきません。
将来の指針となるメソッドだけを作るべきクラスだからです。
そこで、任意検索に対応できるように
別途に探すデータとフィットしたか調べるメソッドのインターフェイスを作り、
それを利用した検索メソッドにします。
Spriteクラスに追加する予定の検索メソッド名は、getFitSpritesと決めます。
仕様としては、subSpriteの中から、「ある比較で適合」するオブジェクトを抽出して、
その配列を返すことにします。
そしてインターフェイスに、この「ある比較で適合」判定をfitWithメソッドの名前で
用意します。
このインターフェイスの名前は、単純にSpriteFitInterfaceとして、次のように作りました。
SpriteFitInterface.java
// Spriteの検索メソッドgetFitSprites用インターフェイス(SpriteFitInterface.java) package sprite; interface SpriteFitInterface { //objとargの情報で、objが探すものに適合したらtrue public boolean fitWith(Sprite obj, T arg);//objが適合したらtrue }
次に、これを利用した次のgetFitSpritesメソッドを、Spriteクラスに追加します。
検索は単純な線形探索ですが、後方から適合したオブジェクトを探して、
戻る時に配列で返します。
なお、後方から探索する理由は、各オブジェクトの描画順が前からになっているので、
後の方が、より前面の画像となり、前面に見える画像のオブジェクトから探すためです。
Spriteクラスに追加するコードを以下に示します。
(←チェックでGenericコードになります)最終的版はGenericを使っています。
Sprite.javaのSpriteクラスに追加する部分コード
//subSpriteの可変長配列から、argの付随情報でobjと合致するSprite群を返す。 public <T> Sprite [] getFitSprites(SpriteFitInterface<T> obj, T arg){ ArrayList <Sprite> lst = new ArrayList <Sprite>();//適合オブジェクト記憶用 for(int i = this.subSprite.size()-1; i >= 0; i--){ Sprite sprite = this.subSprite.get(i); if( obj.fitWith( sprite , arg) ){//適合したら追加 lst.add( sprite ); } } Sprite []t = new Sprite[0]; return lst.toArray(t);//配列にして返す。 }
次に、これを利用する「座標に位置するするSpriteオブジェクト」を探すメソッドを、
searchの名前で、SpriteBasicクラスに作ります。以下にそのコードを示します。
SpriteBasic.javaのSpriteBasicクラスに追加する部分コード
public Sprite [] search(int x, int y){//subSprite内より、引数の座標(x,y)に位置するSprite群を返す。
Point pt = new Point(x,y);
SpriteFitInterface<Point> fitObj = new SpriteFitInterface <Point>() {
public boolean fitWith(Sprite obj, Point p){//インターフェイスの実装メソッド
ImageObserver observer = null;
if(obj.parent instanceof SpriteThread){
observer = ((SpriteThread)obj.parent).targetComponent;
}
Dimension size = obj.getSize(observer);
Point pt = new Point((int)obj.x, (int)obj.y);
Rectangle rect = new Rectangle(pt, size);
return rect.contains(p);//座標が長方形エリア内ならtrue
}
};//----SpriteFitInterfaceインターフェイスを継承した匿名クラスの定義範囲
return getFitSprites(fitObj, pt);// fitObjに適合するsubSprite内オブジェクトを返す
}
当然ですが、SpriteFitInterfaceインターフェイスを実装したクラスを作らなければ使えません。
引数の座標(x,y)が探索対象のイメージサイズ内にあるかを判定する機能を、
SpriteFitInterfaceインターフェース実装クラスとしています。
上記では、その実装クラスを、匿名クラスとして作っています。
しかしこの名前のないクラス(匿名クラス)は、コンストラクタで引数を持つことができません。
つまり、座標(x,y)の情報を引数で渡せません。
そこで使うのがfitWithメソッド第2引数のです。
内部的にはObject型なので、座標(x,y)でも任意情報も渡せます。
(上記のsearchは、SpriteFitInterfaceインターフェースの利用例とも言えるコードです。
インターフェイスを匿名クラスで実装し、それを引数にしてSpriteのgetFitSpritesメソッドを使っています。)