先日、MFCにてアクセラレータキーが場合によって効かなくなるという症状を書いたのですが、一応自己解決いたしましたので、報告します。
(解決案をくださったAOIさん、Thanx!)

そもそもの原因は「TranslateAccelerator」というAPIの仕様とMFCの相性が悪いことにあります。 TranslateAcceleratorはキー入力をメニューコマンドへ変換するAPIですが、メニュー状態が無効だったら変換(送信)しないという仕様になっています。そのため、 MFCのコマンド更新ハンドラで pCmdUI->Enable(TRUE); となっていても、メニュー状態が無効ならば、ショートカットキーは使えません(深い場所のメニューコマンドは)。

ちなみに浅いコマンドが効くようになったことについては、少し憶測ですが書いてみますね。 TranslateAcceleratorの仕様として、キー→メニューコマンド直前(?)に WM_INITMENUなどのメッセージを送信してきます。そのメッセージをMFCフレームワークが掴み、メニューコマンドを「コマンド更新ハンドラ」を使って更新し、最新の状態になるため、ショートカットが効いたのだと思われます。
(ルート直下のメニューコマンドしか更新しません)

さて、深い位置のメニューコマンドを効かせるために、まず思いつくのが、「メニュー状態を更新する」という方法です。しかしいつ更新してよいのかわかりません。毎回キー入力(またはTranslateAcceleratorが送信してくるWM_INITMENUなど)でメニューコマンド全ての状態を更新することは負荷となりパフォーマンスの低下に繋がることは目に見えています。

で、私が使用した解決方法は、以前ちょろっと書きましたが、アクセラレータ処理を「TranslateAccelerator」を使わず自前で実装するという事です。もともとEDGE2はショートカットキーのカスタマイズに対応しており、キーの設定をリソースではなく、通常のデータ(謎)として持っているため、WM_KEYDOWNやらWM_SYSKEYDOWNメッセージを捕まえて、メニューコマンドへ変換し、SendMessage(WM_COMMAND・・・);しています。幸い、MFCはコマンドを実行する直前でコマンドUI更新ハンドラを呼び出して、コマンドを実行可能か調べているため、例えば「実行出来ないはずのメニューコマンドを実行する」というような事も起こりません(コマンド更新ハンドラでEnable(FALSE)となっているとwarningはTRACEされますが^^;)。

現在公開しているEDGE2β版では既にこの方法で実装しています。今のところ問題も出ていませんので、おそらく大丈夫かと思われます。

(一応解決しました。)

最近はEDGE2の動作チェックなどをやっているのですが、また新たな不具合が発生しまして・・・、これがなかなか曲者でして、今まで気が付きませんでしたがなんとEDGE1でも再現します_| ̄|○・・・。

例によってシンプルなプロジェクトファイルと実行ファイルを用意しましたので、もし通りすがった方で良い解決策などをご存知の方がいらっしゃれば、私まで連絡をお願いいたします(という他力本願な日記です)。なお、興味のある方向けに実行ファイルも用意しました。

Visual C++ 6.0 プロジェクトファイル
実行ファイル

概要

今回の不具合は、アクセラレータキー(Ctrl+Zでアンドゥが効くような機構・・・ショートカットキーと呼ぶのが一般的?)が場合によって効かなくなるというものです。

再現手順

  1. 起動する
  2. 「↑(矢印)」キーが「浅い」というコマンドに割り当てられ、「↓」キーが「深い」というコマンドに割り当てられています。
    050414_00

    050414_01

    つまり、「↑」キーを押せば「浅い」が実行され、「↓」キーを押せば「深い」が実行されるというわけです。

  3. では試しに「↑」「↓」キーを押してみてください。
    どちらもコマンドが実行されるとメッセージボックスが表示され、「実行された」という事が目で見て解るようにしてあります。

    どちらのキーでも処理が実行されることを確認してみてください。
    050414_02

  4. ここで、ツールボタン「ONで有効」の凹んでる状態を解除します(OFFになります)
    050414_03

  5. すると、「浅い」や「深い」が無効状態になります(無効状態にしています)。

    メニューを表示し、各コマンドが両方とも使えなくなっていル事を確認してください(必須)
    050414_04

    050414_05

  6. さて、ここで「↑」「↓」キーを押してみてください。

    「浅い」や「深い」は使えない状態ですので、もちろん処理は実行されません。

  7. では、ツールボタン「ONで有効」をもう一度凹まし、ONの状態にしてください。

    050414_06

  8. これで内部的には「浅い」も「深い」も実行可能状態になります。
    (メニューは開かないでください。)

    このまま、「↑」「↓」キーを押してみてください。

    「浅い」は処理されますが、「深い」が処理されません。

    「浅い」位置にあるコマンド(ルートの直下)は使えるのに、
    「深い」位置にあるコマンド(サブメニュー?)は使えないのです。

    これが今回の不具合です。

  9. ちなみに、このあとメニューを開き、「深い」が有効状態になっているのを確認してから「↓」キーを押せば処理されるようになります。

