Robcup2D足球学习记录【2020.01.18】

bhv_strict_check_shoot.cpp

代码个人理解与存在的问题(已经通过注释标出)

注释的格式为:
/*
问题:
1.xxxx
2.xxxx

理解:
这个函数是xxxxx
By ChenYanTing
*/

// -*-c++-*-

/*!
  \file bhv_pass_kick_find_receiver.cpp
  \brief search the pass receiver player and perform pass kick if possible
*/

/*
 *Copyright:

 Copyright (C) Hidehisa AKIYAMA

 This code is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 3, or (at your option)
 any later version.

 This code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this code; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

 *EndCopyright:
 */

/////////////////////////////////////////////////////////////////////

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "bhv_pass_kick_find_receiver.h"

#include "action_chain_holder.h"
#include "action_chain_graph.h"
#include "field_analyzer.h"

#include "neck_turn_to_receiver.h"

#include <rcsc/action/bhv_scan_field.h>
#include <rcsc/action/body_hold_ball.h>
#include <rcsc/action/body_kick_one_step.h>
#include <rcsc/action/body_smart_kick.h>
#include <rcsc/action/body_stop_ball.h>
#include <rcsc/action/body_turn_to_point.h>
#include <rcsc/action/neck_scan_field.h>
#include <rcsc/action/neck_turn_to_point.h>
#include <rcsc/action/neck_turn_to_player_or_scan.h>
#include <rcsc/action/view_synch.h>
#include <rcsc/action/kick_table.h>
#include <rcsc/player/player_agent.h>
#include <rcsc/player/abstract_player_object.h>
#include <rcsc/player/soccer_intention.h>
#include <rcsc/player/intercept_table.h>
#include <rcsc/player/say_message_builder.h>
#include <rcsc/common/server_param.h>
#include <rcsc/common/logger.h>
#include <rcsc/math_util.h>

#include <vector>
#include <algorithm>
#include <cmath>

// #define DEBUG_PRINT

using namespace rcsc;


class IntentionPassKickFindReceiver
    : public SoccerIntention {
private:
    int M_step;
    int M_receiver_unum;
    Vector2D M_receive_point;

public:

    IntentionPassKickFindReceiver( const int receiver_unum,
                                   const Vector2D & receive_point )
        : M_step( 0 ),
          M_receiver_unum( receiver_unum ),
          M_receive_point( receive_point )
      { }

    bool finished( const PlayerAgent * agent );

    bool execute( PlayerAgent * agent );

private:

};

/*-------------------------------------------------------------------*/
/*!

 */
/*
 问题:
无
 
 
 理解:
 这个函数是IntentionPassKickFindReceiver的finished函数,主要作用是根据kickable、reciever等因素在IntentionPassKickFindReceiver结束时返回一些提示
 By ChenYanTing
 */
bool
IntentionPassKickFindReceiver::finished( const PlayerAgent * agent )
{
    ++M_step;

    dlog.addText( Logger::TEAM,
                  __FILE__": (finished) step=%d",
                  M_step );

    if ( M_step >= 2 )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": (finished) time over" );
        return true;
    }

    const WorldModel & wm = agent->world();

    //
    // check kickable
    //

    if ( ! wm.self().isKickable() )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": (finished) no kickable" );
        return true;
    }

    //
    // check receiver
    //

    const AbstractPlayerObject * receiver = wm.ourPlayer( M_receiver_unum );

    if ( ! receiver )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": (finished) NULL receiver" );
        return true;
    }

    if ( receiver->unum() == wm.self().unum() )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": (finished) receiver is self" );
        return true;
    }

    if ( receiver->posCount() <= 0 )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": (finished) already seen" );
        return true;
    }

    //
    // check opponent
    //

    if ( wm.existKickableOpponent() )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": (finished) exist kickable opponent" );
        return true;
    }

    if ( wm.interceptTable()->opponentReachCycle() <= 1 )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": (finished) opponent may be kickable" );
        return true;
    }

    //
    // check next kickable
    //

    double kickable2 = std::pow( wm.self().playerType().kickableArea()
                                 - wm.self().vel().r() * ServerParam::i().playerRand()
                                 - wm.ball().vel().r() * ServerParam::i().ballRand()
                                 - 0.15,
                                 2 );
    Vector2D self_next = wm.self().pos() + wm.self().vel();
    Vector2D ball_next = wm.ball().pos() + wm.ball().vel();

    if ( self_next.dist2( ball_next ) > kickable2 )
    {
        // unkickable if turn is performed.
        dlog.addText( Logger::TEAM,
                      __FILE__": (finished) unkickable at next cycle" );
        return true;
    }

    return false;
}


/*-------------------------------------------------------------------*/
/*!

 */
Bhv_PassKickFindReceiver::Bhv_PassKickFindReceiver( const ActionChainGraph & chain_graph )
    : M_chain_graph( chain_graph )
{
}


/*-------------------------------------------------------------------*/
/*!

 */
*/
/*
 问题:
 1.AngleDeg类有什么用?
 2.M_receive_point是什么?为什么face_point = ( receiver_pos + M_receive_point ) * 0.5?无法理解这个计算公式
 
 
 
 理解:
 这个函数是IntentionPassKickFindReceiver的execute函数,主要作用是根据reciever的坐标还有自己身体的朝向来判断是否需要执行相应的转向接受者的动作
 By ChenYanTing
 */
bool
IntentionPassKickFindReceiver::execute( PlayerAgent * agent )
{
    const WorldModel & wm = agent->world();
    const AbstractPlayerObject * receiver = wm.ourPlayer( M_receiver_unum );

    if ( ! receiver )
    {
        return false;
    }

    const Vector2D next_self_pos = agent->effector().queuedNextMyPos();
    const AngleDeg next_self_body = agent->effector().queuedNextMyBody();
    const double next_view_width = agent->effector().queuedNextViewWidth().width() * 0.5;

    const Vector2D receiver_pos = receiver->pos() + receiver->vel();
    const AngleDeg receiver_angle = ( receiver_pos - next_self_pos ).th();

    Vector2D face_point = ( receiver_pos + M_receive_point ) * 0.5;
    AngleDeg face_angle = ( face_point - next_self_pos ).th();

    double rate = 0.5;
    while ( ( face_angle - receiver_angle ).abs() > next_view_width - 10.0 )
    {
        rate += 0.1;
        face_point
            = receiver_pos * rate
            + M_receive_point * ( 1.0 - rate );
        face_angle = ( face_point - next_self_pos ).th();

        if ( rate > 0.999 )
        {
            break;
        }
    }

    dlog.addText( Logger::TEAM,
                  __FILE__": (intentin) facePoint=(%.1f %.1f) faceAngle=%.1f",
                  face_point.x, face_point.y,
                  face_angle.degree() );
    agent->debugClient().addMessage( "IntentionTurnToReceiver%.0f",
                                     face_angle.degree() );
    Body_TurnToPoint( face_point ).execute( agent );
    agent->setNeckAction( new Neck_TurnToPoint( face_point ) );

    return true;
}



/*-------------------------------------------------------------------*/
/*-------------------------------------------------------------------*/
/*-------------------------------------------------------------------*/


/*-------------------------------------------------------------------*/
/*!

 */
/*
 问题:
 1.AngleDeg类有什么用?
 2.M_receive_point是什么?为什么face_point = ( receiver_pos + M_receive_point ) * 0.5?无法理解这个计算公式
 
 理解:
 这个函数是Bhv_PassKickFindReceiver的execute函数,主要作用是根据isKickable、 receiver->unum()等变量来判断是否可以传球,如果不可以则返回false,否则传球并且返回true
 By ChenYanTing
 */
bool
Bhv_PassKickFindReceiver::execute( PlayerAgent * agent )
{
    dlog.addText( Logger::TEAM,
                  __FILE__": Bhv_PassKickFindReceiver" );

    const WorldModel & wm = agent->world();

    if ( ! wm.self().isKickable() )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": no kickable" );
        return false;
    }

    //
    // validate the pass
    //
    const CooperativeAction & pass = M_chain_graph.getFirstAction();

    if ( pass.category() != CooperativeAction::Pass )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": action(%d) is not a pass type.",
                      pass.category() );
        return false;
    }

    const AbstractPlayerObject * receiver = wm.ourPlayer( pass.targetPlayerUnum() );

    if ( ! receiver )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": NULL receiver." );

        return false;
    }

    dlog.addText( Logger::TEAM,
                  __FILE__": pass receiver unum=%d (%.1f %.1f)",
                  receiver->unum(),
                  receiver->pos().x, receiver->pos().y );

    if ( wm.self().unum() == receiver->unum() )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": receiver is my self." );
        return false;
    }

    if ( receiver->unum() == 1 )
    {
        std::cerr << wm.time().cycle() << __FILE__ << ": DO NOT PASS TO OUR GOALIE !!!\n\n";
        return false;
    }

    // if ( receiver->isGhost() )
    // {
    //     dlog.addText( Logger::TEAM,
    //                   __FILE__": receiver is a ghost." );
    //     return false;
    // }

    if ( wm.gameMode().type() == GameMode::PlayOn )
    {
        doPassKick( agent, pass );
        return true;
    }

