以下で、ライブラリの基本的な構造を説明しています。
(細部で最新版と異なる部分があります。)
アニメーションの基本は、スレッドで次のような移動の繰り返しを行う形になります。
このスレッド内の描画繰り返しを
管理するクラス名を、SpriteThreadと決めます。
前述の流れ図において、素材群と書いていますが、
その各素材の基本となるクラス名を、Spriteと決めます。
(Spriteの直訳は妖精ですが、昔からコンピュータのイメージパターンを表現する用語でよく使われます)
Spriteクラスにおいて、
素材を描画する時に使うイメージの取得する方法や、
アクションの仕方は、未来の利用者によって決まることなのでこのクラス作成時点に決めることはできません。
よって、その機能のメソッドは宣言だけにします。
インターフェイスで作る方法もありますが、
ここでは基本的な情報を持たせるので抽象クラスにします。
理想的に必要な情報は、描画イメージ、位置(左上座標)、横と縦の拡大縮小率、角度、中心座標、不透明度、可視状態
などが上げられます。
最初は必要最小限の描画イメージ(image)と、
位置(左上座標:x,y)だけで作成します。
そして、これら情報を操作するメソッドを検討します。
また、Spriteクラスの構造ですが、自身が素材であると同時に、
他の素材を複数管理できるような構造にします。
例えば「地球と月」のアニメーションを作る時、
地球のSpriteオブジェクトと月のSpriteオブジェクトで、
「地球と月」のSpriteオブジェクトを作ります。
他の素材を複数管理できる構造であれば、できた「地球と月」のSpriteオブジェクトと
太陽のSpriteオブジェクトで、
簡単に『太陽の周りを回る「地球と月」』のSpriteオブジェクトを作ることができるでしょう。
それはSpriteクラスの中でSpriteクラスの集合を管理する形態です。
それにはArrayListを使います。そして、それに対する追加メソッドを作ります。
なお、このような構造で作る時、addを行うのSpriteオブジェクトが親、
追加する方のSpriteオブジェクトが子供と捉えられるような階層構造ができます。
例えば、「地球と月」Spriteオブジェクトが親で、
地球のSpriteオブジェクトと月のSpriteオブジェクトが子供という関係です。
この場合、例えば子である月のSpriteオブジェクトのアクションで、
親の「地球と月」を操作したい場合があります。
その場合を想定して、
Spriteクラスの中に親のSpriteオブジェクト(parent)を管理させます。
なお基本はアニメーションの元になるイメージを管理するクラスなので、
これに関するメソッドを用意します。イメージサイズの指定や取得メソッドです。
以上より基本的なSpriteクラスの構造は、次のようになります。
Sprite |
---|
親のSpriteオブジェクト→parent 描画イメージ→image 位置:左上座標→x,y 自身が管理する素材群→ArrayList<Sprite> subSprite |
描画イメージの取得abstractメソッド→getImage() アクションのabstractメソッド→ action() 追加メソッド→add(Sprite sprite) イメージを指定するコンストラクタ イメージサイズを指定するコンストラクタ |
実際のコンポネントへの描画を行うのは、SpriteThreadクラスです。
ここでは、描画対象のコンポネントを管理します。アニメーションのためスレッドを作り、
そこでSpriteをコンポネントに描画するわけです。
以下で、SpriteThreadとSpriteの関係をイメージ化しました。
このように考えると、構造的にSpriteThreadは、
Spriteの継承で作れることがわかります。
ただし、Spriteは抽象クラスなので、
その宣言だけのabstractメソッド実体を作らなければなりません。
(Spriteの抽象クラスは、
これから継承して作るであろうクラスの指針となるクラスです。)
そこで、直接にSpriteThreadで作ってもよいのですが、
よく使われるabstractメソッドの実装クラスを作り、
それを継承した方がよいでしょう。
このよく使われそうなabstractメソッド実装クラス名をSpriteBasicと決めます。
この前提でSpriteThreadの作るコードを検討すると、
描画処理とそのスレッド管理を実現するためのものとなります。
その描画対象は様々な部品で可能にするためJComponentクラスとします。
JComponentオブジェクトの描画処理は、
paintComponentメソッド内に書く必要があります。
そこで、paintComponentメソッド内で使う描画メソッドを用意します。
またpaintComponentを呼び出す(repaint)用スレッド、アクションスレッドも管理します。
SpriteThread(Runnable実装のpriteBasic継承クラス) |
---|
描画先コンポネント→targetComponent スレッド→thread スレッドを制御するフラグ→loopFlag actionを実行させる間隔(ミリ秒)→animationInterval |
イメージサイズと描画先を指定するコンストラクタ 描画対象に描画するメソッド→ paintTo(Graphics g) 描画とアクションのスレッド→run() アクション間隔を引数にスレッドをスタートするメソッド→start(int msec) スレッドの停止メソッド→stop() |
SpriteBasicで、Spriteの抽象メソッド
(getImageとaction)を実装します。
getImageの描画済みのメモリイメージ取得メソッドで
AffineTransformのインスタンス変数transを使いますが、
左上座標(x,y)に移動grawImageで描画するためのtrans設定専用メソッドも用意します。
SpriteBasicクラス(Sprite継承クラス) |
---|
イメージを指定するコンストラクタ イメージサイズを指定するコンストラクタ 描画イメージの取得abstractメソッドの実装→getImage() アクションのabstractメソッドの実装→ action() |
各クラス図を示すと、次のようなクラス構造図になります。
まず、Spriteが全体の指針となる抽象クラスです。
これを継承して、一般的使い方を実装したSpriteBasicがあります。
これに、Spriteの抽象メソッドを実装します。
そしてこのSpriteBasicを継承し、
コンポーネントへの描画と、アクションのスレッドを持ったたSpriteThreadが
あるという構造です。
なお、ここでSpriteAは、テスト用のクラスです。
実際に使う作品の素材を作る場合はSpriteAのように、
すでに抽象メソッド実装済みのSpriteBasicを継承することで
簡単に作成できるようにするわけです。
またSpriteBasicと異なる描画イメージを作りたい場合は、直接にSpriteを継承すればよいわけです。