EDGE1の場合・・・

EDGE1の場合は、矢印キーで選択範囲を移動する事が出来るのですが、
選択範囲が無い時点でメニューを見に行き、座標微調整コマンドが無効状態になっているのを確認してから、画像を選択し、矢印キーを押してみると、キーが効かなくなるという不具合が発生します。

考察

まだちょこっとしか調査していませんが、キーアクセラレータ機構については、キー入力系メッセージ(KEYDOWNとか)からTranslateAccelerator APIを通ってコマンド(WM_COMMAND)に変換されるようなのです。
その際にTranslateAcceleratorは、対応するメニューコマンドが無効だとコマンドを送信しない仕様らしいんです(MSDNの資料はこちら)。
だから、MFCのフレームワークで深い位置にあるメニューコマンド状態が更新されないのかなぁなどと推測しています(あんまりWindowsSDKとかメッセージ処理とか詳しくないのでどっかかん違いしていたらごめんなさい)。

仕様なのか不具合なのか、どちらにせよ、便利であるはずのライブラリに時間を取られるのだけは勘弁してほしいです(´・ω・`)ショボーン

#アクセラレータキー処理を自前でやれば問題無しかも?

#今回は矢印キーばかりでしたが、「Ctrl+A」のような感じのキーも同様です

土曜日に書いたツールバードッキングで嫌な感じ事件ですが、無事(?)に解決いたしました。

当初は闘う前から負けていた(だってドッキング部分はいろいろなサイトで難解と言われていましたから)のですが、きよのさんの協力もあってやる気が出まして(笑)、駄目元でデバッグをしていったところ、それっぽい原因を見つけ出すことができました。

折角ですので、VC6.0を使ってどうやって問題を解決したかなどを簡単に書き記しておこうと思います。

さてさて、ドッキングしているツールバーをドラッグ&ドロップした際、ドロップした位置より下側にずれてドッキングしていまう、というのが今回の不具合です(詳しくは12日の日記を参照してください)。

なんとなく「ドロップしたあとのツールバー位置を決める処理」に不具合があるんだろうなぁとは予想出来ましたので、その辺をさぐろうと思ったのですが、ソースを見るに当たってまずは大体どんなかんじでドッキングしたツールバーなどを管理しているのか、データ構造を探ることにしました(その方がソース見ていて解りやすくなると思いまして)。

もともとCToolBarやCStatusBarのヘルプを見たときに、それらがCControlBarというクラスから派生していたのを何度か目にしていたため、「きっとメインフレームがCControlBarの一覧を持ってるんだろう」という憶測はしていました。

早速、CMainFrameの親クラスを参照機能でたどって行くとCFrameWndというクラスに

CPtrList m_listControlBars;

という名前がそのままの変数を見つけました。

ためしに一つずつポインタを取得してみてGetWindowRectでウィンドウ座標を取り、その位置に四角形を描画してみたのですが、思ったとおり、全てのツールバーやステータスバーが格納されていました。

しかし実際にはそれだけでなく、謎のクラスCDockBarというクラス(これもCControlBarの派生クラス)が上下左右に1つずつ存在していました。どうやらこのCDockBarというのがツールバーのドッキングを受け入れるバーのようです(受け入れるバーと受け入れられるツールバーが同じリスト内に存在している、というのも不思議な気がしますが)。

050314_00

#ちなみにCDockBarのコンストラクタにブレークポイントを設定してみたところ、
 上下左右の4つだけでなく、ツールバーを浮かせた状態にした際にも生成されるようです。

CDockBarがドッキングを受け入れるバーならば、そのCDockBarがドッキングしているコントロールバーの座標を持っているんじゃないかと思い、さっそくソースを見ていったところ、

CPtrArray m_arrBars;    // each element is a CControlBar

という怪しいポインタ配列を見つけたので、例によって一つずつポインタを取得してみてGetWindowRectでウィンドウ座標を取り、その位置に四角形を描画してみましたが、またも思ったとおり、ドッキングされているツールバーなどが格納されていました。
ところが、中にはNULLという情報も含まれており、どういったルールでこの配列の中身が決まっているかが気になりました。

そこで、ツールバーのドッキング状態をいろいろ変えながらm_arrBarsがどのように変化するか試したところ、上の行から順番にコントロールバーのポインタが格納されており、NULLは「コントロールバーの改行」を意味するようでした。

つまり、
050314_01

↑このような状態では、

    m_arrBars[0] = NULL;
    m_arrBars[1] = ツールバー1のアドレス;
    m_arrBars[2] = NULL;
    m_arrBars[3] = ツールバー2のアドレス;
    m_arrBars[4] = NULL;
    m_arrBars[5] = ツールバー3のアドレス;
    m_arrBars[6] = NULL;

このような配列状態になり、

050314_02

↑このような状態では、

    m_arrBars[0] = NULL;
    m_arrBars[1] = ツールバー1のアドレス;
    m_arrBars[2] = ツールバー4のアドレス;
    m_arrBars[3] = NULL;
    m_arrBars[4] = ツールバー2のアドレス;
    m_arrBars[5] = NULL;
    m_arrBars[6] = ツールバー3のアドレス;
    m_arrBars[7] = NULL;

このような配列状態になりました。

「・・・ということは、ツールバーをドロップした際、この配列への挿入場所を導き出す処理がうまくいかず、こちらが期待する位置にツールバーが配置されず、下の段にドッキングしてしまうのではないか」、というような考えにいきつきました。

データ構造は大体解りましたので(?)ようやくここからドッキング部分のソースを追うことにします。

・・・どうやって追うのか?

10秒ぐらい悩みましたが、ドッキング後には、メインフレームのRecalLayoutが呼び出されると思い、ここにブレークポイントを設置し、実際にツールバーをドラッグ&ドロップしてみたところ、見事にひっかかりました。

050314_03

そこからコールスタックウィンドウを駆使して呼び出し元を辿り、
050314_04

CDockContext::EndDrag()という関数の最初の方でまたブレークポイントを設置し、また実行してドラッグ&ドロップして停止させて、今度はステップ実行でひとつずつ怪しいところが無いか見ていきました。

しばらく追っていき、
CDockContext::EndDrag() → CFrameWnd::DockControlBar() → CDockBar::DockControlBar() →CDockBar::Insert() この関数内で先に出た「CPtrArray m_arrBars;」というポインタ配列へバーを挿入している事が判明しました。

というわけでこの関数の先頭にブレークポイントを設定して、実行→ツールバーをドラッグ&ドロップ→ブレークポイントで停止させ、
今度は変数ウォッチに、この関数内で使用している変数を表示させ、変数の変化を見ながらステップ実行していきました。

このCDockBar::Insert()という関数、完璧に理解したわけではありませんが、
配列の先頭(=一番上のコントロールバー)から順番に座標を照らし合わせながら、
ドッキングしたいコントロールバーの「順番(配列番号)」を求め、ポインタを挿入している関数だと思われます。

int CDockBar::Insert(CControlBar* pBarIns, CRect rect, CPoint ptMid)
{
    ASSERT_VALID(this);
    ASSERT(pBarIns != NULL);

    int nPos = 0;
    int nPosInsAfter = 0;
    int nWidth = 0;
    int nTotalWidth = 0;
    BOOL bHorz = m_dwStyle & CBRS_ORIENT_HORZ;

    for (nPos = 0; nPos < m_arrBars.GetSize(); nPos++)
    {
        CControlBar* pBar = GetDockedControlBar(nPos);
        if (pBar != NULL && pBar->IsVisible())
        {
            CRect rectBar;
            pBar->GetWindowRect(&rectBar);
            ScreenToClient(&rectBar);
            nWidth = max(nWidth,
                bHorz ? rectBar.Size().cy : rectBar.Size().cx - 1);
            if (bHorz ? rect.left > rectBar.left : rect.top > rectBar.top)
                nPosInsAfter = nPos;
        }
        else // end of row because pBar == NULL
        {
            nTotalWidth += nWidth - afxData.cyBorder2;
            
            nWidth = 0;
            if ((bHorz ? ptMid.y : ptMid.x) < nTotalWidth)
            {
                if (nPos == 0) // first section
                    m_arrBars.InsertAt(nPosInsAfter+1, (CObject*)NULL);
                m_arrBars.InsertAt(nPosInsAfter+1, pBarIns);
                return nPosInsAfter+1;
            }
            nPosInsAfter = nPos;
        }
    }

    // create a new row
    m_arrBars.InsertAt(nPosInsAfter+1, (CObject*)NULL);
    m_arrBars.InsertAt(nPosInsAfter+1, pBarIns);

    return nPosInsAfter+1;
}

この関数でどんな処理が行われているか、私の解釈で簡単に説明しますと・・・

コントロールバーというのは種類によってバーの高さが異なりますので、行の中で一番高いサイズをnWidthという変数で記憶しておいて、改行(=NULL)または表示されていないバーが来たら「高さの合計」を示すnTotalWidth変数にnWidthを足す、というような処理が入っています。

この高さ合計と、ドッキングしたい場所のY座標(中央)を比較し、条件が合えばその位置にバーを挿入、というような感じです。

#垂直状態のドッキングも考慮しているとはいえ、何故「nWidth」という名前なのかはちょっとわかりません・・・

さて、デバッグ実行しているときに気が付いたのが、改行と表示されていないバーが連続で来たときなどに、

    nTotalWidth += nWidth - afxData.cyBorder2;

という処理が実行されると、nTotalWidthが減るという事です。

nWidthは0ですが、afxData.cyBorder2は0ではないため(2だったかな?)
改行&表示されていないバーが来るたびに
nTotalWidthの値がどんどん減っていきました。
 
 
・・・これってバグじゃないの?
 
 
 
この部分の不具合疑惑が浮上し、ここをなんとか書き換えて実行しようと思いました。
 
書き換えたい気持ちは山々なのですが、ここはMFCソース内部、変えるのが困難な部分です。

誰か変えた人いないの!?ってなかんじでぐぐってみましたが、ヒットせず_| ̄|○

しょうがないので自分でやることに(^^;
 
 
まず、CDockBar::Insertという関数はvirtual関数ではないため、オーバーライドさせることが出来ません。そんなわけで、virtual関数が出てくるまで呼び出し元をたどりました。

CDockContext::StartDrag(CPoint pt);
という関数が仮想関数であることがわかったため、
この関数からCDockBar::Insertまでのすべての呼び出し処理を変更すればCDockBar::Insert処理を別のものに変えられそうでした。

具体的には
CDockContext::StartDrag() → CDockContext::Track() → CDockContext::EndDrag() → CFrameWnd::DockControlBar() → CDockBar::DockControlBar() →CDockBar::Insert()
これら全ての関数を修正する必要があるという事です(´・ω・`)ショボーン

