Home > Tags > Win32猫

Win32猫

徘徊アプリの動作骨組(2)

●状態クラスの例(待機状態)


状態クラスの例として,「徘徊を中断させているとき」に対応する状態の実装方法を示します.
この状態は,



  • ポップアップメニューで「箱入り猫」を選択されたらこの状態になる
  • 「猫が箱に入った画像」が表示される
  • 徘徊しない(ほっとくと,ずっと同じ場所)
  • マウスドラッグで移動させることができる

ものとします.


InBoxMenuポップアップメニューから状態変更.


InBox箱入り猫画像.
本当は「*はこのなかにいる*」まで描きたいのだが短縮系.足りない「にいる」については脳内補間で対応.





●OnCreate()


CDMManagerがこのクラスのオブジェクトを作ったときに呼びます.
猫ウィンドウクラスに箱入り猫のアニメーションを登録するだけです.(コード省略)





●OnSelect()


状態変更時に(CDMManager::ChangeState()内から)呼びます.
状態クラスはここで,猫ウィンドウに対して,自分用のアニメーションを選択させます.
また,その他の必要な設定(ポップアップメニュー項目のEnable,Disableとか)を行います.
箱入り猫状態では,ポップアップメニュー項目の「箱入り猫」項目にチェックをいれたりします.

void CDMState_InBox::OnSelect( CCatWnd *pCatWnd, class CDMManager *pManager )
{
 pCatWnd->SetBltMode( CCatWnd::BLT_NORMAL );//アニメーションを普通に描画する
 pCatWnd->EnablePopupMenuItem( MENU_ID_INBOX, true );//メニュー項目を有効に
 pCatWnd->CheckPopupMenuItem( MENU_ID_INBOX, true );//メニュー項目にチェックを入れる

 pCatWnd->SetCurAnimFrame( ANIM_ID_INBOX, 0 );//箱入り猫なアニメーションを選択する
}

CCatWnd::SetBltMode()は,画像を反転表示させたりするための設定用関数です.
(左右向き分の画像を用意するのが面倒なので::StretchBlt()で反転表示.)





●OnPreChangeAnimFrame()


アニメーションの切り替わり時の処理ですが,箱入り猫状態では,特にすることがないのでオーバーロードしません.
(デフォルト動作で,アニメーションがループ)





●OnPopupMenu()


ポップアップメニューへの対応です.
選択された項目が「箱入り猫」だった場合,この状態を抜けて「徘徊」状態に移行させます.

bool CDMState_InBox::OnPopupMenu( CCatWnd *pCatWnd, class CDMManager *pManager, UINT ItemID )
{
 return pManager->ChangeState( pCatWnd, ANIM_ID_WALKA );//徘徊状態に切換え
}

「箱入り猫」メニュー項目のチェックを外したりするのは,徘徊状態クラス側のOnSelect()の仕事にしているので,単純に状態切換えをするだけです.





●OnOtherEvent()


その他のメッセージへの対応処理です.
箱入り猫状態では,ドラッグによる移動を可能にするためのコードを記述します.
コードは省略しますが,WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE で普通に処理しています.


なお,この処理のためにマウスキャプチャを行う必要に迫られ,既に「CCatWndにHWNDを返すメソッドを追加したくて仕方が無い」精神状態に追いやられています.





●動作骨組みはこれだけ.


個々の状態での処理は少しずつ異なるだけ(他の状態への遷移の条件等が違う)なので,ひとつ作れば増やすのは(コードのコピーとちょっとした修正で済むので)楽です.
CDMManagerクラスが状態クラスのメンバを適切なタイミングで呼ぶ部分ができているので,徘徊アプリケーションが動作する骨組み自体はほぼ出来上がりです.
一番の問題は,


 状態(アニメパターン)を増やすためにはアニメーションの絵を描かなければならない


ということです.
あと,猫にカーソルを合わせると砂時計カーソルになる原因不明の現象が発生中.誰か助けて!


タスクトレイに猫入れる

  • Comments (Close): 0
  • Trackbacks (Close): 0

徘徊アプリの動作骨組(1)

