なんとなくだらだらと。方向性はまだ決まってない。
当方のプログラムでは、山田巧さん作成のDXライブラリを利用させていただいてます。
本サイト http://homepage2.nifty.com/natupaji/DxLib/index.html
DX Library Copyright (C) 2001-2008 Takumi Yamada.
× [PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
ゴールキーパーが、ボールが来るまでいつもボーっと立ってるのが気になってた。
進むべき道はわかってたんだけど、禿げるほど難解なんで後回しにしてたんだよな。 そろそろやることも無くなってきたんで、こういう高校数学に手をつけていかないと・・・。 ダウンロード http://hiyayakko.sarashi.com/SimpleSoccer/SC11.zip (2009.08.18) 円と直線の交点を求めるわけだが、まずはキーパーの守備半径を決める。 ゴールの中心よりもエリアの少し外側に中心を持ってくるほうが、自然な位置に 収まるんじゃないかと勝手な推測。 いろいろ円を書いてみて、「エリアの50ピクセル外側から半径100」の円に決める。 求めたいのは、この白丸で示した守備円とボールが円の中心に向かう直線の交点。 ここ数日、壁にぶち当たるいやな感じで悩んでたんだけど、自分でもびっくりするぐらい 簡単だった。 任意の直線ならともかく、今のこの状況なら直線は必ず円の中心に向かう。 っていうかそういうふうに作ってる。 ある点(X,Y)からもう1点(X,Y)へ向かう直線の角度を求めるはさんざん使ってる。 Yaw = atan2(AY - By, AX - Bx); 逆転の発想で、円の中心からボール(予測地点)へ向かう角度Yawを求める。 この角度から求めるサインコサインに半径100を掛けたら、この図の「円と直線の交点」が 求められてしまったわけだ。 ball.h void Ball::YosokuKeeperArea() { double Yaw; AreaFlag = Free; if(yBx < 250){ // ボール予想地点が青軍寄りのとき Yaw = atan2(yBy - 150, yBx - (-50)); kBx = -50 + cos(Yaw)*100; kBy = 150 + sin(Yaw)*100; AreaFlag = Blue; }else if(yBx>350){ // ボール予想地点が赤軍寄りのとき Yaw = atan2(yBy - 150, yBx - 650); kBx = 650 + cos(Yaw)*100; kBy = 150 + sin(Yaw)*100; AreaFlag = Red; } return; } キーパー予想位置用に kBx、kBy なんてメンバ変数作って、それ用にゲット関数や 初期化などなど追加したけど、そのへんは面倒なんで書かない。 この追加部分の式も、上で図まで用意して説明したそのまんま。 ちゃんとできてるか、表示して確認してみる。 main.cpp void DrawScene() { : : // ゴールキーパー守備地点 DrawCircle( -50+20, 150+160, 100, Blue, 0); DrawCircle( 650+20, 150+160, 100, Red, 0); if(ball.getArea()==Area::Blue){ DrawLine(ball.getYBx()+20,ball.getYBy()+160,-50+20,150+160,Blue,1); DrawLine(ball.getKBx()-2+20,ball.getKBy()-2+160,ball.getKBx()+2+20,ball.getKBy()+2+160,White,1); DrawLine(ball.getKBx()+2+20,ball.getKBy()-2+160,ball.getKBx()-2+20,ball.getKBy()+2+160,White,1); }else if(ball.getArea()==Area::Red){ DrawLine(ball.getYBx()+20,ball.getYBy()+160,650+20,150+160,Red,1); DrawLine(ball.getKBx()-2+20,ball.getKBy()-2+160,ball.getKBx()+2+20,ball.getKBy()+2+160,White,1); DrawLine(ball.getKBx()+2+20,ball.getKBy()-2+160,ball.getKBx()-2+20,ball.getKBy()+2+160,White,1); } 動かしてみる。 うむ、ちゃんと動いてる感じ。えらいえらい。 enum Area::Blue とかやってるところ警告されてるけど。軽く無視。 このマーカーポイントにゴールキーパーを置くようにする。 main.cpp void GamePlay() { int i,dist; int rc=-1,bc=-1,rc_dist=999999,bc_dist=999999; for(i=0;i<10;i++)player[i].setStatus(WAIT); for(i=0;i<10;i++){ // ゴールキーパー以外で、両軍ともにボール予測位置に一番近いプレイヤーを探す if(player[i].getPos()!=GOALKEEPER){ dist = Distance(player[i].getPx(),player[i].getPy(),ball.getYBx(),ball.getYBy()); if(player[i].getTeam()==RED){ if(dist<rc_dist){ rc=i; // このプレイヤーが今のところ一番近い rc_dist=dist; } } else { if(dist<bc_dist){ bc=i; // このプレイヤーが今のところ一番近い bc_dist=dist; } } } else { // ゴールキーパーは自分のエリアからある程度ボールが離れれば、自分のポジションに戻る if(player[i].getTeam()==RED){ if(ball.getBx()<400)player[i].GoHomePos(); if(ball.getArea() == Area::Red) player[i].GoLocate(SUPPORT, ball.getKBx(), ball.getKBy()); } else { if(ball.getBx()>200)player[i].GoHomePos(); if(ball.getArea() == Area::Blue) player[i].GoLocate(SUPPORT, ball.getKBx(), ball.getKBy()); } } } // いちばん近いプレイヤーに目標地点に向かう指令を出す if(bc!=-1) player[bc].GoLocate(CHASE_BALL,ball.getYBx(),ball.getYBy()); if(rc!=-1) player[rc].GoLocate(CHASE_BALL,ball.getYBx(),ball.getYBy()); // プレイヤーの移動処理 for(i=0;i<10;i++){ if(player[i].getPos()==GOALKEEPER){ // ゴールキーパーだけ、守備範囲を広く取る if(Distance(player[i].getPx(),player[i].getPy(),ball.getBx(),ball.getBy())<6400){ player[i].GoLocate(CHASE_BALL,ball.getBx(),ball.getBy()); } } else { if(player[i].getStatus()!=SUPPORT){ if(Distance(player[i].getPx(),player[i].getPy(),ball.getBx(),ball.getBy())<1500) if(ball.getSpd()<2.0) player[i].GoLocate(CHASE_BALL,ball.getBx(),ball.getBy()); // プレイヤーが他のプレイヤーの近くにいるときは、その相手から遠ざかる方向へ動く for(int j=i+1;j<10;j++){ // if(j!=i){ int mPx = player[i].getPx(); int mPy = player[i].getPy(); int yPx = player[j].getPx(); int yPy = player[j].getPy(); if(Distance(mPx,mPy,yPx,yPy)<100){ player[i].GoLocate(SUPPORT,mPx*2-yPx,mPy*2-yPy); player[j].GoLocate(SUPPORT,yPx*2-mPx,yPy*2-mPy); } } // } } } うむ。 怖いぐらい順調。 あと、プレイヤー同士のぶつかり合いの判定をちょっと変更。 自分より若い番号の人にはすでに判定されてるんだから、プレイヤー番号全員から 全員分判定しなくてもいいんじゃないか。 j !=i の判定も、自分自身が判定に含まれることが無くなったんで、もう不要に。 そう思ってたんだけど、変更してみたら何が変わったのかいろいろと怪奇現象が。 ボールを挟んで完全にお見合い状態になるんで、判定距離を100に戻した。 あと、まあ偶然だがそうなるといえばそうなるんだけど、赤軍青軍ボールのY座標が 完全に一致すると、敵軍をかわして切り込む動きができなくなってる。 今までもそうだったと思うんだけど、この変更から急に気になる動きが出てきた。 マーカー消したら、結構本格的な、いい動きしてるように見える。 この先どう進むべきか。 まずは、プログラム的にいちいちRed、Blueで分けて同じことやってるのが気になってる。 スマートに解決する方法ないかな。 あと、マジックナンバーが多くなってきたのが気になる。 考え無しに定点座標ぶちこみ続けた結果なんだけど。 たとえばエリアを倍に広げるとかやったときに、変更箇所がほぼプログラム全域に及ぶことになる。 プレイヤーが固定で5vs5というのも気になってる。 柔軟に変更できるように、std::listとか持ち込むべきかな? そして最初からわかってた大きな問題のひとつ。 知ってのとおり、今のところ、プレイヤーはボールと邪魔する相手しか見てない。 ボーっと立ってないで、ちゃんとチームで連携して敵陣の薄いところに切り込んでいくように。 ディフェンダーも、シュートの危険があるプレイヤーを邪魔するように動くとか。 こうやって連携が取れてきたら、攻撃もとりあえず前へボールを送るだけじゃなく パスしたりドリブルでボールキープしながら前進したりできるように考えられる。 ここまで出来たら「脱・小学生サッカー」名乗ってもいいんじゃないだろうか。 あともうひとつの大きな問題。 遊ぶ人としてのプレイヤーがどこにどう介入するべきか。 これがさっぱりわからん。 どっちが勝つとか関係なく、見てるだけで楽しいんだよなあ。 PR |
カレンダー
カテゴリー
フリーエリア
最新記事
(01/29)
(01/28)
(01/26)
(12/28)
(12/27)
(12/25)
(12/20)
(09/09)
(09/09)
(09/09)
(09/08)
(09/08)
(09/08)
(09/06)
(09/05)
(08/27)
(08/27)
(08/27)
(08/25)
(08/23)
ブログ内検索
P R
アクセス解析
カウンター
|