#if 1
    //ht: testing avoid own_goal
    if ( wm.gameMode().type() == 7 ) //GameMode::GoalKick
    {
        Body_KickOneStep( pass.targetPoint(),
                          pass.firstBallSpeed() ).execute( agent );


        agent->setNeckAction( new Neck_TurnToReceiver( M_chain_graph ) );
        doSayPass( agent, pass );
        //std::cerr << wm.time().cycle() << __FILE__ << wm.self().unum() << ": 应该没有乌龙球了吧!!!\n\n";

        return true;
    }
#endif //1

    //
    // estimate kick step
    //
    int kick_step = pass.kickCount(); //kickStep( wm, pass );

    if ( kick_step == 1
         //&& pass.targetPoint().x > -20.0
         && receiver->seenPosCount() <= 3 )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": 1 step kick." );
        doPassKick( agent, pass );
        return true;
    }

    //
    // trying to turn body and/or neck to the pass receiver
    //

    if ( doCheckReceiver( agent, pass ) )
    {
        agent->debugClient().addCircle( wm.self().pos(), 3.0 );
        agent->debugClient().addCircle( wm.self().pos(), 5.0 );
        agent->debugClient().addCircle( wm.self().pos(), 10.0 );

        return true;
    }

    if ( ( kick_step == 1
           && receiver->seenPosCount() > 3 )
         || receiver->isGhost() )
    {
        agent->debugClient().addMessage( "Pass:FindHold2" );
        dlog.addText( Logger::TEAM,
                      __FILE__": (execute) hold ball." );

        Body_HoldBall( true,
                       pass.targetPoint(),
                       pass.targetPoint() ).execute( agent );
        doSayPass( agent, pass );
        agent->setNeckAction( new Neck_TurnToReceiver( M_chain_graph ) );
        return true;
    }

    //
    // pass kick
    //

    doPassKick( agent, pass );

    return true;
}

/*-------------------------------------------------------------------*/
/*!

 */
/*
 问题:
 1.pass.kickCount()的含义是什么?
 2.M_receive_point是什么?为什么face_point = ( receiver_pos + M_receive_point ) * 0.5?无法理解这个计算公式
 3.Body_KickOneStep和Body_SmartKick的作用是什么?在哪里可以找到?
 
 理解:
 这个函数是Bhv_PassKickFindReceiver的doPassKick函数,主要作用是执行身体转向并且执行传球动作
 By ChenYanTing
 */
bool
Bhv_PassKickFindReceiver::doPassKick( PlayerAgent * agent,
                                      const CooperativeAction & pass )
{
    agent->debugClient().setTarget( pass.targetPlayerUnum() );
    agent->debugClient().setTarget( pass.targetPoint() );
    dlog.addText( Logger::TEAM,
                  __FILE__" (Bhv_PassKickFindReceiver) pass to "
                  "%d receive_pos=(%.1f %.1f) speed=%.3f",
                  pass.targetPlayerUnum(),
                  pass.targetPoint().x, pass.targetPoint().y,
                  pass.firstBallSpeed() );

    if ( pass.kickCount() == 1
         || agent->world().gameMode().type() != GameMode::PlayOn )
    {
        Body_KickOneStep( pass.targetPoint(),
                          pass.firstBallSpeed() ).execute( agent );

    }
    else
    {
        Body_SmartKick( pass.targetPoint(),
                        pass.firstBallSpeed(),
                        pass.firstBallSpeed() * 0.96,
                        3 ).execute( agent );
    }
    agent->setNeckAction( new Neck_TurnToReceiver( M_chain_graph ) );
    doSayPass( agent, pass );

    return true;
}

/*-------------------------------------------------------------------*/
/*!

 */
/*
 问题:
 1.这个函数的意义是什么?看不太懂
 
 理解:
 这个函数是Bhv_PassKickFindReceiver的doPassKick函数,主要作用是执行身体转向并且执行传球动作
 By ChenYanTing
 */
int
Bhv_PassKickFindReceiver::kickStep( const WorldModel & wm,
                                    const CooperativeAction & pass )
{
    Vector2D max_vel
        = KickTable::calc_max_velocity( ( pass.targetPoint() - wm.ball().pos() ).th(),
                                        wm.self().kickRate(),
                                        wm.ball().vel() );

    // dlog.addText( Logger::TEAM,
    //               __FILE__": (kickStep) maxSpeed=%.3f passSpeed=%.3f",
    //               max_vel.r(), pass.firstBallSpeed() );

    if ( max_vel.r2() >= std::pow( pass.firstBallSpeed(), 2 ) )
    {
        return 1;
    }

    if ( pass.firstBallSpeed() > 2.5 ) // Magic Number
    {
        return 3;
    }

    return 2;
}

/*-------------------------------------------------------------------*/
/*!

 */
/*
 问题:
 无
 
 理解:
 这个函数是Bhv_PassKickFindReceiver的doPassKick函数,主要作用是根据目标点的坐标、自己的朝向、球的位置等等来判断是否有必要doCheckReceiver,如果没有返回false,如果有责返回true并且设置朝向面对reciever
 By ChenYanTing
 */
bool
Bhv_PassKickFindReceiver::doCheckReceiver( PlayerAgent * agent,
                                           const CooperativeAction & pass )
{
    const WorldModel & wm = agent->world();

    double nearest_opp_dist = 65535.0;
    wm.getOpponentNearestTo( wm.ball().pos(), 10, &nearest_opp_dist );
    if ( nearest_opp_dist < 4.0 )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": (doCheckReceiver) exist near opponent. dist=%.2f",
                      nearest_opp_dist );
        return false;
    }

    const AbstractPlayerObject * receiver = wm.ourPlayer( pass.targetPlayerUnum() );

    if ( ! receiver )
    {
        return false;
    }

    if ( receiver->seenPosCount() == 0 )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": (doCheckReceiver) receiver already seen." );
        return false;
    }

    //
    // set view mode
    //
    agent->setViewAction( new View_Synch() );

    const double next_view_half_width = agent->effector().queuedNextViewWidth().width() * 0.5;
    const double view_min = ServerParam::i().minNeckAngle() - next_view_half_width + 10.0;
    const double view_max = ServerParam::i().maxNeckAngle() + next_view_half_width - 10.0;

    //
    // check if turn_neck is necessary or not
    //
    const Vector2D next_self_pos = wm.self().pos() + wm.self().vel();
    const Vector2D player_pos = receiver->pos() + receiver->vel();
    const AngleDeg player_angle = ( player_pos - next_self_pos ).th();

    const double angle_diff = ( player_angle - wm.self().body() ).abs();

    if ( angle_diff < view_min
         || view_max < angle_diff )
    {
        //
        // need turn
        //

        dlog.addText( Logger::TEAM,
                      __FILE__": (doCheckReceiver) need turn."
                      " angleDiff=%.1f viewRange=[%.1f %.1f]",
                      angle_diff, view_min, view_max );

        //
        // TODO: check turn moment?
        //


        //
        // stop the ball
        //

        const double next_ball_dist = next_self_pos.dist( wm.ball().pos() + wm.ball().vel() );
        const double noised_kickable_area = wm.self().playerType().kickableArea()
            - wm.ball().vel().r() * ServerParam::i().ballRand()
            - wm.self().vel().r() * ServerParam::i().playerRand()
            - 0.15;

        dlog.addText( Logger::TEAM,
                      __FILE__": (doCheckReceiver) next_ball_dist=%.3f"
                      " noised_kickable=%.3f(kickable=%.3f)",
                      next_ball_dist,
                      noised_kickable_area,
                      wm.self().playerType().kickableArea() );

        if ( next_ball_dist > noised_kickable_area )
        {
            if ( doKeepBall( agent, pass ) )
            {
                return true;
            }

            if ( Body_StopBall().execute( agent ) )
            {
                dlog.addText( Logger::TEAM,
                              __FILE__": (doCheckReceiver) stop the ball" );
                agent->debugClient().addMessage( "PassKickFind:StopBall" );
                agent->debugClient().setTarget( receiver->unum() );

                return true;
            }

            dlog.addText( Logger::TEAM,
                          __FILE__": (doCheckReceiver) Could not stop the ball???" );
        }

        //
        // turn to receiver
        //

        doTurnBodyNeckToReceiver( agent, pass );
        return true;
    }

    //
    // can see the receiver without turn
    //
    dlog.addText( Logger::TEAM,
                  __FILE__": (doCheckReceiver) can see receiver[%d](%.2f %.2f)"
                  " angleDiff=%.1f viewRange=[%.1f %.1f]",
                  pass.targetPlayerUnum(),
                  player_pos.x, player_pos.y,
                  angle_diff, view_min, view_max );

    return false;

    // agent->debugClient().addMessage( "Pass:FindHold1" );
    // dlog.addText( Logger::TEAM,
    //               __FILE__": (doCheckReceiver) hold ball." );

    // Body_HoldBall( true,
    //                pass.targetPoint(),
    //                pass.targetPoint() ).execute( agent );
    // doSayPass( agent, pass );
    // agent->setNeckAction( new Neck_TurnToReceiver() );

    // return true;
}

