实验二   doPreprocess()(kick 和 dash)

1、实验目的:

  1. 了解 doPreprocess 的工作原理
  2. 会对 doPreprocess 进行简单的修改

    2、实验设备

    硬件环境:PC
    软件环境:Linux

    3、实验内容

    1. doPreprocess 的工作原理:

    doPreprocess 函数负责在动作链之前对球队的各类特殊情况进行处理,它如果产生了动作就返回true,否则返回false,由后面的动作链来决定执行的动作。在 doPreprocess 中有一系列的判断来决定每个周期的动作。下面对 doPreprocess 进行简要的分析.
    doPreprocess()是一个决策函数,在策略上使用的是下面这个简单的策略:

    // check tackle expires 检查截球有效性 // check self position accuracy 检查自身位置的有效性 // ball search 球的搜索 // check queued intention 检查队列的目的 // check simultaneous kick 检查即时的行动

我们现在先看一下球可踢时的代码:
在调用SamplePlayer::doForceKick()函数中:

bool
SamplePlayer::doForceKick()
{
    const WorldModel & wm = this->world(); //获得世界模型

    if ( wm.gameMode().type() == GameMode::PlayOn //比赛模式
         && ! wm.self().goalie()  //不是守门员
         && wm.self().isKickable()  // 球可踢
         && wm.existKickableOpponent() ) // 对手也可以进行踢球
    {
        Vector2D goal_pos( ServerParam::i().pitchHalfLength(), 0.0 ); // 对方球门中心

        if ( wm.self().pos().x > 36.0
             && wm.self().pos().absY() > 10.0 )
        {
            goal_pos.x = 45.0;
        }
        Body_KickOneStep( goal_pos, // 踢球的函数
                          ServerParam::i().ballSpeedMax() // 速度
                        ).execute( this ); // 将自身对象传过去,因为动作要调用自身对象的函数 有兴趣可以看一下里边。
        this->setNeckAction( new Neck_ScanField() );
        return true; // 进行了动作
    }

    return false; // 返回false 由动作链处理其他的内容
}

这一小段函数决定了当球在球员 Agent 的可踢范围之内时应当做的动作,这里是一个简单的根据一些情况进行踢球的方法。该程序段的条理是很清晰的。
总结一下,调用踢球的函数就是Body_KickOneStep(位置,速度).excute(this)

2.对 doPreprocess 进行简单的修改:

现在我们对 doPreprocess 进行简单的修改,让它在球可踢的时候进行带球的动作。带球就是 kick 和 dash 动作序列的结合。
带球的函数为 Body_Dribble()
它接收4个参数,第一个参数为带球要到达的目标点,第二个参数为带球的力量参数。第三个参数是提踢球后有几个dash命令。

Body_Dribble(Vector2D(0,0),
              1.0,
              ServerParam::i().maxDashPower(),
              2
            ).execute(this);

调用的execute函数的返回值是一个 bool 类型。 标志着是否进行了带球动作。 知道了如何调用 dribble,我们将其加入doPreprocess函数的前边:

#include <rcsc/action/body_dribble.h>
// 注意在文件中加入需要的头文件

if ( wm.self().isKickable() ){
    Vector2D goal_pos( ServerParam::i().pitchHalfLength() - 5, 0.0 );
    Body_Dribble( goal_pos,
                          1.0,
                          ServerParam::i().maxDashPower(),
                          2
                          ).execute(this);
    return true;
}

这样,在球可踢的时候,球员 Agent 将把球带向球门,即一直向球门前快速带球。

我们再次对 doPreprocess 函数进行修改,这次是让球员 Agent 将球踢向各个不同的地方。这将调用 Body_KickOneStep()的 execute()函数来完成。下面简要说明一下Body_KickOneStep()函数的使用方法:这个函数有两个参数,第一个参数是目标点的坐标,第二个参数是球到达目标点是的速度,返回是否成功执行了动作。可以使用下面的形式来调用:

Body_KickOneStep( goal_pos,
                  ServerParam::i().ballSpeedMax()
                  ).execute( this );

函数在其内部将会决定踢球时所用力量的大小,并且会判断是否能够将球踢到该点, 并作出相应的调整。比如,将球以最大的速度踢向(0,0):

    if ( wm.self().isKickable() &&
         Body_KickOneStep( Vector2D(0,0),
                            ServerParam::i().ballSpeedMax()
                            ).execute(this))
    return true;
  • 根据上述操作,完成以下踢球操作:

    • 将球踢向对方的球门。
    • 将球踢向距离自己最近的队友。
    • 尝试不同的踢球点。

以下是一些可能用到的函数:

  1. 得到对方球门的坐标.
    Vector2D goal_pos( ServerParam::i().pitchHalfLength(), 0.0 );
    
  2. 得到距离自己最近的队员
    PlayerObject* nearteammate = wm.teammatesFromSelf()[0];
    
  3. 得到一个对象的坐标

    Vector2D pos = nearteammate->pos();
    

    更多的函数请查找教材,或者查看源程序的 WorldModel.cpp, PlayerObject.cpp等文件。

  4. 根据上述操作,完成以下带球的操作:

    • 用不同的带球速度进行带球。
    • 将球向对方的球门方向带。
    • 尝试不同的踢球位置以及速度。
  5. 根据上述内容,完成以下综合联系:
    带球与踢球的结合:

    • 让 agent 一直向对方球门的方向带球,在进入对方禁区后以最大力量踢向球门。涉及到的具体函数请查看教材。
Copyright@Njupt-Apollo-2d-2021 all right reserved,powered by Gitbook该文件最新修订时间: 2022-02-26 09:05:41

results matching ""

    No results matching ""