实验五 特殊比赛模式的开球设计
1、实验目的
1.掌握 Robocup 仿真机器人足球比赛中特殊比赛模式发生的条件;
2.掌握 Robocup 仿真机器人足球比赛特殊比赛模式的规则要求;
3.了解 Robocup 仿真机器人足球比赛特殊比赛模式的战术设计思想;
4.进一步熟悉 WorldModel 类。
2、实验设备
硬件环境:PC机
软件环境:操作系统Linux
3.实验内容
(1)概述
Robocup 仿真机器人足球比赛特殊比赛模式包括角球(corner_kick)、界外球(kick_in)、 定位球/任意球(free_kick)以及球门球(goal_kick)。
在各 play mode 当中,若是我方球队的 定点球(set play) 时,必须采取对我方恰当的Play Mode,包括: kick in , corner kick , goal kick ,直接 free kick ,间接 free kick ,还包括守门员拿球后的 free kick 。除守门员拿球的情况以外,必须决定由谁来开球。而且承担开球的球员必须让他在合适的时机开球。
在球队中的角色分配和形成的信息已被静态地确定,如果是球员之间的共享,您可能要选择的战略的基础上踢球。但是,它减弱了客户端程序的障碍,比如漏掉球员。下面我们将选择一个简单的思路,即最近的球员作为开球者:
bool isKicker( const PlayerAgent * agent, const Vector2D & home_pos) {
const WorldModel & wm = agent->world();
const long wait_cycle = 30;
if ( wm.getTeammatesFromBall().empty() )
return true;
const PlayerObject * nearest_mate = nearest_mate = wm.getTeammatesFromBall().front();
if ( wm.getSetPlayCount() < wait_cycle
|| ( nearest_mate
&& nearest_mate->distFromBall() < wm.ball().distFromSelf() * 0.9 )
) {
return false;
}
return true;
}
在这个例子中,运行 isKicker 函数来确定自己是否是开球人的函数。这是一个简单的实现,但在大多数情况下它都能运行良好。
函数内声明了 wait cycle 变量,决定了直至选择开球者的待机周期数。首先, PlayMode发生改变之后, wait cycle 不运行 isKicker 的判断。以此来确保有时间来移动到原来的位置 Home Position 。 wait cycle 经过后,比较最靠近球的伙伴球员和自己,如果自己离球更近,就判定自己为开球者。
(2)角球(corner_kick)
当防守方球员将球踢出底线时,由进攻方开角球。Server 一旦接收到发球队员发出的 kick 命令后,就将比赛模式设为正常的 play_on 模式。注意,和国际足联的规则类似,发球 队员在其他球员接触球之前不能再触球,否则判犯规。此时,另一方球员须在一定时间(根 据 Manual 的规定为 300 周期)内将球开出,否则算发球失误,由对方发定位球。
case CornerKick_:
return ( side() == LEFT
? PM_CornerKick_Left
: PM_CornerKick_Right );
判断角球方位
switch ( wm.gameMode().type() ) {
case GameMode::CornerKick_:
if ( wm.gameMode().side() == wm.ourSide() )//判断发球归属方
{
return Bhv_SetPlayKickIn().execute( agent );
}
else
{
doBasicTheirSetPlayMove( agent );
return true;
}
break;
}
判定比赛模式 并对角球模式做出应对
if判断是不是我方开角球
函数void Bhv_SetPlay::doBasicTheirSetPlayMove( PlayerAgent *agent );是开始执行基本动作
bool
Bhv_SetPlayKickIn::execute( PlayerAgent * agent )
{
dlog.addText( Logger::TEAM,
__FILE__": Bhv_SetPlayKickIn" );
if ( Bhv_SetPlay::is_kicker( agent ) )//是否是持球的球员
{
doKick( agent );//持球球员对射球进行判定
}
else
{
doMove( agent );//非持球队员进行移动判定
}
return true;
}
函数bool Bhv_SetPlayKickIn::execute( PlayerAgent * agent ) 通过判断是否是合适的射球时机来决定是执行射球动作 还是移动动作到球的方位 不同的球员根据所在位置和自身属性而确定即将执行的动作
首先我们知道doPreprocess 函数负责在动作链之前对球队的各类特殊情况进行处理(实验二),在 doPreprocess 中有一系列的判断来决定每个周期的动作 。
(3)界外球(kick_in)
当一方球员将球踢出边线时,比赛即进入界外球模式。
case KickIn_:
return ( side() == LEFT
? PM_KickIn_Left
: PM_KickIn_Right );
比赛的规则要求基本同角球。
简单的设计思路和实验内容与角球也差不多,在此不再赘述。
要求同学们尝试仿照角球的逻辑编写一段程序实现界外球策略,要求能够根据发球点的位置给出合适的 接应球员的接应位置。
switch ( wm.gameMode().type() ) {
case GameMode::KickIn_:
/*
your code
*/
break;
(4)定位球/任意球(free_kick)
当一方球员犯规或违例时,由对方开任意球。跟国际足联的规定略有不同的是,Robocup 的任意球没有直接任意球跟间接任意球之分。
case FreeKick_:
return ( side() == LEFT
? PM_FreeKick_Left
: PM_FreeKick_Right )
比赛的规则要求基本同界外球。
简单的设计思路和实验内容与界外球也差不多,在此不再赘述。略有不同的是,如果条 件允许,开球队员可以选择直接射门。另外,有能力的同学可以在这里考虑实现开球队员等 待一段时间再开球的策略(提示,要用到锁定机制)。
要求完成一种任意球的开球动作。
switch ( wm.gameMode().type() ) {
case GameMode::FreeKick_:
/*
your code
*/
break;
(5)球门球(goal_kick)
当对方进攻球员将球踢出底线或我方守门员截住对方射门的球时,由我方守门员开门 球。注意,如果守门员截住的是己方后卫的回传球,那么会由对方球员在离截球点最近的禁 区角点发任意球,因为这是违例行为。
case GoalKick_:
return ( side() == LEFT
? PM_GoalKick_Left
: PM_GoalKick_Right )
如果守门员在 300 周期内不能将球开出,那么由对方球员在离开球点最近的禁区角点发 任意球。
在 UVA_trilearn 的源代码中,守门员开球也是直接将球踢向对方球门。而开门球是一个 比较复杂且非常重要的细节,许多强队,诸如清华、科大,都有不错的开门球策略。我们这次实验只完成一个简单的策略,即守门员沿某一直线开球,该直线是最近对方球员、守门员、 次近对方球员三点所构成角的角平分线。
注:
各种特殊比赛模式的开球都集中在game_mode.h
中 下面举出其余有关的class:
Bhv_SetPlayFreeKick
Bhv_SetPlayGoalKick
Bhv_SetPlayKickIn
Bhv_SetPlayKickOff
这样虽然增大了程序设计的复杂性,但却大大增强了程序的可读性。