終電帰りがデフォになりつつある…
とはいっても土日は休ませてもらえるのでまだラッキーなほうでしょうか…
この2週間くらいは先輩にフルボッコにされる日々でした…
自分のコードの粗がバンバン指摘され「なんで面倒なつくりにするんだこの野郎!ハゲ!死ね!」的な感じで、ね。
※ハゲとか死ねとかは言われてません
タスクシステムといいますかなんというか
一つ一つのタスクが独立したつくりでなければいけない、その一方で変化があった時のトリガーがほしい時もあれば
個々に各々演技をさせる必要もあり…
じゃあそのタイミングってどうやって手に入れるの?って話になり、私はこれに結構悩まされました。
クラスのインスタンスをstaticなポインタに渡して外に公開するという愚行を働き結果的にめちゃめちゃ怒られました。
その方法論はどうしたらいいもんか…
というときに所謂「親子階層」を作ってしまうというわけですね。
一つ一つのタスクを管理する親タスクがあって、仮にParentTaskとしましょうか…
// 子タスク
// 使い捨てなのでヘッダーには公開しない
class Child1 : public Task{
protected :
void update(){}
};
class Child2 : public Task{
protected :
void update(){}
};
class Child3 : public Task{
protected :
void update(){}
};
// シーケンス
class Scene{
private :
ParentTask parent; // これは何にもなりうる。UIレイアウトのコントロールとか。
public :
void setup()
{
// ParentTaskの中にはリンクリストのChildが存在する。そこにタスクを積むということ
parent.entryChild( new Child1() );
parent.entryChild( new Child2() );
parent.entryChild( new Child3() );
}
};
全員独立していて各々がupdateを処理します。
じゃあなにか命令があったらどうするの?というのが問題点。
親タスクには実は自身が持つ子タスク達に一斉にコールバックを呼ばせる仕組みが用意されます。
たとえば...
// 子タスク
// 使い捨てなのでヘッダーには公開しない
class Child1 : public Task{
protected :
virtual void update(){}
virtual void command( int param )
{
if( param == CMD_SND_01 )
{
playSound( "SE_1" );
}
}
};
class Child2 : public Task{
protected :
void update(){}
virtual void command( int param )
{
if( param == CMD_SND_02 )
{
playSound( "SE_2" );
}
}
};
class Child3 : public Task{
protected :
void update(){}
virtual void command( int param )
{
if( param == CMD_SND_03 )
{
playSound( "SE_3" );
}
}
};
// シーケンス
class Scene{
private :
ParentTask parent; // これは何にもなりうる。UIレイアウトのコントロールとか。
public :
void setup()
{
// ParentTaskの中にはリンクリストのChildが存在する。そこにタスクを積むということ
parent.entryChild( new Child1() );
parent.entryChild( new Child2() );
parent.entryChild( new Child3() );
parent.commandToChilds( CMD_SND_01 );
}
};
守秘義務の関係上すべて私が日記を書きながら即興で考えた名前です。ライブラリもこれっていうものは考えてません。
commandToChildsは子タスク達にコマンドを送ります。
こいつらはイテレーターで反復処理され、command()メソッドがそれぞれ呼ばれます。
たとえば音声01を再生したいならCMD_SND_01をパラメータにしてあげれば、
それを受け取ったタスクが「じゃあ音声ならすわ!」といって音声を鳴らしてくれます。
反応するのはChild1クラスのcommandです。
それ以外は無視されます。
コマンドには引数すら必要ないこともあります。
あくまでもこれはトリガーなのであって、トリガーが立った時に親が公開しているパラメーターを見に行ったって問題はありません。
公開したいデータだけstaticにしてしまう。
親となるクラスだけでstaticを管理すれば比較的管理も楽です。外のクラスからは参照しかできないようにすれば良い
セットしたいのであれば要検討となりますが、どのみち窓口を作ればさまざまな事象に対応しやすそうです。
これはあくまでも一例ですが、
たとえばゲームのメニュー画面とか、STGならスコア画面やゲームボードなどの所謂UI絡みは
一つの「レイアウトクラス」としてのタスクリストで制御するとわかりやすい。
たとえば、ある位置にカーソルが指定された
指定されない画像は半透明にしてカーソル番号が一致した画像だけ普通に表示する。
というのは
void update()
{
if( Scene::getCursorIndex() == m_MyCursorNumber ){
setAlpha( 255 );
return;
}
setAlpha( 128 );
}
あとは各々が判断して透明になったりならなかったりしてくれます。
選択画面では街頭する項目にカーソルを合わせたら基本的に決定キーを押します。
押されたらUIがどっかに飛んでいくと非常に格好いいです。
ボタンが押されたタイミングでparentがchildたちに「動け!」とコマンドを送ると、
それぞれ動いてくれそうな感じがしますね。
void Child1::command( int param )
{
if( param == CMD_MOVE ){
vect.x = 10;
}
}
void Child2::command( int param )
{
if( param == CMD_MOVE ){
vect.x = -10;
}
}
void Child3::command( int param )
{
if( param == CMD_MOVE ){
vect.x = 10;
vect.y = 10;
}
}
void Child4::command( int param )
{
if( param == CMD_MOVE ){
vect.x = -10;
vect.y = 10;
}
}
こいつらは右に行ったり左に行ったりななめに行ったり個々にアクションします。
なんかそれだけで本格的なゲームっぽい演出が作れそうです。
つまりは情報を参照するときは「子は親の情報を頼りにする」
というのが望ましい。
逆に親が子の情報に依存するとたちまち崩壊してしまうと、つまりはそんな話なのですね。
そして公開範囲はなるべく限定的に。。。
そんなこんなのUIの操作の仕方を勉強の一週間でした。
まだまだ書きたいことは山ほどあるなぁ…