/*-------------------------------------------------------------------*/
/*!

 */
/*
 问题:
 无
 
 理解:
 这个函数是Bhv_PassKickFindReceiver的doKeepBall函数,主要作用是根据getKeepBallVel()函数获得的保持球在keepArea区域的速度,与球自身的速度,来计算踢球的加速度和角度等,最后实现doKeepBall动作
 By ChenYanTing
 */
bool
Bhv_PassKickFindReceiver::doKeepBall( rcsc::PlayerAgent * agent,
                                      const CooperativeAction & pass )
{
    Vector2D ball_vel = getKeepBallVel( agent->world() );

    if ( ! ball_vel.isValid() )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": (doKeepBall) no candidate." );

        return false;
    }

    //
    // perform first kick
    //

    Vector2D kick_accel = ball_vel - agent->world().ball().vel();
    double kick_power = kick_accel.r() / agent->world().self().kickRate();
    AngleDeg kick_angle = kick_accel.th() - agent->world().self().body();

    if ( kick_power > ServerParam::i().maxPower() )
    {
        dlog.addText( Logger::TEAM,
                      __FILE__": (doKeepBall) over kick power" );
        return false;
    }

    dlog.addText( Logger::TEAM,
                  __FILE__": (doKeepBall) "
                  " ballVel=(%.2f %.2f)"
                  " kickPower=%.1f kickAngle=%.1f",
                  ball_vel.x, ball_vel.y,
                  kick_power,
                  kick_angle.degree() );

    agent->debugClient().addMessage( "PassKickFind:KeepBall" );
    agent->debugClient().setTarget( pass.targetPlayerUnum() );
    agent->debugClient().setTarget( agent->world().ball().pos()
                                    + ball_vel
                                    + ball_vel * ServerParam::i().ballDecay() );

    agent->doKick( kick_power, kick_angle );
    agent->setNeckAction( new Neck_TurnToReceiver( M_chain_graph ) );

    //
    // set turn intention
    //

    dlog.addText( Logger::TEAM,
                  __FILE__": (doKeepBall) register intention" );
    agent->setIntention( new IntentionPassKickFindReceiver( pass.targetPlayerUnum(),
                                                            pass.targetPoint() ) );

    return true;
}

/*-------------------------------------------------------------------*/
/*!

 */
/*
 问题:
 无
 
 理解:
 这个函数是Bhv_PassKickFindReceiver的getKeepBallVel函数,最重要的部分是for循环的内容,通过十二次遍历球员的一周,找到一个最佳位置的球的对应的速度,并且返回。
 By ChenYanTing
 */
rcsc::Vector2D
Bhv_PassKickFindReceiver::getKeepBallVel( const rcsc::WorldModel & wm )
{
    static GameTime s_update_time( 0, 0 );
    static Vector2D s_best_ball_vel( 0.0, 0.0 );

    if ( s_update_time == wm.time() )
    {
        return s_best_ball_vel;
    }
    s_update_time = wm.time();

    //
    //
    //

    const int ANGLE_DIVS = 12;

    const ServerParam & SP = ServerParam::i();
    const PlayerType & ptype = wm.self().playerType();
    const double collide_dist2 = std::pow( ptype.playerSize()
                                           + SP.ballSize(),
                                           2 );
    const double keep_dist = ptype.playerSize()
        + ptype.kickableMargin() * 0.5
        + ServerParam::i().ballSize();

    const Vector2D next_self_pos
        = wm.self().pos() + wm.self().vel();
    const Vector2D next2_self_pos
        = next_self_pos
        + wm.self().vel() * ptype.playerDecay();

    //
    // create keep target point
    //

    int best_angle = -1;
    Vector2D best_ball_vel = Vector2D::INVALIDATED;
    int best_opponent_step = 0;
    double best_ball_speed = 1000.0;


    for ( int a = 0; a < ANGLE_DIVS; ++a )
    {
        Vector2D keep_pos
            = next2_self_pos
            + Vector2D::from_polar( keep_dist,
                                    360.0/ANGLE_DIVS * a );
        if ( keep_pos.absX() > SP.pitchHalfLength() - 0.2
             || keep_pos.absY() > SP.pitchHalfWidth() - 0.2 )
        {
            continue;
        }

        Vector2D ball_move = keep_pos - wm.ball().pos();
        double ball_speed = ball_move.r() / ( 1.0 + SP.ballDecay() );

        Vector2D max_vel
            = KickTable::calc_max_velocity( ball_move.th(),
                                            wm.self().kickRate(),
                                            wm.ball().vel() );
        if ( max_vel.r2() < std::pow( ball_speed, 2 ) )
        {
            continue;
        }

        Vector2D ball_next_next = keep_pos;

        Vector2D ball_vel = ball_move.setLengthVector( ball_speed );
        Vector2D ball_next = wm.ball().pos() + ball_vel;

        if ( next_self_pos.dist2( ball_next ) < collide_dist2 )
        {
            ball_next_next = ball_next;
            ball_next_next += ball_vel * ( SP.ballDecay() * -0.1 );
        }

#ifdef DEBUG_PRINT
        dlog.addText( Logger::TEAM,
                      "(getKeepBallVel) %d: ball_move th=%.1f speed=%.2f max=%.2f",
                      a,
                      ball_move.th().degree(),
                      ball_speed,
                      max_vel.r() );
        dlog.addText( Logger::TEAM,
                      "__ ball_next=(%.2f %.2f) ball_next2=(%.2f %.2f)",
                      ball_next.x, ball_next.y,
                      ball_next_next.x, ball_next_next.y );
#endif

        //
        // check opponent
        //

        int min_step = 1000;
        for ( PlayerPtrCont::const_iterator o = wm.opponentsFromSelf().begin();
              o != wm.opponentsFromSelf().end();
              ++o )
        {
            if ( (*o)->distFromSelf() > 10.0 )
            {
                break;
            }

            int o_step = FieldAnalyzer::predict_player_reach_cycle( *o,
                                                                    ball_next_next,
                                                                    (*o)->playerTypePtr()->kickableArea(),
                                                                    0.0, // penalty distance
                                                                    1, // body count thr
                                                                    1, // default turn step
                                                                    0, // wait cycle
                                                                    true );

            if ( o_step < 0 )                                          //change
            {
                break;
            }

            if ( o_step < min_step )
            {
                min_step = o_step;
            }
        }
#ifdef DEBUG_PRINT
        dlog.addText( Logger::TEAM,
                      __FILE__": (getKeepBallVel) %d: keepPos=(%.2f %.2f)"
                      " ballNext2=(%.2f %.2f) ballVel=(%.2f %.2f) speed=%.2f o_step=%d",
                      a,
                      keep_pos.x, keep_pos.y,
                      ball_next_next.x, ball_next_next.y,
                      ball_vel.x, ball_vel.y,
                      ball_speed,
                      min_step );
#endif
        if ( min_step > best_opponent_step )
        {
            best_angle = a;
            best_ball_vel = ball_vel;
            best_opponent_step = min_step;
            best_ball_speed = ball_speed;
        }
        else if ( min_step == best_opponent_step )
        {
            if ( best_ball_speed > ball_speed )
            {
                best_angle = a;
                best_ball_vel = ball_vel;
                best_opponent_step = min_step;
                best_ball_speed = ball_speed;
            }
        }
    }

    s_best_ball_vel = best_ball_vel;
    return s_best_ball_vel;
}

