エンタープライズ:特集 2003/09/22 21:29:00 更新
C Magazine

[C Magazine連載]プログラムのレシピ(第2回)
ドローツールを作る (5/6)

C MAGAZINE 2002年10月号より転載

図形の当たり判定
 ドローツールでは、図形をクリックして選択し、図形をドラッグして移動します。このとき、画面上のどの図形がクリックされたのかを判定しなければなりません。

 図形が矩形ならば簡単ですね。矩形の左上の座標を(left, top)、矩形のサイズを(width, height)としましょう。座標(x, y)をクリックしたときに、矩形がクリックされたかどうかを判別するには、(x, y)が矩形の内側の点かどうかを調べればいいのです。つまり、


  if(left<=x && top<=y &&
   x<left+width && y<top+height){
   // 矩形がクリックされた
  }

のようなプログラムになります。

 問題は矩形以外の図形です。楕円やポリゴンでは、Fig.9 -(A)のように図形の周囲に空白の領域があるため、矩形では正確な当たり判定ができません。とくにFig.9-(B)のように図形同士が重なり合ったときには、下になった図形がクリックしにくくなってしまいます。したがって矩形以外の図形では、形状に応じた当たり判定を行う必要があります。

Fig.9
Fig.9 楕円やポリゴンの当たり判定

 楕円の場合には、矩形と同様に比較的簡単な数式で当たり判定ができます。しかしポリゴンとなると複雑です。また、これら以外にも図形の種類が増えたときのことを考えると、どんな図形でも当たり判定ができる汎用的な方法を使うべきでしょう。

 1つのシンプルな解決策は、ビットマップを使う方法です。当たり判定用のビットマップを用意して、そこに図形を描きます。当たり判定を行うときには、クリックした位置に対応するビットマップ上のピクセルを読み取ります。図形のIDを描画色にしておけば、どの図形をクリックしたのかがわかるという仕組みです。

 Fig.10は、この仕組みを図にしたものです。Fig.10-(A)のように図形が配置されているときには、Fig.10-(B)のような当たり判定をビットマップに描画します。描画色は各図形のIDです。グループ化された図形には同じ描画色を使います。また、細い線は太めに描いておくとクリックしやすくなります。

Fig.10
Fig.10 当たり判定の描画

 Fig.10 -(A)、(B)を見比べると、色以外はほとんど同じ描画だということがわかります。プログラムを作るときは、通常の描画と当たり判定用の描画とでうまく描画処理を共有できるように工夫するといいでしょう。

●プログラム例
 List7は楕円の場合のプログラム例です。List7-(2)は通常の描画で、List7-(3)は当たり判定の描画です。List7-(1)は両者に共通な処理をまとめたメソッドです。

List7 楕円の通常描画と当たり判定の描画(DObject.cpp)

//====================================== (1)
// 通常描画と当たり判定描画の共通部分
void DOval::PaintCommon(TCanvas* canvas) {
   if (Filled) {
       canvas->Ellipse(Left, Top, Left+Width, Top+Height);
   } else {
       canvas->Arc(Left, Top, Left+Width, Top+Height, 0,0,0,0);
   }
}

//====================================== (2)
// 通常の描画
void DOval::Paint(TCanvas* canvas) {
   canvas->Pen=Pen;
   canvas->Brush=Brush;
   PaintCommon(canvas);
}

//====================================== (3)
// 当たり判定の描画
void DOval::PaintHitArea(TCanvas* canvas, TColor color) {
   canvas->Pen=Pen;
   canvas->Brush=Brush;

   //================================== (4)
   // 図形のIDを描画色にする
   canvas->Pen->Color=color;
   canvas->Brush->Color=color;

   //================================== (5)
   // 輪郭描画で線が細い場合,太めの線で描画する
   if (!Filled && canvas->Pen->Width<HitPenWidth)
       canvas->Pen->Width=HitPenWidth;

   PaintCommon(canvas);
}

 List7-(2)の通常描画では、図形のペン(輪郭)属性とブラシ(塗りつぶし)属性を使って、図形を描画します。これに対して当たり判定の描画では、List7-(4)のように図形のIDを使って描画します。ここでは引数colorで図形のID(グループの子オブジェクトリスト内のインデックス)を受け取るようになっています。

 List7-(5)は、輪郭だけを描画するときに、一定値(HitPenWidth)よりも細い線を太くする処理です。細い線を見た目どおりの当たり判定にしてしまうとクリックしにくいので、当たり判定描画では線を太くして、実際の見た目よりも当たり判定を大きくするわけです。

コラム2 Javaへの移植ポイント(当たり判定)

 Javaで当たり判定を実装する場合も、原理はほとんど同じです。C++BuilderやWin32 APIではビットマップを使いますが、Javaではjava.awt.Imageクラスを使うといいでしょう。java.awt.ComponentクラスのcreateImageメソッドを使えば、オフスクリーンイメージ(直接画面に表示しないイメージ)が作れます。あとは、このオフスクリーンイメージに対して当たり判定を描画するだけです。


[C Magazine連載]プログラムのレシピ(第2回)
ドローツールとは
制作上のポイント
図形のクラス設計
図形の基本クラス
矩形クラスと楕円クラス
ポリゴンクラス
テキストクラス
グループ化機能
図形の当たり判定
サンプルプログラムの使い方
おわりに
・実行ファイル/リソース一式(.lzh形式/1.31MB)
・リスト(.lzh形式/3.40KB)

関連リンク
▼C MAGAZINE
▼ひぐぺん工房
▼「デスクトップマスコットを作ろう」紹介ページ
▼「デスクトップマスコットを作ろう」著者ページ

前のページ | 1 2 3 4 5 6 | 次のページ

[松浦健一郎(ひぐぺん工房),JAVA Developer]