忍者ブログ
なんとなくだらだらと。方向性はまだ決まってない。 当方のプログラムでは、山田巧さん作成のDXライブラリを利用させていただいてます。 本サイト http://homepage2.nifty.com/natupaji/DxLib/index.html DX Library Copyright (C) 2001-2008 Takumi Yamada.
[53] [52] [51] [50] [49] [48] [47] [46] [45] [44] [43]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

ゴールキーパーが、ボールが来るまでいつもボーっと立ってるのが気になってた。
進むべき道はわかってたんだけど、禿げるほど難解なんで後回しにしてたんだよな。

そろそろやることも無くなってきたんで、こういう高校数学に手をつけていかないと・・・。



v012




ダウンロード http://hiyayakko.sarashi.com/SimpleSoccer/SC11.zip  (2009.08.18)




円と直線の交点を求めるわけだが、まずはキーパーの守備半径を決める。
ゴールの中心よりもエリアの少し外側に中心を持ってくるほうが、自然な位置に
収まるんじゃないかと勝手な推測。
いろいろ円を書いてみて、「エリアの50ピクセル外側から半径100」の円に決める。


v013


求めたいのは、この白丸で示した守備円とボールが円の中心に向かう直線の交点。
ここ数日、壁にぶち当たるいやな感じで悩んでたんだけど、自分でもびっくりするぐらい
簡単だった。

任意の直線ならともかく、今のこの状況なら直線は必ず円の中心に向かう。
っていうかそういうふうに作ってる。

ある点(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


忍者ブログ [PR]
カレンダー
11 2024/12 01
S M T W T F S
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
フリーエリア
バーコード
ブログ内検索
P R
アクセス解析
カウンター