/*-------------------------------------------------------------------*/
/*!

 */
/*
 问题:
 无
 
 理解:
 这个函数是Bhv_PassKickFindReceiver的doTurnBodyNeckToReceiver函数,主要通过往循环遍历,找到一个最合适的身体朝向,然后将身体转向reciever
 By ChenYanTing
 */
bool
Bhv_PassKickFindReceiver::doTurnBodyNeckToReceiver( PlayerAgent * agent,
                                                    const CooperativeAction & pass )
{
    const ServerParam & SP = ServerParam::i();
    const WorldModel & wm = agent->world();

    const AbstractPlayerObject * receiver = wm.ourPlayer( pass.targetPlayerUnum() );

    const double next_view_half_width = agent->effector().queuedNextViewWidth().width() * 0.5;
    const double view_min = SP.minNeckAngle() - next_view_half_width + 10.0;
    const double view_max = SP.maxNeckAngle() + next_view_half_width - 10.0;

    //
    // create candidate body target points
    //

    std::vector< Vector2D > body_points;
    body_points.reserve( 16 );

    const Vector2D next_self_pos = wm.self().pos() + wm.self().vel();
    const Vector2D receiver_pos = receiver->pos() + receiver->vel();
    const AngleDeg receiver_angle = ( receiver_pos - next_self_pos ).th();

    const double max_x = SP.pitchHalfLength() - 7.0;
    const double min_x = ( max_x - 10.0 < next_self_pos.x
                           ? max_x - 10.0
                           : next_self_pos.x );
    const double max_y = std::max( SP.pitchHalfLength() - 5.0,
                                   receiver_pos.absY() );
    const double y_step = std::max( 3.0, max_y / 5.0 );
    const double y_sign = sign( receiver_pos.y );

    // on the static x line (x = max_x)
    for ( double y = 0.0; y < max_y + 0.001; y += y_step )
    {
        body_points.push_back( Vector2D( max_x, y * y_sign ) );
    }

    // on the static y line (y == receiver_pos.y)
    for ( double x_rate = 0.9; x_rate >= 0.0; x_rate -= 0.1 )
    {
        double x = std::min( max_x,
                             max_x * x_rate + min_x * ( 1.0 - x_rate ) );
        body_points.push_back( Vector2D( x, receiver_pos.y ) );
    }

    //
    // evaluate candidate points
    //

    const double max_turn
        = wm.self().playerType().effectiveTurn( SP.maxMoment(),
                                                wm.self().vel().r() );
    Vector2D best_point = Vector2D::INVALIDATED;
    double min_turn = 360.0;

    const std::vector< Vector2D >::const_iterator p_end = body_points.end();
    for ( std::vector< Vector2D >::const_iterator p = body_points.begin();
          p != p_end;
          ++p )
    {
        AngleDeg target_body_angle = ( *p - next_self_pos ).th();
        double turn_moment_abs = ( target_body_angle - wm.self().body() ).abs();

#ifdef DEBUG_PRINT
        dlog.addText( Logger::TEAM,
                      "____ body_point=(%.1f %.1f) angle=%.1f moment=%.1f",
                      p->x, p->y,
                      target_body_angle.degree(),
                      turn_moment_abs );
#endif

        double angle_diff = ( receiver_angle - target_body_angle ).abs();
        if ( view_min < angle_diff
             && angle_diff < view_max )
        {
            if ( turn_moment_abs < max_turn )
            {
                best_point = *p;
#ifdef DEBUG_PRINT
                dlog.addText( Logger::TEAM,
                              "____ oooo can turn and look" );
#endif
                break;
            }

            if ( turn_moment_abs < min_turn )
            {
                best_point = *p;
                min_turn = turn_moment_abs;
#ifdef DEBUG_PRINT
                dlog.addText( Logger::TEAM,
                              "____ ---- update candidate point min_turn=%.1f",
                              min_turn );
#endif
            }
        }
#ifdef DEBUG_PRINT
        else
        {
            dlog.addText( Logger::TEAM,
                          "____ xxxx cannot look" );
        }
#endif
    }

    if ( ! best_point.isValid() )
    {
        best_point = pass.targetPoint();
#ifdef DEBUG_PRINT
        dlog.addText( Logger::TEAM,
                      __FILE__": (doTurnBodyNeckToPoint) could not find the target point." );
#endif
    }

    //
    // perform the action
    //
    agent->debugClient().addMessage( "PassKickFind:Turn" );
    agent->debugClient().setTarget( receiver->unum() );

    dlog.addText( Logger::TEAM,
                  __FILE__": (doTurnBodyNeckToReceiver)"
                  " receiver=%d receivePos=(%.2f %.2f)"
                  " turnTo=(%.2f %.2f)",
                  pass.targetPlayerUnum(),
                  pass.targetPoint().x, pass.targetPoint().y,
                  best_point.x, best_point.y );
    agent->debugClient().addLine( next_self_pos, best_point );

    Body_TurnToPoint( best_point ).execute( agent );
    doSayPass( agent, pass );
    agent->setNeckAction( new Neck_TurnToReceiver( M_chain_graph ) );

    return true;
}

/*-------------------------------------------------------------------*/
/*!

 */
/*
 问题:
 无
 
 理解:
 这个函数是Bhv_PassKickFindReceiver的doSayPass函数,作用是告知reciever我要传球了
 By ChenYanTing
 */
void
Bhv_PassKickFindReceiver::doSayPass( PlayerAgent * agent,
                                     const CooperativeAction & pass )
{
    const int receiver_unum = pass.targetPlayerUnum();
    const Vector2D & receive_pos = pass.targetPoint();

    if ( agent->config().useCommunication()
         && receiver_unum != Unum_Unknown
         && ! agent->effector().queuedNextBallKickable()
         )
    {
        const AbstractPlayerObject * receiver = agent->world().ourPlayer( receiver_unum );
        if ( ! receiver )
        {
            return;
        }

        dlog.addText( Logger::ACTION | Logger::TEAM,
                      __FILE__": (doSayPass) set pass communication." );

        Vector2D target_buf( 0.0, 0.0 );

        agent->debugClient().addMessage( "Say:pass" );

        Vector2D ball_vel( 0.0, 0.0 );
        if ( ! agent->effector().queuedNextBallKickable() )
        {
            ball_vel = agent->effector().queuedNextBallVel();
        }

        agent->addSayMessage( new PassMessage( receiver_unum,
                                               receive_pos + target_buf,
                                               agent->effector().queuedNextBallPos(),
                                               ball_vel ) );
    }
}

bhv_attackers_move.cpp

代码个人理解与存在的问题(已经通过注释标出)

注释的格式为:
/*
问题:
1.xxxx
2.xxxx

理解:
这个函数是xxxxx
By ChenYanTing
*/

// -*-c++-*-

/*
 *Copyright:

 Copyright (C) Hidehisa AKIYAMA

 This code is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.

 This code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this code; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

 *EndCopyright:
 */

/////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "bhv_attackers_move.h"
#include "bhv_basic_tackle.h"
#include "bhv_basic_move.h"     //以后要逐渐取代掉
#include <rcsc/action/body_intercept2009.h>
#include <rcsc/action/basic_actions.h>
#include <rcsc/action/bhv_scan_field.h>
#include <rcsc/action/body_go_to_point.h>
#include <rcsc/action/neck_scan_field.h>
#include <rcsc/action/neck_turn_to_ball_or_scan.h>
#include <rcsc/action/neck_turn_to_goalie_or_scan.h>
#include <rcsc/action/neck_turn_to_low_conf_teammate.h>
#include "strategy.h"
#include <rcsc/player/debug_client.h>
#include <rcsc/player/intercept_table.h>
#include <rcsc/player/player_agent.h>
#include <rcsc/player/soccer_intention.h>
#include <rcsc/player/say_message_builder.h>

#include <rcsc/common/audio_memory.h>
#include <rcsc/common/logger.h>
#include <rcsc/common/server_param.h>

//#define DEBUG2014

using namespace rcsc;

/*-------------------------------------------------------------------*/