●黒猫徘徊アプリの実装


前回,CCatWndクラスの大枠部分の実装ができました.
開発目標である「黒猫徘徊」部分の実装を,CCatWndManagerの派生クラスを作って実装していきます.





●猫の状態で場合分け


CCatWndには複数のアニメーションパターンを登録できます.
当然,現在のアニメーション選択状況によって,やりたいことが変わってきます.
例えば,



  • アプリ起動時には特定のアニメーションで猫が出現.
  • 徘徊時はウィンドウ位置を都度動かす必要がある.
  • 徘徊中止状態も欲しい…

等です.そのような処理分岐の記述が,圧倒的な長さを誇るif elseif… またはswitch case case… みたいなことになっていると,コードを見た瞬間に個人的に萎えるので,
「アニメーションパターン毎に状態クラスを用意」しておいて,これを切り替えることで猫の状態を遷移させることにします.
世間では「Stateパターン」とか呼ぶかもしれません.
猫状態の基本クラスを用意し,各状態クラスを派生させて作ります.基本クラスは↓のようなものです.

//DesktopMascotState
class CDMState
{
public:
 virtual ~CDMState(){}

public:
 virtual bool OnCreate( CCatWnd *pCatWnd ) = 0;

 virtual void OnSelect( CCatWnd *pCatWnd, class CDMManager *pManager ) = 0;

 virtual bool OnPreChangeAnimFrame( CCatWnd *pCatWnd, class CDMManager *pManager, unsigned int AnimID, unsigned int FrameIndex ){ return true; }
 virtual bool OnPopupMenu( CCatWnd *pCatWnd, class CDMManager *pManager, UINT ItemID ){ return false; }

 virtual bool OnOtherEvent( CCatWnd *pCatWnd, class CDMManager *pManager, UINT message, WPARAM wParam, LPARAM lParam ){ return false; }
};

徘徊アプリで状態毎に異なる処理が必要そうなタイミングに呼ぶための処理関数群が宣言されています.宣言順に上から



  • 初期処理用(アニメーションの登録等)
  • 状態選択されたとき用(アニメーションの切換え等)
  • フレーム切り替わり時用(アニメーションが1周したら他の状態に移行とか)
  • ポップアップメニューのイベントに対する処理用
  • その他のメッセージ処理用

といった感じです.
(コードを書き忘れるとアニメーション切換えが起らなくなってしまう類のメソッドを純粋仮想関数にしてあります.)





●CCatWndManager派生クラスの実装


CCatWndManagerから派生させたクラスには,以下のように…

class CDMManager : public CCatWndManager
{
public:
 bool ChangeState( CCatWnd *pCatWnd, unsigned int indx );//m_CurStateIndexを書き換える

private:
 unsigned int m_CurStateIndex;//現在の状態を選択するための値
 std::vector< CDMState * > m_StatePool;//状態群.インスタンス生成時あたりで状態群をつくって保持しておく.
 bool IsValidStateIndex( unsigned int indx ) const { return ( indx < m_StatePool.size() ); }
 CDMState *GetCurState(){ return m_StatePool.at( m_CurStateIndex ); }
};

状態クラス群を保持していて,必要なタイミングでChangeState()で切り替えて使用します.
あとは適切なタイミングで


 GetCurState()->XXX();


として今の状態クラスに処理を任せるようにしておけばOK.
例えば,フレーム画像変更時の処理は,

//フレーム変更直前時
bool CDMManager::OnPreChangeAnimFrame( class CCatWnd *pCatWnd, unsigned int AnimID, unsigned int FrameIndex )
{
 if( IsValidStateIndex(m_CurStateIndex) )
 {
  return GetCurState()->OnPreChangeAnimFrame( pCatWnd, this, AnimID, FrameIndex );
 }
 else
 {
  return true;
 }
}

として,現在の状態クラスに処理を投げるだけです.

徘徊アプリの動作骨組(2)

  • Comments (Close): 0
  • Trackbacks (Close): 0

Home > Tags > Win32猫

Search
Feeds
Meta

Return to page top