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

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

一定時間後のボールの位置を予測して、その予測地点をプレイヤーに指示する。

がむしゃらに追いつかないボールを追いかけるだけじゃなく、飛んでくるボールを待つ感じは、
ちょっと賢くなったように感じる。




v008


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








Ball.h


class Ball
{
    double Bx,By;       // ボール現在位置
    double yBx,yBy;     // 1秒後のボールの予測位置
    double Spd;         // ボールの速度
    double Vx,Vy;       // ボールの移動速度(X、Y成分)
    int HomeX,HomeY;    // ホームポジション(試合開始時、ピッチ中央)
public:
    void Init(int HomeX, int HomeY);
    int getBx(){return static_cast<int>(Bx);}
    int getBy(){return static_cast<int>(By);}
    double getSpd(){return Spd;}
    void Kick(int LocX, int LocY, double Spd);
    bool Move();
    void Yosoku();
    int getYBx(){return static_cast<int>(yBx);}
    int getYBy(){return static_cast<int>(yBy);}

};

void Ball::Init(int hx, int hy){
    Bx = yBx = HomeX = hx;
    By = yBy = HomeY = hy;
    Vx = Vy = 0.0;
    Spd = 0.0;
}

void Ball::Yosoku()
{
    double dSpd = Spd;
    yBx = Bx;
    yBy = By;

    // 60フレーム(約1秒)後の位置を読む
    for(int i = 0; i< 60; i++){
        yBx += Vx * dSpd;
        yBy += Vy * dSpd;
        dSpd *= 0.98;
    }
    if(yBx<0.0) yBx = -yBx;
    if(yBy<0.0) yBy = -yBy;
    if(yBx>600.0) yBx = 600.0-(yBx-600.0);
    if(yBy>300.0) yBy = 300.0-(yBy-300.0);

}


bool Ball::Move()
{
    Bx += Vx*Spd;
    By += Vy*Spd;

    Spd *= 0.98;     // 地面との摩擦により、転がるスピードが落ちる
    if(Spd < 0.001) { Spd = 0.0; Vx = Vy = 0.0;}

    // 壁の反射とゴール判定
    if(By<0.0){Vy=-Vy;By=0.0;}
    if(By>300.0){Vy=-Vy;By=300.0;}

    if((Bx<0.0)||(Bx>600.0)){
        Vx=-Vx;
        if(Bx<300.0) Bx=0.0;
        else Bx=600.0;
        if((By>=100.0)&&(By<=200.0)){
            return true;
        }
    }
    Yosoku();
    return false;
}


今のボール位置と進行方向からプレイヤーごとに毎回計算するのもナニな話なんで、ボール自身に
計算させて用意しておく。
まずは予測位置用に double yBx、yBy を新設。初期化と取得関数も整備。
ボールの移動関数から、適切と思われるタイミングでYosoku() を呼び出す。

予測地点の判定はけっこう強引。
60フレーム分、ころがり判定を重ねる。最後に、枠外にはみ出した部分を折り返す。
for で60回計算しなくても、微分積分とか使ったら計算一発で出るんだけど、頭がまわらない。
今さら高校数学の参考書で勉強するのも面倒だし。
なんかいい方法あったら差し替える。


メインで使ってみる。

main.cpp



void DrawScene()
{
    // 表示用のパレットデータ
    static const int FieldBaseColor = GetColor( 72, 255, 72);
    static const int White = GetColor(255,255,255);
    static const int Black = GetColor(  0,  0,  0);
    static const int Blue  = GetColor(  0,  0,224);
    static const int Red   = GetColor(224,  0,  0);

    // サッカーフィールド(固定)
    DrawBox(  20, 160, 620, 460, FieldBaseColor, 1);    // フィールド部塗りつぶし
    DrawBox( 120, 160, 220, 460, Black, 0);             // 西軍エリア分割
    DrawBox(  20, 260, 320, 360, Black, 0);
    DrawBox( 420, 160, 520, 460, Black, 0);             // 東軍エリア分割
    DrawBox( 320, 260, 620, 360, Black, 0);
    DrawBox(  20, 160, 620, 460, White, 0);             // 外枠
    DrawLine(320, 160, 320, 460, White, 1);             // 中央ライン
    DrawBox(  20, 260,  70, 360,  Blue, 0);             // 西軍ゴール
    DrawBox( 570, 260, 620, 360,   Red, 0);             // 東軍ゴール
    DrawCircle(320, 310, 80, White, 0);                 // 中央サークル

    // プレイヤー
    int tc;
    for(int i=0;i<10;i++){
        if(player[i].getTeam()==BLUE) tc = Blue;
        else tc = Red;
        DrawCircle(player[i].getPx()+20,player[i].getPy()+160, 8,    tc, 1);
        DrawCircle(player[i].getPx()+20,player[i].getPy()+160, 8, White, 0);
    }
    // ボール
    DrawCircle(ball.getBx()+20,ball.getBy()+160, 6, White, 1);

    // ボール予測位置
    DrawLine(ball.getYBx()-2+20,ball.getYBy()-2+160,ball.getYBx()+2+20,ball.getYBy()+2+160,White,1);
    DrawLine(ball.getYBx()+2+20,ball.getYBy()-2+160,ball.getYBx()-2+20,ball.getYBy()+2+160,White,1);

    DrawFormatString(0,100,White,"BallSpeed:%5d",static_cast<int>(ball.getSpd()*1000));
    DrawFormatString(0,120,White,"BlueScore:%2d    RedScore:%2d",game.getBlueScore(),game.getRedScore());

    return;
}



ボールの予測位置を表示してみる。
これで動かして、位置予測がちゃんと出来てるか確認。

なかなかいいんじゃない?
ってことで、この地点にプレイヤーを向かわせる。


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();
            } else {
                if(ball.getBx()>200)player[i].GoHomePos();
            }
        }
    }
    // いちばん近いプレイヤーに目標地点に向かう指令を出す
    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(Distance(player[i].getPx(),player[i].getPy(),ball.getBx(),ball.getBy())<500)
            if(ball.getSpd()<2.0) player[i].GoLocate(CHASE_BALL,ball.getBx(),ball.getBy());

        player[i].Move();

        // ボールを蹴られる位置にいるか。




キーパーは変な予測させずに現状維持でボールだけを見る。

こんな感じで動くはず。
なんか簡単に変更できた!いい感じに動いてる。
マーカー位置のポジション取りの動きがすごくいい。

結果オーライだけど、ある程度ボールが近づいたら自分から蹴りに、前に出る感じもいい。

あと、ボールを蹴った直後、当然だけどボールの近くにいるんだが、ほんのちょっと
追いつけないボールを追いかける動作が気になってたんで、スピード判定を差し込んでみた。



着実に賢くなっていってる。
このプログラムに手をつけた時から大きな問題がふたつ残ると思ってたんだけど、
そのうちのひとつは力技で強引に抑えてしまえそう。

それとは別の問題だけど、プレイヤーが重なるのがいやだなあ。次はこれをどうにかしようかな。


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
アクセス解析
カウンター