/*-------------------------------------------------------------------*/
/*!
need to change:
    经常会几个人都去抢球
    跑位不太好
    中锋抢球范围不要太大
 */
/*
 问题:
 1.问题太多,不懂那些数字的设定,以后实战的时候再看这个函数应该好很多
 
 
 
 理解:
 这个函数是Bhv_AttackersMove的AttackersMove函数,主要作用是根据一堆我看不懂的数字来设置一堆我想不清的阙值,来实现的AttackersMove哈哈哈,我不懂这个函数
 By ChenYanTing
 */
bool
Bhv_AttackersMove::AttackersMove(PlayerAgent * agent)
{
  const WorldModel & wm = agent->world();

//  dlog.addText(Logger::TEAM,
//      __FILE__": AttackerOffensiveMove. target=(%.2f %.2f)", M_home_pos.x,
  //    M_home_pos.y);

  //------------------------------------------------------
  // tackle
  if (Bhv_BasicTackle(0.75, 90.0).execute(agent))
  {
    return true;;
  }

  //------------------------------------------------------
  int self_min = wm.interceptTable()->selfReachCycle();
  int mate_min = wm.interceptTable()->teammateReachCycle();
  int opp_min = wm.interceptTable()->opponentReachCycle();
 // dlog.addText(Logger::TEAM,
 //     __FILE__": execute. intercept cycle. self=%d, mate=%d, opp=%d", self_min,
 //     mate_min, opp_min);
  //------------------------------------------------------
  if (wm.self().stamina() > ServerParam::i().staminaMax() * 0.6
      && opp_min < 3
      && opp_min < mate_min - 2
      && (opp_min < self_min - 2 || opp_min == 0
          || (opp_min == 1 && self_min > 1))
      && wm.ball().pos().dist(M_home_pos) < 10.0
      && wm.ball().distFromSelf() < 15.0)
  {
    if (Body_ForestallBlock(agent))
    {
      agent->setNeckAction(new Neck_TurnToBall());
#ifdef DEBUG2014
      std::cerr << wm.time().cycle() << __FILE__ << wm.self().unum() << ": Body_ForestallBlock.\n";
#endif
      return true;
    }
  }

  //------------------------------------------------------
    //如果自己距离球的可达半径比队友小,那么就去得到球
  if ((mate_min >= 2 && self_min <= 4)
      || (self_min <= mate_min + 1 && mate_min >= 4))
  {
 //   dlog.addText(Logger::TEAM, __FILE__": execute. get ball");
 //   agent->debugClient().addMessage("AttGetBall");
    Vector2D face_point(52.5, wm.self().pos().y);

    Body_Intercept2009(true, face_point).execute(agent);
    if (self_min == 4 && opp_min >= 2)
    {
      agent->setViewAction(new View_Wide());
    }
    else if (self_min == 3 && opp_min >= 2)
    {
      agent->setViewAction(new rcsc::View_Normal());
    }
    agent->setNeckAction(new Neck_TurnToBallOrScan());
#ifdef DEBUG2014
    std::cerr << wm.time().cycle() << __FILE__ << wm.self().unum() << ": Body_Intercept.\n";
#endif // DEBUG2014

    return true;
  }

  //------------------------------------------------------

  const Vector2D mate_trap_pos = wm.ball().inertiaPoint(mate_min);

  Vector2D target_point = M_home_pos;

  const double max_x = std::max(wm.offsideLineX(), mate_trap_pos.x);
//  dlog.addText(Logger::TEAM, __FILE__": max x = %.1f", max_x);

  if (wm.self().pos().x > max_x && wm.self().pos().x < 42.0
  //&& std::fabs( wm.self().pos().y - M_home_pos.y ) < 10.0
      )
  {
    target_point.y = wm.self().pos().y;
  }

  if (std::fabs(mate_trap_pos.y - M_home_pos.y) < 15.0
      || mate_trap_pos.x > max_x - 5.0)
  {
    if (target_point.x > max_x - 1.5)
    {
      target_point.x = std::min(M_home_pos.x, max_x - 1.5);
    }
  }
  else
  {
    if (target_point.x > max_x - 3.0)
    {
      target_point.x = std::min(M_home_pos.x, max_x - 3.0);
    }
  }

#if 1
  // 2008-04-23 akiyama
  if (mate_min >= 3 && wm.self().pos().dist2(target_point) < 5.0 * 5.0)
  {
    double opp_dist = 1000.0;
    const PlayerObject * opp = wm.getOpponentNearestTo(target_point, 10,
        &opp_dist);
    if (opp && opp_dist < 4.0 && std::fabs(opp->pos().y - target_point.y) < 2.0)
    {
//             target_point.y += ( target_point.y > opp->pos().y
//                                 ? +3.0
//                                 : -3.0 );
      target_point.y = (
          target_point.y > opp->pos().y ?
              opp->pos().y + 2.0 : opp->pos().y - 2.0 );
//      dlog.addText(Logger::TEAM,
 //         __FILE__": adjust target point to avvoid opponent. y=%.1f",
 //         target_point.y);
    }
  }
#endif
#if 1
  // 2008-04-28 akiyama
  if (mate_min < 3 && std::fabs(wm.self().pos().y - M_home_pos.y) < 3.0)
  {
    target_point.y = wm.self().pos().y * 0.9 + M_home_pos.y * 0.1;
    ;
 //   dlog.addText(Logger::TEAM,
  //      __FILE__": adjust target point to prepare receive. y=%.1f",
  //      target_point.y);
  }
#endif

  bool breakaway = false;
  bool intentional = false;

  if (wm.existKickableTeammate() || mate_min <= 5 || mate_min <= opp_min + 1)
  {
    if (wm.self().pos().x > max_x)
    {
      if (std::fabs(mate_trap_pos.y - target_point.y) < 4.0)
      {
        double abs_y = wm.ball().pos().absY();
        bool outer = (wm.self().pos().absY() > abs_y );
        if (abs_y > 25.0)
          target_point.y = (outer ? 30.0 : 20.0 );
        else if (abs_y > 20.0)
          target_point.y = (outer ? 25.0 : 15.0 );
        else if (abs_y > 15.0)
          target_point.y = (outer ? 20.0 : 10.0 );
        else if (abs_y > 10.0)
          target_point.y = (outer ? 15.0 : 5.0 );
        else if (abs_y > 5.0)
          target_point.y = (outer ? 10.0 : 0.0 );
        else
          target_point.y = (outer ? 5.0 : -5.0 );

        if (wm.self().pos().y < 0.0)
        {
          target_point.y *= -1.0;
        }

   //     agent->debugClient().addMessage("AvoidOffside");
   //     dlog.addText(Logger::TEAM,
   //         __FILE__": avoid offside possibility. new_target=(%.1f %.1f)",
   //         target_point.x, target_point.y);
      }
    }
    else if (M_forward_player
    //&& wm.audioMemory().dribbleTime() != wm.time()
        && mate_min <= 2 && opp_min >= 3
        && mate_trap_pos.x > wm.offsideLineX() - 10.0
        && wm.self().stamina() > ServerParam::i().staminaMax() * 0.8
        && 5.0 < wm.self().pos().x && wm.self().pos().x < 27.0
        && wm.self().pos().x > max_x - 7.0 && wm.self().pos().x < max_x - 1.0
        && wm.self().pos().x < mate_trap_pos.x + 10.0
        && (std::fabs(mate_trap_pos.y - wm.self().pos().y) < 8.0
            || (mate_trap_pos - wm.self().pos()).th().abs() < 110.0
        //|| ( mate_trap_pos.x > wm.offsideLineX() - 8.0
        //     && std::fabs( mate_trap_pos.y - wm.self().pos().y ) < 20.0 )
        ) && wm.self().pos().dist(mate_trap_pos) < 20.0
        && std::fabs(M_home_pos.y - wm.self().pos().y) < 15.0)
    {
      double x_diff = max_x - wm.self().pos().x;
      int dash_step = wm.self().playerType().cyclesToReachDistance(x_diff);
      if (mate_min < dash_step - 1)
      {
        target_point.x = std::min(wm.self().pos().x + 20.0, 50.0);
        target_point.y = wm.self().pos().y * 0.8 + mate_trap_pos.y * 0.2;
        if (target_point.absY() > 8.0
            && target_point.absY() > M_home_pos.absY())
        {
          target_point.y = M_home_pos.y;
        }
        intentional = true;
      }

 //     dlog.addText(Logger::TEAM, __FILE__": try breakaway=(%.1f %.1f)",
  //        target_point.x, target_point.y);
      breakaway = true;
    }
  }

  const double dash_power = (
      breakaway ?
          ServerParam::i().maxPower() : getDashPower(agent, target_point) );

  if (dash_power < 1.0)
  {
    agent->debugClient().addMessage("AttackGoRecover");
    agent->debugClient().setTarget(target_point);
    AngleDeg face_angle = wm.ball().angleFromSelf() + 90.0;
    if (face_angle.abs() > 90.0)
      face_angle += 180.0;
    Body_TurnToAngle(face_angle).execute(agent);
    agent->setNeckAction(new Neck_TurnToBallOrScan());
    return true;
  }

  ///////////////////////////////////////////////////

  agent->debugClient().addMessage("AttackGo%.0f", dash_power);

  double dist_thr = std::fabs(wm.ball().pos().x - wm.self().pos().x) * 0.2
      + 0.25;
  //double dist_thr = wm.ball().pos().dist( target_point ) * 0.1 + 0.5;
  if (dist_thr < 1.0)
    dist_thr = 1.0;
  if (target_point.x > wm.self().pos().x - 0.5
      && wm.self().pos().x < wm.offsideLineX()
      && std::fabs(target_point.x - wm.self().pos().x) > 1.0)
  {
    dist_thr = std::min(1.0, wm.ball().pos().dist(target_point) * 0.1 + 0.5);
  }

 // agent->debugClient().setTarget(target_point);
//  agent->debugClient().addCircle(target_point, dist_thr);
 // dlog.addText(Logger::TEAM,
//      __FILE__": execute. go to (%.2f, %.2f) dash_power=%.2f", target_point.x,
//      target_point.y, dash_power);

  if (Body_GoToPoint(target_point, dist_thr, dash_power, 100, // cycle
      false, // back
      true, // stamina save
      25.0 // angle threshold
      ).execute(agent))
  {
    if (intentional)
    {
 //     agent->debugClient().addMessage("BreakAway");

  //    agent->debugClient().addMessage("Sayh");
      agent->addSayMessage(new PassRequestMessage(target_point));

 //     dlog.addText(Logger::TEAM, __FILE__": intention breakaway");
      agent->setArmAction(new Arm_PointToPoint(target_point));
    }
    #ifdef DEBUG2014
    std::cerr << wm.time().cycle() << __FILE__ << wm.self().unum() << ": Body_GoToPoint.\n";
    #endif // DEBUG2014

  }
  else
  {
    AngleDeg body_angle(0.0);
    Body_TurnToAngle(body_angle).execute(agent);
  }

  if (agent->world().ball().posCount() <= 1)
  {
    agent->setNeckAction(new Neck_ScanField());
  }
  else
  {
    agent->setNeckAction(new Neck_TurnToBallOrScan());
  }

  return true;
}

