DXライブラリで多角形を描く (with C++サンプル)
DXライブラリで2Dゲーム作ってるときに、多角形を描く必要が出てきました
しかし、DXライブラリには三角形を描画する関数ならありますが多角形を描画する関数はありません
ということで、多角形を三角形に分割して描くことにしました
どうやって多角形を三角形にするのか?という理論については、こちらのサイトが分かりやすかったです。無断リンクお許しください
Javaゲーム制作記 任意多角形の三角形分割
以下、C++のサンプルコードです
タイトルからDXライブラリって描いてましたが、描画部分を変えれば他のライブラリでも使えます(多分)
なお、このコードは辺と辺が交差していない多角形でのみ使用できます。注意
// ベクトル構造体 struct t_vector{ double sx, sy; double vx, vy; }; // p1からp2へ伸びるベクトルを生成 t_vector makeVector( pair<double,double> p1, pair<double,double> p2 ){ t_vector v; v.sx = p1.first; v.sy = p1.second; v.vx = p2.first - p1.first; v.vy = p2.second - p1.second; return v; } // v1とv2の外積を計算 double cross( t_vector v1, t_vector v2 ){ return v1.vx*v2.vy - v1.vy*v2.vx; } //---------------------------------------------------------- /// @brief 点の集合vの中で、v1,v2で構成される三角形内部に点があるか確認する /// @param v1,v2 : 三角形を構成するベクトル。始点が同じである必要あり /// v : 点の集合 /// @return 1つでも含まれている→true, ない→false //---------------------------------------------------------- bool IsExistPointInTriangle(t_vector v1, t_vector v2, vector< pair<double,double> > &v){ // v2の向き反転 v2.sx += v2.vx; v2.sy += v2.vy; v2.vx *= -1; v2.vy *= -1; // v1の先端からv2の後端に伸びるベクトルv3生成 t_vector v3; v3.sx = v1.sx + v1.vx; v3.sy = v1.sy + v1.vy; v3.vx = v2.sx - v3.sx; v3.vy = v2.sy - v3.sy; // 全ての点について、ベクトルv1~v3の左右どちらにあるか判定していく t_vector *vn[3] = {&v1, &v2, &v3}; for(int i=0; i<v.size(); i++){ t_vector vp; bool outside = false; for(int j=0; j<3; j++){ vp.sx = vn[j]->sx; vp.sy = vn[j]->sy; vp.vx = v[i].first - vp.sx; vp.vy = v[i].second - vp.sy; if( cross( *vn[j], vp ) >= 0 ){ outside = true; break; } } if( !outside ) return true; } return false; } // 三角形構造体 struct t_triangle{ double x[3], y[3]; }; //---------------------------------------------------------- /// @brief 点の集合vで表される多角形を三角形分割し、trisに格納する /// @param v : 多角形を作る点の集合vector。辺が繋がっている順番である必要あり /// tris : 生成した三角形を格納するvector /// v,trisとも、pairのfirstがx座標を、secondがy座標を表す //---------------------------------------------------------- void SplitTriangles(vector< pair<double,double> > v, vector<t_triangle> &tris){ // 三角形が作れなくなるまで繰り返す while( v.size() >= 3 ){ // 原点から最も遠い点を探す int mfar = 0; for(int i=1; i<v.size(); i++){ if( v[mfar].first*v[mfar].first+v[mfar].second*v[mfar].second < v[i].first*v[i].first+v[i].second*v[i].second ) mfar = i; } // 最も遠い点から伸びる2つのベクトルを生成 t_vector v1, v2; v1 = makeVector( v[mfar], v[(mfar+1)%v.size()] ); v2 = makeVector( v[mfar], v[(mfar+v.size()-1)%v.size()] ); // 参考元ではここで180度判定をしていたが、特に必要ない気がするので、はしょる // 三角形内部に点があるとき if( IsExistPointInTriangle(v1, v2, v) ){ // 外積の記録 double cr = cross( v1, v2 ); // 見つかるまでループ while(1){ // 1つ横の点を選ぶ mfar = (mfar+1)%v.size(); // ベクトル生成 v1 = makeVector( v[mfar], v[(mfar+1)%v.size()] ); v2 = makeVector( v[mfar], v[(mfar+v.size()-1)%v.size()] ); // 外積の符号が異なる→ループ最初に戻る if( cr*cross(v1,v2) < 0.0 ) continue; // 内部に点があるか確認 // 点がある→ループ最初に戻る if( IsExistPointInTriangle(v1, v2, v) ) continue; // 点がない→脱ループ break; } } // 三角形の3点を_trisに記録 t_triangle t; t.x[0] = v1.sx; t.y[0] = v1.sy; t.x[1] = v1.sx+v1.vx; t.y[1] = v1.sy+v1.vy; t.x[2] = v2.sx+v2.vx; t.y[2] = v2.sy+v2.vy; _tris.push_back(t); // 選ばれた点をvから除外 v.erase( remove( v.begin(), v.end(), v[mfar] ) ); } } // 描画はこんな感じで void Draw(){ for(int i=0; i<tris.size(); i++){ DrawTriangle( tris[i].x[0], tris[i].y[0], tris[i].x[1], tris[i].y[1], tris[i].x[2], tris[i].y[2], GetColor( 255, 255, 255 ), TRUE ); } }