クラス別に見て

  • CDockContext
  • CFrameWnd
  • CDockBar

これら3つがありますで、これらから新たにクラスを派生させ、そこで別関数を用意すれば良いという事です。
(CFrameWndに関してはCMainFrameという関数がありますので、クラスを新しく用意する必要はありませんね。)

で、これらのクラスから新たに

CDockContext
→CMyDockContext
CDockBar
→CMyDockBar

というクラスを作るのはまぁ出来るだろうとは思うのですが、
いままでCDockContextクラスをnewしていた部分を今度はCMyDockContextクラスをnewさせるようにしないといけないわけで、それが出来るかどうかの実験から始めました。
 
 
CDockContextのコンストラクタにブレークポイントを設定して生成タイミングなどを調査した結果、
CControlBar::EnableDocking();関数内でnewされている事が解りました。

CToolBarから新たにクラスを派生させ、そこからEnableDocking()を作る、というのが普通かもしれませんが、
なにしろツールバー以外にもコントロールバーというのは多数ありますから(ダイアログバーなど)
少し汚い手ですが、

EnableDocking();させた後で全コントロールバーに対してメンバ変数m_pDockContextを見て、インスタンスあれば一旦deleteして、CMyDockContextをnewさせ、保持させておくという手段を用いました(爆

CDockBarの方はCFrameWnd::EnableDocking時に生成されるようでしたので、その関数のソースをそのままコピペしてnew CDockBar部分を書き換えました。

これでクラスのインスタンスをごっそり変える事が出来ましたので、
CMyDockContextや、CMyDockBarのメンバ変数をコピペしたりして
各関数を実装します。

CMyDockContext::StartDrag() → CMyDockContext::TrackDebug() → CMyDockContext::EndDragDebug() → CMainFrame::DockControlBarDebug() → CMyDockBar::DockControlBarDebug() →CMyDockBar::InsertDebug()

というように呼ばれるわけです。

CMyDockContext::EndDragDebug() → CMainFrame::DockControlBarDebug()
というように、クラスが異なる呼び出しの場合には、
呼び出す際の型キャストも必要です。

    CMainFrame* pMainFrame = dynamic_cast<CMainFrame*>(m_pDockSite);
    if (pMainFrame) {
        pMainFrame->DockControlBarDebug(m_pBar, pDockBar, &rect);
    }
    else {
        m_pDockSite->DockControlBar(m_pBar, pDockBar, &rect);
    }

こんな感じで最終的にCMyDockBar::InsertDebug()が呼ばれるようにし、
これでようやく・・・ようやくCDockBar::Insert部分をいじれるようになりました_| ̄|○

早速例の「高さの合計を示すnTotalWidth変数にnWidth足す」という部分に修正を試みます。

#if 1
            if (nWidth > 0) {
                nTotalWidth += nWidth - afxData.cyBorder2;
            }
#else
            nTotalWidth += nWidth - afxData.cyBorder2;
#endif

これで実行してみたところ、ドッキング不具合は発生しなくなりました!
 
 
・・・長かった。
 
 
そんなわけで治ったっぽいプロジェクトはこちらです。
今後同じような問題にぶちあたった人のお役に立てられれば幸いです・・・。
 
 
・・・Microsoftさん、貴重な休日を返して(T_T

EDGE2のツールバーカスタマイズ周りを実装中なんですが、
カスタマイズとは関係無い部分でおかしな部分が見つかりました_| ̄|○

もし解決策、回避策などが解る技術者の方がおられましたら、
私まで連絡をお願いします。

#Microsoftに質問メール送る方法が解らなかった_| ̄|○
 プロフェッショナルサポートとか契約してないとメールで質問出来ないのかな~?
 変わりにMSへ問い合わせてくれる人でも構いません(^^ゞ

症状1 ツールバードッキングで嫌な感じ (解決したかも?)

→問題部分のみを抽出したプロジェクトファイルはこちら(40KB)
(Visual C++6.0が必要です)
VisualC持ってないけど見てみたいという方はこちらをどうぞ。

プロジェクトの主な作成手順は次の通りです。

  1. ウィザードでMFC→MDIアプリケーションを作成(他の設定はそのまま)
  2. CMainFrame::OnCreateにて
    1. ツールバーを5個以上作成する
    2. 作成したツールバーで、最初の2個だけを残し、残りのツールバーをShowControlBar(・・・,FALSE, TRUE);で非表示する
    3. また、症状がわかり易くなるように、ここでダイアログバーを一つ作成しています。(無くても症状は発生します)
  3. ビルドし、実行します。

症状の再現方法は次の通りです。

  1. EXEを実行します。
    050312_00

    ツールバー5個中、2個が表示されています。
    050312_01

  2. 上のツールバーを、ダイアログバーの下へドラッグ&ドロップしてドッキングさせます。
    050312_02

    すると、普通にドッキングします。
    050312_03

  3. さて、ここでもう一つのツールバーを、さきほどのツールバーの横へドラッグ&ドロップしてドッキングさせようとすると・・・

    050312_04

    下にずれる。
    050312_05

これが嫌な症状です。
ちなみに、がんばると(ちょっとダイアログバーへめり込むようにドロップすると)、隣へドッキングさせることも出来るのですが、また少しずらそうとすると、一段下がった場所へ勝手に配置されてしまいます。

二つしかツールバーが無い程度ならばいいのですが、それが複数になって、隣へ配置出来なくなるのは、ツールとしての使い勝手が悪くなる要因ともなりかねませんので、解決したいところです。

ツールバーは5個中2のみ表示、と書きましたが、5個全て表示したり、最初から2個しか
作らなかった場合には、これらの症状は発生しません。

症状が発生しない期待通りの実行ファイルはこちら

MFC側の不具合のような気もするのですが、もしそうであっても直したい部分ではあります^^;

(20:00 追記)
きよのさんからメールを頂きまして(有難うございます!)
Visual C++ 6.0 Enterprise Edition SP6では症状が発生しないとの情報を頂きました。
ちなみに私の環境は
Visual C++ 6.0 Professional Edition SP6です。
MFCのソースが異なるんでしょうかね~_| ̄|○
もう少し追ってみます。

(20:24 追記)
と思ったらEnterprise Editionでも症状が確認されたようです(^^;
更にはVisual C++ .NET Professional 2003でも再現したそうです_| ̄|○

ツールバーの表示方法とか作成方法が間違ってるのかなぁ、と不安になってきました。

(3/13 0:55 追記)
解決したかも?明日解決方法などを紹介します。

あ、掲示板のSISTさんサンクス!
たしかにでにくくなってましたが、いろいろやっているうちに症状が再現してました。

症状2 ツールサイズ変更でアプリがフリーズ (解決しました!)

こちらはだいぶ解りやすい症状です^^;

→問題部分のみを抽出したプロジェクトファイルはこちら(40KB)
(Visual C++6.0が必要です)
VisualC持ってないけど見てみたいという方はこちらをどうぞ。

プロジェクトの主な作成手順は次の通りです。

  1. ウィザードでMFC→MDIアプリケーションを作成(他の設定はそのまま)
  2. CMainFrame::OnCreateにて、デフォルトで作成されたツールバーの状態をいじり、ドロップダウンボタンをいくつか追加する(2つぐらいあると症状が発生しやすい)
  3. ビルドし、実行します。

症状の再現方法は次の通りです。

  1. EXEを実行します。
  2. ツールバーをドラッグ&ドロップし、浮かせます(ドッキングを解除)
    050312_06

    050312_07

  3. あとは、その浮いたツールバーの上の部分を上へドラッグするとフリーズします。
    050312_08

ドロップダウンボタンが2つぐらい有ると起こる症状のようです。
フリーズ状態でVCのブレークを実行すると、CToolBar::SizeToolBarやらCToolBar::CalcSizeで無限ループに陥っているのかなぁ、というように思えます。
各関数にvirtualがついていないので、単純にオーバーライドして値をTRACEさせるという技も使えず^^;

こちらもMFC側の不具合のような気もするのですが、もしそうであっても直したい部分ではあります。

(追記)
CToolBar::CalcDynamicLayoutがvirtualになっていましたので、オーバーライドし、その中で使用されている関数などをMFCのソースからコピペ、問題を探ったところ、
CMyToolBar::SizeToolBarの中で無限ループに陥っていることが解りました。

無限ループにならないように、勝手にreturnしてみたのですが、これで良いのやら・・・
→修正後のプロジェクトファイルはこちら

        while (sizeMin.cx < sizeMax.cx)
        {
            sizeMid.cx = (sizeMin.cx + sizeMax.cx) / 2;
            WrapToolBar(pData, nCount, sizeMid.cx);
            sizeMid = CalcSize(pData, nCount);

// ここの判定分を追加してみた by takabo soft
#if 1
            if (sizeMax == sizeMid) {
                return;
            }
#endif

            if (nLength < sizeMid.cy)
            {
                if (sizeMin == sizeMid)
                {
                    WrapToolBar(pData, nCount, sizeMax.cx);
                    return;
                }
                sizeMin = sizeMid;
            }
            else if (nLength > sizeMid.cy)
                sizeMax = sizeMid;
            else
                return;
        }

(20:00 追記)
きよのさんからメールを頂きまして(ありがとうございます)、MSのサポートサイトにて解決策があると教えていただきました!
http://support.microsoft.com/default.aspx?scid=kb;ja;190501
すっきりです(笑)

相互リンク1件追加しました。

  • Dot+s(ドット絵)

このサイトの管理人さんであるウォーターさんから
相互リンクの依頼メールを頂いていたのですが、
トップページ3回連続リンク更新のみってのは寒いな(&多忙)って事で
「明日やろう」の無限ループに突入。

昨日再度メールを貰ってしまったのでbreakしました(^^;
気が付けば最初に依頼されたときから2週間も経ってました・・・早っ。
可愛そうな事をしてしまってごめんなさい_| ̄|○>ウォーターさん

最近仕事でシューティングゲームっぽいものを作っているのですが(MFCで)、
「あたり判定」処理を

CRect rcMy; // 自機の矩形とする
CRect rcBullet; // 弾の矩形とする
if (!(rcMy & rcBullet).IsRectEmpty()) {
(当たっている)
}

なんて書いて横着っぷり(?)を発揮しています。
最近のCPUパワーなら無駄も無視出来ると思い込んでマス。

記事検索

アーカイブ