/*-------------------------------------------------------------------*/
/*!
    ht: 20140905
    from roleoffensivehalfmove::doGoToCrossPoint( rcsc::PlayerAgent * agent, const rcsc::Vector2D & home_pos )
    need to change
*/
/*
 问题:
 1.Circle2D类下的intersection是指的什么?
 
 理解:
 这个函数是Bhv_AttackersMove的doGoToCrossPoint函数,主要作用是根据一堆我看不懂的数字来设置一堆我想不清的阙值,来实现的AttackersMove哈哈哈,我不懂这个函数
 By ChenYanTing
 */
void
Bhv_AttackersMove::doGoToCrossPoint( rcsc::PlayerAgent * agent)
{
    rcsc::dlog.addText( rcsc::Logger::ROLE,
                        __FILE__": doGoToCrossPoint" );

    const rcsc::WorldModel & wm = agent->world();
    //------------------------------------------------------
    // tackle
    if ( Bhv_BasicTackle( 0.75, 90.0 ).execute( agent ) )
    {
        return;
    }

    //----------------------------------------------
    // intercept check
    int self_min = wm.interceptTable()->selfReachCycle();
    int mate_min = wm.interceptTable()->teammateReachCycle();
    int opp_min = wm.interceptTable()->opponentReachCycle();

    if ( self_min < mate_min
         || ( mate_min != 0 // ! wm.existKickableTeammate()  //try mate_min > 1
              && self_min <= 6
              && wm.ball().pos().dist( M_home_pos ) < 10.0 )
         //|| wm.interceptTable()->isSelfFastestPlayer()
         )
    {
        rcsc::dlog.addText( rcsc::Logger::ROLE,
                            __FILE__": doGoToCross. get ball" );
        agent->debugClient().addMessage( "CrossGetBall" );

        rcsc::Body_Intercept2009().execute( agent );

        if ( self_min == 3 && opp_min >= 3 )
        {
            agent->setViewAction( new rcsc::View_Normal() );
        }

        if ( wm.self().pos().x > 30.0 )
        {
            if ( ! doCheckCrossPoint( agent ) )
            {
                agent->setNeckAction( new rcsc::Neck_TurnToGoalieOrScan() );
            }
        }
        else
        {
            agent->setNeckAction( new rcsc::Neck_TurnToBallOrScan() );
        }
        return;
    }

    //----------------------------------------------
    // ball owner check
    if ( ! wm.interceptTable()->isOurTeamBallPossessor() )
    {
        const rcsc::PlayerObject * opp = wm.getOpponentNearestToBall( 3 );

        if ( opp
             && opp->distFromSelf() < 2.0 ) //3.0?
        {
            rcsc::dlog.addText( rcsc::Logger::ROLE,
                                __FILE__": doGoToCross. opp has ball" );
            agent->debugClient().addMessage( "CrossOppOwn(2)" );
            Bhv_BasicMove().execute( agent );
            return;
        }
    }

    //----------------------------------------------
    // set target

    rcsc::Vector2D target_point = M_home_pos;
    rcsc::Vector2D trap_pos = ( mate_min < 100
                                ? wm.ball().inertiaPoint( mate_min )
                                : wm.ball().pos() );

    if ( mate_min <= opp_min
         && mate_min < 3
         && target_point.x < 38.0
         && wm.self().pos().x < wm.offsideLineX() - 1.0
         //&& target_point.x < wm.self().pos().x
         //&& std::fabs( target_point.x - wm.self().pos().x ) < 20.0
         && std::fabs( target_point.y - wm.self().pos().y ) < 5.0
         && std::fabs( wm.self().pos().y - trap_pos.y ) < 13.0
         )
    {
        target_point.y = wm.self().pos().y * 0.9 + M_home_pos.y * 0.1;
        rcsc::dlog.addText( rcsc::Logger::ROLE,
                            __FILE__": doGoToCross. chance keep current." );
        agent->debugClient().addMessage( "CrossCurPos" );
    }

    // consider near opponent
    if ( target_point.x > 36.0 )
    {
        double opp_dist = 200.0;
        const rcsc::PlayerObject * opp = wm.getOpponentNearestTo( target_point,
                                                                  10,
                                                                  &opp_dist );
        if ( opp && opp_dist < 2.0 )
        {
            rcsc::Vector2D tmp_target = target_point;
            for ( int i = 0; i < 3; ++i )
            {
                tmp_target.x -= 1.0;

                double d = 0.0;
                opp = wm.getOpponentNearestTo( tmp_target, 10, &d );
                if ( ! opp )
                {
                    opp_dist = 0.0;
                    target_point = tmp_target;
                    break;
                }
                if ( opp
                     && opp_dist < d )
                {
                    opp_dist = d;
                    target_point = tmp_target;
                }
            }
            rcsc::dlog.addText( rcsc::Logger::ROLE,
                                __FILE__": doGoToCross. avoid(%.2f, %.2f)->(%.2f, %.2f)",
                                M_home_pos.x, M_home_pos.y,
                                target_point.x, target_point.y );
            agent->debugClient().addMessage( "Avoid" );
        }
    }

    if ( target_point.dist( trap_pos ) < 6.0 )
    {
        rcsc::Circle2D target_circle( trap_pos, 6.0 );
        rcsc::Line2D target_line( target_point, rcsc::AngleDeg( 90.0 ) );
        rcsc::Vector2D sol_pos1, sol_pos2;
        
        int n_sol = target_circle.intersection( target_line, &sol_pos1, &sol_pos2 );

        if ( n_sol == 1 ) target_point = sol_pos1;
        if ( n_sol == 2 )
        {
            target_point = ( wm.self().pos().dist2( sol_pos1 ) < wm.self().pos().dist2( sol_pos2 )
                             ? sol_pos1
                             : sol_pos2 );

        }

        rcsc::dlog.addText( rcsc::Logger::ROLE,
                            __FILE__": doGoToCross. adjust ot avoid the ball owner." );
        agent->debugClient().addMessage( "Adjust" );
    }

    //----------------------------------------------
    // set dash power
    // check X buffer & stamina
    static bool s_recover_mode = false;
    if ( wm.self().pos().x > 35.0
         && wm.self().stamina()
         < rcsc::ServerParam::i().recoverDecThrValue() + 500.0 )
    {
        s_recover_mode = true;
        rcsc::dlog.addText( rcsc::Logger::ROLE,
                            __FILE__": doGoToCross. recover on" );
    }

    if ( wm.self().stamina() > rcsc::ServerParam::i().staminaMax() * 0.5 )
    {
        s_recover_mode = false;
        rcsc::dlog.addText( rcsc::Logger::ROLE,
                            __FILE__": doGoToCross. recover off" );
    }

    double dash_power = rcsc::ServerParam::i().maxPower();
    if ( s_recover_mode )
    {
        const double my_inc
            = wm.self().playerType().staminaIncMax()
            * wm.self().recovery();
        dash_power = std::max( 1.0, my_inc - 25.0 );
        //dash_power = wm.self().playerType().staminaIncMax() * 0.6;
    }
    else if ( wm.ball().pos().x > wm.self().pos().x )
    {
        if ( wm.existKickableTeammate()
             && wm.ball().distFromSelf() < 10.0
             && std::fabs( wm.self().pos().x - wm.ball().pos().x ) < 5.0
             && wm.self().pos().x > 30.0
             && wm.ball().pos().x > 35.0 )
        {
            dash_power *= 0.5;
        }
    }
    else if ( wm.self().pos().dist( target_point ) < 3.0 )
    {
        const double my_inc
            = wm.self().playerType().staminaIncMax()
            * wm.self().recovery();
        dash_power = std::min( rcsc::ServerParam::i().maxPower(),
                               my_inc + 10.0 );
        //dash_power = rcsc::ServerParam::i().maxPower() * 0.8;
    }
    else if ( mate_min <= 1
              && wm.ball().pos().x > 33.0
              && wm.ball().pos().absY() < 7.0
              && wm.ball().pos().x < wm.self().pos().x
              && wm.self().pos().x < wm.offsideLineX()
              && wm.self().pos().absY() < 9.0
              && std::fabs( wm.ball().pos().y - wm.self().pos().y ) < 3.5
              && std::fabs( target_point.y - wm.self().pos().y ) > 5.0 )
    {
        dash_power = wm.self().playerType()
            .getDashPowerToKeepSpeed( 0.3, wm.self().effort() );
        dash_power = std::min( rcsc::ServerParam::i().maxPower() * 0.75,
                               dash_power );
        rcsc::dlog.addText( rcsc::Logger::ROLE,
                            __FILE__": doGoToCross. slow for cross. power=%.1f",
                            dash_power );
    }

#if 1


    bool intentional = true;    //false;

    const Vector2D mate_trap_pos = wm.ball().inertiaPoint(mate_min);

    const double max_x = std::max(wm.offsideLineX(), mate_trap_pos.x);

    if (wm.existKickableTeammate() || mate_min <= 5 || mate_min <= opp_min + 1)
    {
    }
    else if (M_forward_player
    //&& wm.audioMemory().dribbleTime() != wm.time()
        && mate_min <= 2 && opp_min >= 3
        && mate_trap_pos.x > wm.offsideLineX() - 10.0
        && wm.self().stamina() > ServerParam::i().staminaMax() * 0.8
        && 5.0 < wm.self().pos().x && wm.self().pos().x < 27.0
        && wm.self().pos().x > max_x - 7.0 && wm.self().pos().x < max_x - 1.0
        && wm.self().pos().x < mate_trap_pos.x + 10.0
        && (std::fabs(mate_trap_pos.y - wm.self().pos().y) < 8.0
            || (mate_trap_pos - wm.self().pos()).th().abs() < 110.0
        //|| ( mate_trap_pos.x > wm.offsideLineX() - 8.0
        //     && std::fabs( mate_trap_pos.y - wm.self().pos().y ) < 20.0 )
        ) && wm.self().pos().dist(mate_trap_pos) < 20.0
        && std::fabs(M_home_pos.y - wm.self().pos().y) < 15.0)
    {
      double x_diff = max_x - wm.self().pos().x;
      int dash_step = wm.self().playerType().cyclesToReachDistance(x_diff);
      if (mate_min < dash_step - 1)
      {
        target_point.x = std::min(wm.self().pos().x + 20.0, 50.0);
        target_point.y = wm.self().pos().y * 0.8 + mate_trap_pos.y * 0.2;
        if (target_point.absY() > 8.0
            && target_point.absY() > M_home_pos.absY())
        {
//          target_point.y = M_home_pos.y;
        }
        intentional = true;
      }
    }
#endif // 1

    //----------------------------------------------
    // positioning to make the cross course!!

    double dist_thr = wm.ball().distFromSelf() * 0.1;
    if ( dist_thr < 0.5 ) dist_thr = 0.5;

    agent->debugClient().addMessage( "GoToCross%.0f", dash_power );
    agent->debugClient().setTarget( target_point );
    agent->debugClient().addCircle( target_point, dist_thr );

    rcsc::dlog.addText( rcsc::Logger::ROLE,
                        __FILE__": doGoToCross. to (%.2f, %.2f)",
                        target_point.x, target_point.y );

    if ( wm.self().pos().x > target_point.x + dist_thr
         && std::fabs( wm.self().pos().x - target_point.x ) < 3.0
         && wm.self().body().abs() < 10.0 )
    {
        agent->debugClient().addMessage( "Back" );
        double back_dash_power
            = wm.self().getSafetyDashPower( -dash_power );
        rcsc::dlog.addText( rcsc::Logger::ROLE,
                            __FILE__": doShootAreaMove. Back Move" );
        agent->doDash( back_dash_power );
    }
    else
    {
        if ( ! rcsc::Body_GoToPoint( target_point, dist_thr, dash_power,
                                     5, // cycle
                                     false, // no back dash
                                     true, // save recovery
                                     30.0 // dir thr
                                     ).execute( agent ) )
        {
            rcsc::Body_TurnToAngle( 0.0 ).execute( agent );
        }
        else
        {
            if (intentional)
            {
         //     agent->debugClient().addMessage("BreakAway");

          //    agent->debugClient().addMessage("Sayh");
              agent->addSayMessage(new PassRequestMessage(target_point));

         //     dlog.addText(Logger::TEAM, __FILE__": intention breakaway");
              agent->setArmAction(new Arm_PointToPoint(target_point));
            }
        }
    }



    if ( wm.self().pos().x > 30.0 )
    {
        agent->setNeckAction( new rcsc::Neck_TurnToGoalieOrScan() );
    }
    else
    {
        agent->setNeckAction( new rcsc::Neck_TurnToLowConfTeammate() );
    }
}

/*-------------------------------------------------------------------*/
/*!
    ht: 20140905
    from roleoffensivehalfmove::doCheckCrossPoint( rcsc::PlayerAgent * agent )
    for doGoToCrossPoint()
*/
/*
 问题:
 1.726行的opposite_pole是指的什么?
 
 理解:
 这个函数是Bhv_AttackersMove的doCheckCrossPoint函数,主要作用是根据一些变量来返回true或者false,但是具体这些变量是怎么得到的,我不是很清楚
 By ChenYanTing
 */
bool
Bhv_AttackersMove::doCheckCrossPoint( rcsc::PlayerAgent * agent )
{
    const rcsc::WorldModel & wm = agent->world();

    if ( wm.self().pos().x < 35.0 )
    {
        return false;
    }

    const rcsc::PlayerObject * opp_goalie = wm.getOpponentGoalie();
    if ( opp_goalie && opp_goalie->posCount() > 2 )
    {
        rcsc::dlog.addText( rcsc::Logger::ROLE,
                            __FILE__": doCheckCrossTarget  goalie should be checked" );
        return false;
    }

    rcsc::Vector2D opposite_pole( 46.0, 7.0 );
    if ( wm.self().pos().y > 0.0 ) opposite_pole.y *= -1.0;

    rcsc::AngleDeg opposite_pole_angle = ( opposite_pole - wm.self().pos() ).th();


    if ( wm.dirCount( opposite_pole_angle ) <= 1 )
    {
        rcsc::dlog.addText( rcsc::Logger::ROLE,
                            __FILE__": doCheckCrossTarget enough accuracy to angle %.1f",
                            opposite_pole_angle.degree() );
        return false;
    }

    rcsc::AngleDeg angle_diff
        = agent->effector().queuedNextAngleFromBody( opposite_pole );
    if ( angle_diff.abs() > 100.0 )
    {
        rcsc::dlog.addText( rcsc::Logger::ROLE,
                            __FILE__": doCheckCrossPoint. want to face opposite pole,"
                            " but over view range. angle_diff=%.1f",
                            angle_diff.degree() );
        return false;
    }


    agent->setNeckAction( new rcsc::Neck_TurnToPoint( opposite_pole ) );
    agent->debugClient().addMessage( "NeckToOpposite" );
    rcsc::dlog.addText( rcsc::Logger::ROLE,
                        __FILE__": doCheckCrossPoint Neck to oppsite pole" );
    return true;
}

/*-------------------------------------------------------------------*/
/*!

 */
/*
 问题:
 1.wm.offsideLineX()指的什么?
 
 理解:
 这个函数是Bhv_AttackersMove的getDashPower函数,主要作用是根据敌人的位置、自己的位置、球的位置等等因素来判断自己的耐力值应该选择消耗多少
 By ChenYanTing
 */
double
Bhv_AttackersMove::getDashPower(const PlayerAgent * agent,
    const Vector2D & target_point)
{
  const WorldModel & wm = agent->world();
  int mate_min = wm.interceptTable()->teammateReachCycle();
  int opp_min = wm.interceptTable()->opponentReachCycle();

  if (target_point.x > wm.self().pos().x
      && wm.self().stamina() > ServerParam::i().staminaMax() * 0.7
      && mate_min <= 8)
  {
    Vector2D receive_pos = wm.ball().inertiaPoint(mate_min);
    if (std::fabs(receive_pos.y - target_point.y) < 15.0)
    {
 //     dlog.addText(Logger::TEAM, __FILE__": getDashPower. chance. fast move");
      return ServerParam::i().maxPower();
    }
  }

  if (wm.self().pos().x > wm.offsideLineX()
      && (wm.existKickableTeammate() || mate_min <= opp_min + 2))
  {
    Vector2D receive_pos = wm.ball().inertiaPoint(mate_min);
    if (target_point.x < receive_pos.x + 30.0
        && wm.self().pos().dist(receive_pos) < 30.0
        && wm.self().pos().dist(target_point) < 20.0)
    {
//      dlog.addText(Logger::TEAM, __FILE__": getDashPower. offside max power");

      return ServerParam::i().maxPower();
    }
  }

  //------------------------------------------------------
  // decide dash power
  static bool s_recover_mode = false;
  if (wm.self().stamina() < ServerParam::i().staminaMax() * 0.4)
  {
 //   dlog.addText(Logger::TEAM,
 //       __FILE__": getDashPower. change to recover mode.");
    s_recover_mode = true;
  }
  else if (wm.self().stamina() > ServerParam::i().staminaMax() * 0.7)
  {
//    dlog.addText(Logger::TEAM,
//        __FILE__": getDashPower. came back from recover mode");
    s_recover_mode = false;
  }

  const double my_inc = wm.self().playerType().staminaIncMax()
      * wm.self().recovery();

  // dash power
  if (s_recover_mode)
  {
    // Magic Number.
    // recommended one cycle's stamina recover value
 //   dlog.addText(Logger::TEAM, __FILE__": getDashPower. recover mode");
    return std::max(0.0, my_inc - 30.0);
  }

  if (!wm.opponentsFromSelf().empty()
      && wm.opponentsFromSelf().front()->distFromSelf() < 1.0)
  {
    // opponent is very close
    // full power
    dlog.addText(Logger::TEAM,
        __FILE__": getDashPower. exist near opponent. full power");
    return ServerParam::i().maxPower();
  }

  if (wm.ball().pos().x < wm.self().pos().x
      && wm.self().pos().x < wm.offsideLineX())
  {
    // ball is back
    // not offside
 //   dlog.addText(Logger::TEAM,
//        __FILE__": getDashPower. ball is back and not offside.");
    if (wm.self().stamina() < ServerParam::i().staminaMax() * 0.8)
    {
      return std::min(std::max(5.0, my_inc - 30.0), ServerParam::i().maxPower());
    }
    else
    {
      return std::min(my_inc * 1.1, ServerParam::i().maxPower());
    }
  }

  if (wm.ball().pos().x > wm.self().pos().x + 3.0)
  {
    // ball is front
    if (opp_min <= mate_min - 3)
    {
      if (wm.self().stamina() < ServerParam::i().staminaMax() * 0.6)
      {
  //      dlog.addText(Logger::TEAM,
  //          __FILE__": getDashPower. ball is front. recover");
        return std::min(std::max(0.1, my_inc - 30.0),
            ServerParam::i().maxPower());
      }
      else if (wm.self().stamina() < ServerParam::i().staminaMax() * 0.8)
      {
 //       dlog.addText(Logger::TEAM,
 //           __FILE__": getDashPower. ball is front. keep");
        return std::min(my_inc, ServerParam::i().maxPower());
      }
      else
      {
 //       dlog.addText(Logger::TEAM,
//            __FILE__": getDashPower. ball is front. max");
        return ServerParam::i().maxPower();
      }
    }
    else
    {
 //     dlog.addText(Logger::TEAM,
 //         __FILE__": getDashPower. ball is front full powerr");
      return ServerParam::i().maxPower();
    }
  }

 // dlog.addText(Logger::TEAM, __FILE__": getDashPower. normal mode.");
  if (target_point.x > wm.self().pos().x + 2.0
      && wm.self().stamina() > ServerParam::i().staminaMax() * 0.6)
  {
    return ServerParam::i().maxPower();
  }
  else if (wm.self().stamina() < ServerParam::i().staminaMax() * 0.8)
  {
    return std::min(my_inc * 0.9, ServerParam::i().maxPower());
  }
  else
  {
    return std::min(my_inc * 1.5, ServerParam::i().maxPower());
  }
}

/*
 问题:
 1.962到968行,身体朝向为什么要这样设定?
 
 理解:
 这个函数是Bhv_AttackersMove的Body_ForestallBlock函数,主要作用是负责球员在各个快之间的移动
 By ChenYanTing
 */
bool
Bhv_AttackersMove::Body_ForestallBlock(PlayerAgent * agent)
{
  int S_count_no_move = 0 ;
  const rcsc::WorldModel & wm = agent->world();
  rcsc:Vector2D home_pos = Strategy::i().getPosition(wm.self().unum());
  rcsc::Vector2D block_point = home_pos;

  if (!block_point.isValid())
  {
    return false;
  }

  double dist_thr = 1.0;

 // agent->debugClient().addMessage("forestall");
 // agent->debugClient().setTarget(block_point);
 // agent->debugClient().addCircle(block_point, dist_thr);

  double dash_power = wm.self().getSafetyDashPower(
      rcsc::ServerParam::i().maxPower());

  if (rcsc::Body_GoToPoint(block_point, dist_thr, dash_power, 5, // cycle
      false, // no back dash
      true, // save recovery
      40.0 // dir_thr
      ).execute(agent))
  {
    S_count_no_move = 0;
    return true;
  }

#if 1
  ++S_count_no_move;

  if (S_count_no_move >= 10)
  {
 //   rcsc::dlog.addText(rcsc::Logger::TEAM,
 //       __FILE__": forestall. long no move. attack to the ball");
 //   agent->debugClient().addMessage("ForestallAttack");
    Body_Intercept2009(true).execute(agent);
    return true;
  }
#endif

  rcsc::AngleDeg body_angle = wm.ball().angleFromSelf() + 90.0;
  if (body_angle.abs() < 90.0)
  {
    body_angle += 180.0;
  }

  rcsc::Body_TurnToAngle(body_angle).execute(agent);

  return true;
}

学习心得与体会

这次主要看的都是一些比较基础的cpp代码,但是发现这些基础代码并不是很好看懂,因为有很多涉及到阙值的设定,和一些数学的问题。所以我觉得这一块的内容其实可以先看个大概,具体原理可以等到跑代码的时候,根据场上球员的实际情况来理解代码!

posted @ 2020-01-18 21:04  南孚先生  阅读(274)  评论(0编辑  收藏  举报