Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

soccerruleaspect.cpp

Go to the documentation of this file.
00001 /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*-
00002 
00003    this file is part of rcssserver3D
00004    Fri May 9 2003
00005    Copyright (C) 2002,2003 Koblenz University
00006    Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group
00007    $Id: soccerruleaspect.cpp,v 1.21 2006/03/13 22:08:25 fruit Exp $
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; version 2 of the License.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 #include "soccerruleaspect.h"
00023 #include <salt/random.h>
00024 #include <zeitgeist/logserver/logserver.h>
00025 #include <oxygen/agentaspect/agentaspect.h>
00026 #include <oxygen/physicsserver/body.h>
00027 #include <oxygen/sceneserver/scene.h>
00028 #include <oxygen/gamecontrolserver/gamecontrolserver.h>
00029 #include <soccer/soccerbase/soccerbase.h>
00030 #include <soccer/gamestateaspect/gamestateaspect.h>
00031 #include <soccer/ballstateaspect/ballstateaspect.h>
00032 #include <soccer/agentstate/agentstate.h>
00033 
00034 using namespace oxygen;
00035 using namespace boost;
00036 using namespace std;
00037 using salt::Vector2f;
00038 using salt::Vector3f;
00039 
00040 SoccerRuleAspect::SoccerRuleAspect() :
00041     mBallRadius(0.111),
00042     mGoalPauseTime(3),
00043     mKickInPauseTime(1),
00044     mHalfTime(2.25 * 60),
00045     mFreeKickDist(9.15),
00046     mFreeKickMoveDist(15.15),
00047     mAutomaticKickOff(false),
00048     mWaitBeforeKickOff(1.0),
00049     mSingleHalfTime(false),
00050     mSayMsgSize(512),
00051     mAudioCutDist(50.0),
00052     mUseOffside(true),
00053     mFirstCollidingAgent(true),
00054     mNotOffside(false)
00055 {
00056 }
00057 
00058 SoccerRuleAspect::~SoccerRuleAspect()
00059 {
00060 }
00061 
00062 void
00063 SoccerRuleAspect::MoveBall(const Vector3f& pos)
00064 {
00065     mBallBody->SetPosition(pos);
00066     mBallBody->SetVelocity(Vector3f(0,0,0));
00067     mBallBody->SetAngularVelocity(Vector3f(0,0,0));
00068 }
00069 
00070 void
00071 SoccerRuleAspect::MoveAgent(shared_ptr<Body> agent_body, const Vector3f& pos)
00072 {
00073     agent_body->SetPosition(pos);
00074     agent_body->SetVelocity(Vector3f(0,0,0));
00075     agent_body->SetAngularVelocity(Vector3f(0,0,0));
00076 }
00077 
00078 void
00079 SoccerRuleAspect::ClearPlayers(const salt::Vector3f& pos, float radius,
00080                                float min_dist, TTeamIndex idx)
00081 {
00082     if (idx == TI_NONE || mBallState.get() == 0) return;
00083     std::list<boost::shared_ptr<AgentState> > agent_states;
00084     if (! SoccerBase::GetAgentStates(*mBallState, agent_states, idx))
00085         return;
00086 
00087     salt::BoundingSphere sphere(pos, radius);
00088     boost::shared_ptr<oxygen::Transform> transform_parent;
00089     boost::shared_ptr<oxygen::Body> agent_body;
00090     std::list<boost::shared_ptr<AgentState> >::const_iterator i;
00091     for (i = agent_states.begin(); i != agent_states.end(); ++i)
00092     {
00093         SoccerBase::GetTransformParent(*(*i), transform_parent);
00094         // call GetAgentBody with matching AgentAspect
00095         SoccerBase::GetAgentBody(transform_parent, agent_body);
00096         // if agent is too close, move it away
00097         Vector3f new_pos = agent_body->GetPosition();
00098         if (sphere.Contains(new_pos))
00099         {
00100             float dist = salt::UniformRNG<>(min_dist, min_dist + 2.0)();
00101 
00102             if (idx == TI_LEFT)
00103             {
00104                 if (pos[0] - dist < -mFieldLength/2.0)
00105                 {
00106                     new_pos[1] = pos[1] < 0 ? pos[1] + dist : pos[1] - dist;
00107                 } else {
00108                     new_pos[0] = pos[0] - dist;
00109                 }
00110             } else {
00111                 if (pos[0] + dist > mFieldLength/2.0)
00112                 {
00113                     new_pos[1] = pos[1] < 0 ? pos[1] + dist : pos[1] - dist;
00114                 } else {
00115                     new_pos[0] = pos[0] + dist;
00116                 }
00117             }
00118             new_pos[2] = 1.0;
00119             MoveAgent(agent_body, new_pos);
00120         }
00121     }
00122 }
00123 
00124 void
00125 SoccerRuleAspect::ClearPlayers(const salt::AABB2& box,
00126                                float min_dist, TTeamIndex idx)
00127 {
00128     if (idx == TI_NONE || mBallState.get() == 0) return;
00129     std::list<boost::shared_ptr<AgentState> > agent_states;
00130     if (! SoccerBase::GetAgentStates(*mBallState, agent_states, idx))
00131         return;
00132 
00133     boost::shared_ptr<oxygen::Transform> transform_parent;
00134     boost::shared_ptr<oxygen::Body> agent_body;
00135 
00136     std::list<boost::shared_ptr<AgentState> >::const_iterator i;
00137     for (i = agent_states.begin(); i != agent_states.end(); ++i)
00138     {
00139         SoccerBase::GetTransformParent(*(*i), transform_parent);
00140         // call GetAgentBody with matching AgentAspect
00141         SoccerBase::GetAgentBody(transform_parent, agent_body);
00142         // if agent is too close, move it away
00143         Vector3f new_pos = agent_body->GetPosition();
00144         if (box.Contains(Vector2f(new_pos[0], new_pos[1])))
00145         {
00146             if (idx == TI_LEFT)
00147             {
00148                 new_pos[0] = box.minVec[0] -
00149                     salt::UniformRNG<>(min_dist, min_dist + 2.0)();
00150             } else {
00151                 new_pos[0] = box.maxVec[0] +
00152                     salt::UniformRNG<>(min_dist, min_dist + 2.0)();
00153             }
00154             new_pos[2] = 1.0;
00155             MoveAgent(agent_body, new_pos);
00156         }
00157     }
00158 }
00159 
00160 void
00161 SoccerRuleAspect::DropBall()
00162 {
00163     DropBall(mBallBody->GetPosition());
00164 }
00165 
00166 void
00167 SoccerRuleAspect::DropBall(Vector3f pos)
00168 {
00169     salt::Vector2f ball_pos(pos.x(), pos.y());
00170 
00171     // we do not drop the ball within the penalty area
00172     if (mLeftPenaltyArea.Contains(ball_pos))
00173     {
00174         pos[0] = mLeftPenaltyArea.maxVec[0];
00175         pos[1] = pos.y() < 0 ?
00176             mLeftPenaltyArea.minVec[1] : mLeftPenaltyArea.maxVec[1];
00177     }
00178     else if (mRightPenaltyArea.Contains(ball_pos))
00179     {
00180         pos[0] = mRightPenaltyArea.minVec[0];
00181         pos[1] = pos.y() < 0 ?
00182             mRightPenaltyArea.minVec[1] : mRightPenaltyArea.maxVec[1];
00183     }
00184 
00185     MoveBall(pos);
00186     ClearPlayers(pos, mFreeKickDist, mFreeKickMoveDist, TI_LEFT);
00187     ClearPlayers(pos, mFreeKickDist, mFreeKickMoveDist, TI_RIGHT);
00188     mGameState->SetPlayMode(PM_PlayOn);
00189 }
00190 
00191 void
00192 SoccerRuleAspect::UpdateBeforeKickOff()
00193 {
00194     // before the game starts the ball should stay in the middle of
00195     // the playing field
00196     Vector3f pos(0,0,mBallRadius);
00197     MoveBall(pos);
00198     ClearPlayers(mRightHalf, 1.0, TI_LEFT);
00199     ClearPlayers(mLeftHalf, 1.0, TI_RIGHT);
00200 
00201     if (mAutomaticKickOff && mGameState->GetModeTime() > mWaitBeforeKickOff)
00202     {
00203         mGameState->KickOff();
00204     }
00205 }
00206 
00207 void
00208 SoccerRuleAspect::UpdateKickOff(TTeamIndex idx)
00209 {
00210     ClearPlayers(mRightHalf, 1.0, TI_LEFT);
00211     ClearPlayers(mLeftHalf, 1.0, TI_RIGHT);
00212     ClearPlayers(Vector3f(0,0,0), mFreeKickDist, mFreeKickMoveDist,
00213                  SoccerBase::OpponentTeam(idx));
00214 
00215     // if no player touched the ball for mDropBallTime, we move away
00216     // all players and set the play mode to play on
00217     if (mDropBallTime > 0 &&
00218         mGameState->GetModeTime() > mDropBallTime)
00219     {
00220         DropBall(mFreeKickPos);
00221         return;
00222     }
00223 
00224     // after the first agent touches the ball move to PM_PLAYON
00225     shared_ptr<AgentAspect> agent;
00226     TTime time;
00227     if (! mBallState->GetLastCollidingAgent(agent,time))
00228     {
00229         return;
00230     }
00231     if (time > mGameState->GetLastModeChange())
00232     {
00233         mGameState->SetPlayMode(PM_PlayOn);
00234     }
00235 }
00236 
00237 void
00238 SoccerRuleAspect::UpdateKickIn(TTeamIndex idx)
00239 {
00240     // do nothing for the duration of mKickInPauseTime
00241     if (mGameState->GetModeTime() < mKickInPauseTime)
00242     {
00243         return;
00244     }
00245     // move away opponent team
00246     ClearPlayers(mFreeKickPos, mFreeKickDist, mFreeKickMoveDist,
00247                  SoccerBase::OpponentTeam(idx));
00248 
00249     // if no player touched the ball for mDropBallTime, we move away
00250     // all players and set the play mode to play on
00251     if (mDropBallTime > 0 &&
00252         mGameState->GetModeTime() > mDropBallTime)
00253     {
00254         DropBall(mFreeKickPos);
00255         return;
00256     }
00257 
00258     // after the first agent touches the ball move to PM_PLAY_ON. the
00259     // time when the agent last touches the ball must be after the
00260     // change to the KickIn mode
00261     shared_ptr<AgentAspect> agent;
00262     TTime time;
00263     if (! mBallState->GetLastCollidingAgent(agent,time))
00264     {
00265         GetLog()->Error() << "ERROR: (SoccerRuleAspect) " << "no agent collided yet\n";
00266         return;
00267     }
00268 
00269     TTime lastChange = mGameState->GetLastModeChange();
00270     if (time > lastChange)
00271     {
00272         mGameState->SetPlayMode(PM_PlayOn);
00273         GetLog()->Error() << "ERROR: (SoccerRuleAspect) " << "Set Playmode to playon\n";
00274     } else
00275     {
00276         // move the ball back on the ground where it left the playing
00277         // field
00278         MoveBall(mFreeKickPos);
00279     }
00280 }
00281 
00282 void
00283 SoccerRuleAspect::UpdateGoalKick(TTeamIndex idx)
00284 {
00285     // do nothing for the duration of mKickInPauseTime
00286     if (mGameState->GetModeTime() < mKickInPauseTime)
00287     {
00288         return;
00289     }
00290     // move away opponent team
00291     ClearPlayers(idx == TI_LEFT ? mLeftPenaltyArea : mRightPenaltyArea,
00292                  1.0, SoccerBase::OpponentTeam(idx));
00293 
00294     // if no player touched the ball for mDropBallTime, we move away
00295     // all players and set the play mode to play on
00296     if (mDropBallTime > 0 &&
00297         mGameState->GetModeTime() > mDropBallTime)
00298     {
00299         DropBall(mFreeKickPos);
00300         return;
00301     }
00302 
00303     // after the first agent touches the ball, we do nothing until
00304     // the ball leaves the penalty area.
00305     shared_ptr<AgentAspect> agent;
00306     TTime time;
00307     if (! mBallState->GetLastCollidingAgent(agent,time))
00308     {
00309         return;
00310     }
00311 
00312     TTime lastChange = mGameState->GetLastModeChange();
00313     // if the team with the goal kick touched the ball and the ball is
00314     // outside the penalty area, we switch to play on.
00315     if (time > lastChange)
00316     {
00317         Vector2f pos(mBallBody->GetPosition().x(),
00318                      mBallBody->GetPosition().y());
00319         if ((idx == TI_RIGHT && !mRightPenaltyArea.Contains(pos)) ||
00320             (idx == TI_LEFT && !mLeftPenaltyArea.Contains(pos)) ||
00321             (idx == TI_NONE))
00322         {
00323             // we have to handle the case where the team with the goal kick
00324             // scores a self goal, because the penalty areas contain the goal.
00325 //            if (!mBallState->GetBallOnField())
00326                 mGameState->SetPlayMode(PM_PlayOn);
00327         }
00328         return;
00329     }
00330     // the ball was not touched yet
00331     else
00332     {
00333         // move the ball back on the free kick position
00334         MoveBall(mFreeKickPos);
00335     }
00336 }
00337 
00338 void
00339 SoccerRuleAspect::UpdateCornerKick(TTeamIndex idx)
00340 {
00341     // do nothing for the duration of mKickInPauseTime
00342     if (mGameState->GetModeTime() < mKickInPauseTime)
00343     {
00344         return;
00345     }
00346     // move away opponent team
00347     ClearPlayers(mFreeKickPos, mFreeKickDist, mFreeKickMoveDist,
00348                  SoccerBase::OpponentTeam(idx));
00349 
00350     // if no player touched the ball for mDropBallTime, we move away
00351     // all players and set the play mode to play on
00352     if (mDropBallTime > 0 &&
00353         mGameState->GetModeTime() > mDropBallTime)
00354     {
00355         DropBall(mFreeKickPos);
00356         return;
00357     }
00358 
00359     // after the first agent touches the ball move to PM_PLAY_ON. the
00360     // time when the agent last touches the ball must be after the
00361     // change to the KickIn mode
00362     shared_ptr<AgentAspect> agent;
00363     TTime time;
00364     if (! mBallState->GetLastCollidingAgent(agent,time))
00365     {
00366         return;
00367     }
00368 
00369     TTime lastChange = mGameState->GetLastModeChange();
00370     if (time > lastChange)
00371     {
00372         mGameState->SetPlayMode(PM_PlayOn);
00373     } else
00374     {
00375         // move the ball back on the ground where it left the playing
00376         // field
00377         MoveBall(mFreeKickPos);
00378     }
00379 }
00380 
00381 bool
00382 SoccerRuleAspect::CheckBallLeftField()
00383 {
00384     if (mBallState->GetBallOnField())
00385     {
00386         return false;
00387     }
00388 
00389     // get the team of the last agent touching the ball and set the
00390     // correct kick in playmode
00391     shared_ptr<AgentAspect> agent;
00392     shared_ptr<AgentState> agentState;
00393     TTime time;
00394 
00395     if (mBallState->GetLastCollidingAgent(agent,time) &&
00396         SoccerBase::GetAgentState(agent,agentState))
00397     {
00398         /* Possibilities are:
00399            - Ball left field on the long sides: kick in for the other team
00400            - Ball left field on the short sides:
00401              - corner kick if the a team kicked the ball over its own side
00402              - goal kick if the a team kicked the ball over opponent side
00403            - [ The ball left the field through a hole in the floor or ceiling
00404                or some aliens have taken it away =:-]
00405                In this case put the ball back to the last valid position and
00406                we hope nobody sees.
00407                (this should not happen. really.  But it CAN happen depending
00408                on the ODE parameters you choose or if somebody is going to
00409                simulate the first contact (stardate 50893.5)).
00410         */
00411         Vector3f ball_pos = mBallBody->GetPosition();
00412         bool last_touch_left = (agentState->GetTeamIndex() == TI_LEFT);
00413         bool ball_left = (ball_pos[0] < 0);
00414         bool ball_up = (ball_pos[1] < 0);
00415 
00416         // handle corner / goal kick
00417         if (salt::gAbs(ball_pos.x()) >= mFieldLength / 2)
00418         {
00419             // check goal kick right team
00420             if (last_touch_left && !ball_left)
00421             {
00422                 mFreeKickPos[0] = mFieldLength / 2 - 5.0;
00423                 mFreeKickPos[1] = 0.0;
00424                 mFreeKickPos[2] = mBallRadius;
00425                 mGameState->SetPlayMode(PM_GOAL_KICK_RIGHT);
00426             }
00427             // check goal kick left team
00428             else if (!last_touch_left && ball_left)
00429             {
00430                 mFreeKickPos[0] = -mFieldLength / 2 + 5.0;
00431                 mFreeKickPos[1] = 0.0;
00432                 mFreeKickPos[2] = mBallRadius;
00433                 mGameState->SetPlayMode(PM_GOAL_KICK_LEFT);
00434             }
00435             // check corner kick right team
00436             else if (last_touch_left && ball_left)
00437             {
00438                 mFreeKickPos[0] = -mFieldLength / 2 + 0.05;
00439                 mFreeKickPos[1] = ball_pos[1] > 0 ?
00440                     mFieldWidth / 2 - 0.05 : -mFieldWidth / 2 + 0.05;
00441                 mFreeKickPos[2] = mBallRadius;
00442                 mGameState->SetPlayMode(PM_CORNER_KICK_RIGHT);
00443             }
00444             // check corner kick left team
00445             else
00446             {
00447                 mFreeKickPos[0] = mFieldLength / 2 - 0.05;
00448                 mFreeKickPos[1] = ball_pos[1] > 0 ?
00449                     mFieldWidth / 2 - 0.05 : -mFieldWidth / 2 + 0.05;
00450                 mFreeKickPos[2] = mBallRadius;
00451                 mGameState->SetPlayMode(PM_CORNER_KICK_LEFT);
00452             }
00453         }
00454         // handle kick in
00455         else if (salt::gAbs(ball_pos.y()) >= mFieldWidth / 2)
00456         {
00457             mFreeKickPos = mBallState->GetLastValidBallPosition();
00458             mFreeKickPos[1] = mFreeKickPos[1] > 0 ?
00459                 mFieldWidth / 2 : -mFieldWidth / 2;
00460             mFreeKickPos[2] = mBallRadius;
00461             mGameState->SetPlayMode((agentState->GetTeamIndex() == TI_LEFT) ?
00462                                     PM_KickIn_Right : PM_KickIn_Left);
00463         }
00464         // we've got a situation here
00465         else {
00466             // this will stop the ball, but better than losing it away.
00467             MoveBall(mBallState->GetLastValidBallPosition());
00468             // no need to change the game state, we just don't know what
00469             // has been going on.
00470             return false;
00471         }
00472     }
00473 
00474     return true;
00475 }
00476 
00477 bool
00478 SoccerRuleAspect::CheckGoal()
00479 {
00480     // check if the ball is in one of the goals
00481     TTeamIndex idx = mBallState->GetGoalState();
00482     if (idx == TI_NONE)
00483     {
00484         return false;
00485     }
00486 
00487     // score the lucky team
00488     mGameState->ScoreTeam((idx == TI_LEFT) ? TI_RIGHT : TI_LEFT);
00489     mGameState->SetPlayMode((idx == TI_LEFT) ? PM_Goal_Right : PM_Goal_Left);
00490 
00491     return true;
00492 }
00493 
00494 void
00495 SoccerRuleAspect::UpdatePlayOn()
00496 {
00497     // check if the ball is in one of the goals
00498     if (CheckGoal())
00499     {
00500         return;
00501     }
00502 
00503     // check if the ball is otherwise not on the playing field
00504     if (CheckBallLeftField())
00505     {
00506         return;
00507     }
00508 
00509     // check if the players are in offside
00510     if (mUseOffside && CheckOffside())
00511     {
00512         return;
00513     }
00514 
00515     // other checks go here...
00516 }
00517 
00518 void
00519 SoccerRuleAspect::UpdateGoal()
00520 {
00521     // check if the pause time after the goal has elapsed
00522     if (mGameState->GetModeTime() < mGoalPauseTime)
00523     {
00524         return;
00525     }
00526 
00527     // put the ball back in the middle of the playing field
00528     Vector3f pos(0,0,mBallRadius);
00529     MoveBall(pos);
00530 
00531     // kick off for the opposite team
00532     // Original
00533 //     mGameState->SetPlayMode(
00534 //         mGameState->GetPlayMode() == PM_Goal_Left ?
00535 //         PM_KickOff_Right : PM_KickOff_Left
00536 //         );
00537     
00538     // kick off for the opposite team
00539     mGameState->KickOff(
00540         mGameState->GetPlayMode() == PM_Goal_Left ?
00541         TI_RIGHT : TI_LEFT
00542         );
00543 }
00544 
00545 void
00546 SoccerRuleAspect::UpdateGameOver()
00547 {
00548     // wait for 10 seconds to finish
00549     if (mGameState->GetModeTime() < 9)
00550     {
00551         return;
00552     }
00553     mGameState->Finish();
00554 
00555     if (mGameState->GetModeTime() >= 10)
00556     {
00557         boost::shared_ptr<GameControlServer> gameControlServer =
00558             shared_dynamic_cast<GameControlServer>(GetCore()->Get("/sys/server/gamecontrol"));
00559         gameControlServer->Quit();
00560     }
00561 }
00562 
00563 void
00564 SoccerRuleAspect::CheckTime()
00565 {
00566     TTime now = mGameState->GetTime();
00567     TGameHalf half = mGameState->GetGameHalf();
00568 
00569     if ((half == GH_FIRST) && (now >= mHalfTime))
00570     {
00571         if (mSingleHalfTime)
00572         {
00573             // we want to play only one half of the match
00574             mGameState->SetPlayMode(PM_GameOver);
00575         } else {
00576             // the first game half is over
00577             mGameState->SetPlayMode(PM_BeforeKickOff);
00578             mGameState->SetGameHalf(GH_SECOND);
00579         }
00580     }
00581     else if ((half == GH_SECOND) && (now >= 2 * mHalfTime))
00582     {
00583         // the game is over
00584         mGameState->SetPlayMode(PM_GameOver);
00585     }
00586 }
00587 
00588 void
00589 SoccerRuleAspect::Update(float deltaTime)
00590 {
00591     if (
00592         (mGameState.get() == 0) ||
00593         (mBallState.get() == 0) ||
00594         (mBallBody.get() == 0)
00595         )
00596     {
00597         return;
00598     }
00599 
00600     CheckTime();
00601 
00602     TPlayMode playMode = mGameState->GetPlayMode();
00603 
00604     static bool updated = false;
00605 
00606     switch (playMode)
00607     {
00608     case PM_BeforeKickOff:
00609         // At the beginning of the match, we update the member variables
00610         // with the values from the ruby script (once). At this point in time,
00611         // the ruby script has definitely been processed.
00612         if (! updated)
00613         {
00614             UpdateCachedInternal();
00615             updated = true;
00616         }
00617         // Below is the check we do during before kick off mode.
00618         UpdateBeforeKickOff();
00619         break;
00620 
00621     case PM_PlayOn:
00622         UpdatePlayOn();
00623         break;
00624 
00625     case PM_KickOff_Left:
00626         UpdateKickOff(TI_LEFT);
00627         break;
00628     case PM_KickOff_Right:
00629         UpdateKickOff(TI_RIGHT);
00630         break;
00631 
00632     case PM_KickIn_Left:
00633         UpdateKickIn(TI_LEFT);
00634         break;
00635     case PM_KickIn_Right:
00636         UpdateKickIn(TI_RIGHT);
00637         break;
00638 
00639     case PM_GOAL_KICK_LEFT:
00640         UpdateGoalKick(TI_LEFT);
00641         break;
00642     case PM_GOAL_KICK_RIGHT:
00643         UpdateGoalKick(TI_RIGHT);
00644         break;
00645 
00646     case PM_CORNER_KICK_LEFT:
00647         UpdateCornerKick(TI_LEFT);
00648         break;
00649 
00650     case PM_CORNER_KICK_RIGHT:
00651         UpdateCornerKick(TI_RIGHT);
00652         break;
00653 
00654     case PM_Goal_Left:
00655     case PM_Goal_Right:
00656         UpdateGoal();
00657         break;
00658 
00659     case PM_OFFSIDE_LEFT:
00660         UpdateOffside(TI_LEFT);
00661         break;
00662     case PM_OFFSIDE_RIGHT:
00663         UpdateOffside(TI_RIGHT);
00664         break;
00665 
00666     case PM_GameOver:
00667         UpdateGameOver();
00668         break;
00669 
00670     default:
00671         GetLog()->Error()
00672             << "ERROR: (SoccerRuleAspect) unknown play mode "
00673             << playMode << "\n";
00674         break;
00675     }
00676 }
00677 
00678 void
00679 SoccerRuleAspect::OnLink()
00680 {
00681     SoccerControlAspect::OnLink();
00682 
00683     mGameState = shared_dynamic_cast<GameStateAspect>
00684         (GetControlAspect("GameStateAspect"));
00685 
00686     mBallState = shared_dynamic_cast<BallStateAspect>
00687         (GetControlAspect("BallStateAspect"));
00688 
00689     SoccerBase::GetBallBody(*this,mBallBody);
00690 }
00691 
00692 void
00693 SoccerRuleAspect::OnUnlink()
00694 {
00695     SoccerControlAspect::OnUnlink();
00696 
00697     mGameState.reset();
00698     mBallState.reset();
00699     mBallBody.reset();
00700 }
00701 
00702 
00703 void
00704 SoccerRuleAspect::UpdateCachedInternal()
00705 {
00706     SoccerBase::GetSoccerVar(*this,"BallRadius",mBallRadius);
00707     SoccerBase::GetSoccerVar(*this,"RuleGoalPauseTime",mGoalPauseTime);
00708     SoccerBase::GetSoccerVar(*this,"RuleKickInPauseTime",mKickInPauseTime);
00709     SoccerBase::GetSoccerVar(*this,"RuleHalfTime",mHalfTime);
00710     SoccerBase::GetSoccerVar(*this,"RuleDropBallTime",mDropBallTime);
00711     SoccerBase::GetSoccerVar(*this,"FieldLength",mFieldLength);
00712     SoccerBase::GetSoccerVar(*this,"FieldWidth",mFieldWidth);
00713     SoccerBase::GetSoccerVar(*this,"GoalWidth",mGoalWidth);
00714     SoccerBase::GetSoccerVar(*this,"FreeKickDistance",mFreeKickDist);
00715     SoccerBase::GetSoccerVar(*this,"AutomaticKickOff",mAutomaticKickOff);
00716     SoccerBase::GetSoccerVar(*this,"WaitBeforeKickOff",mWaitBeforeKickOff);
00717     SoccerBase::GetSoccerVar(*this,"SingleHalfTime",mSingleHalfTime);
00718     SoccerBase::GetSoccerVar(*this,"UseOffside",mUseOffside);
00719 
00720     // set up bounding boxes for halfs and goal areas
00721 
00722     // the right and the left half are intentionally oversized towards the sides and
00723     // the end of the field so that no opponents sneak up from behind.
00724     mRightHalf = salt::AABB2(Vector2f(0, -mFieldWidth/2.0 - 10.0),
00725                              Vector2f(mFieldLength/2.0 + 10, mFieldWidth/2.0 + 10.0));
00726     mLeftHalf = salt::AABB2(Vector2f(0, -mFieldWidth/2.0 - 10.0),
00727                             Vector2f(-mFieldLength/2.0 - 10, mFieldWidth/2.0 + 10.0));
00728 
00729     // the penalty areas (exact sizes)
00730     mRightPenaltyArea = salt::AABB2(Vector2f(mFieldLength/2.0 - 16.5, -16.5 - mGoalWidth/2.0),
00731                                     Vector2f(mFieldLength/2.0 , 16.5 + mGoalWidth/2.0));
00732     mLeftPenaltyArea = salt::AABB2(Vector2f(-mFieldLength/2.0 + 16.5, -16.5 - mGoalWidth/2.0),
00733                                    Vector2f(-mFieldLength/2.0, 16.5 + mGoalWidth/2.0));
00734 }
00735 
00736 void 
00737 SoccerRuleAspect::Broadcast(const string& message, const Vector3f& pos,
00738                             int number, TTeamIndex idx)
00739 {
00740     TAgentStateList agent_states;
00741     if (! SoccerBase::GetAgentStates(*mBallState, agent_states, idx))
00742     {
00743         return;
00744     }
00745 
00746     TAgentStateList opponent_agent_states;
00747     if (! SoccerBase::GetAgentStates(*mBallState, opponent_agent_states,
00748                                      SoccerBase::OpponentTeam(idx)))
00749     {
00750         return;
00751     }
00752 
00753     if (message.size() > mSayMsgSize)
00754     {
00755         return;
00756     }
00757 
00758     salt::BoundingSphere sphere(pos, mAudioCutDist);
00759     
00760     shared_ptr<Transform> transform_parent;
00761     shared_ptr<Body> agent_body;
00762     
00763     for (
00764         TAgentStateList::const_iterator it = agent_states.begin();
00765         it != agent_states.end();
00766         it++
00767         )
00768     {    
00769         if ( (*it)->GetUniformNumber() == number)
00770         {
00771             (*it)->AddSelfMessage(message);
00772             continue;
00773         }
00774         SoccerBase::GetTransformParent(*(*it), transform_parent);
00775 
00776         // call GetAgentBody with matching AgentAspect
00777         SoccerBase::GetAgentBody(transform_parent, agent_body);
00778 
00779         // if the player is in the range, send the message
00780         Vector3f new_pos = agent_body->GetPosition();
00781         if (sphere.Contains(new_pos))
00782         {
00783             Vector3f relPos = pos - new_pos;
00784             relPos = SoccerBase::FlipView(relPos, idx);
00785             float direction = salt::gRadToDeg(salt::gArcTan2(relPos[1], relPos[0]));
00786             (*it)->AddMessage(message, direction, true);
00787         }
00788     }
00789 
00790     for (
00791         SoccerBase::TAgentStateList::const_iterator it = opponent_agent_states.begin();
00792         it != opponent_agent_states.end();
00793         it++
00794         )
00795     {    
00796         SoccerBase::GetTransformParent(*(*it), transform_parent);
00797 
00798         // call GetAgentBody with matching AgentAspect
00799         SoccerBase::GetAgentBody(transform_parent, agent_body);
00800 
00801         // if the player is in the range, send the message
00802         Vector3f new_pos = agent_body->GetPosition();
00803         if (sphere.Contains(new_pos))
00804         {
00805             Vector3f relPos = pos - new_pos;
00806             relPos = SoccerBase::FlipView(relPos, SoccerBase::OpponentTeam(idx));
00807             float direction = salt::gRadToDeg(salt::gArcTan2(relPos[1], relPos[0]));
00808             (*it)->AddMessage(message, direction, false);
00809         }
00810     }
00811 }
00812 
00813 bool
00814 SoccerRuleAspect::CheckOffside()
00815 {
00816     shared_ptr<AgentAspect> agent;
00817     shared_ptr<AgentState> agentState;
00818     TTime time;
00819 
00820     if (! mBallState->GetLastCollidingAgent(agent,time))
00821     {
00822         return false;
00823     }
00824 
00825     TTime lastModeChange = mGameState->GetLastModeChange();
00826 
00827     if (time == lastModeChange)
00828     {
00829         mFirstCollidingAgent = true;
00830     }
00831 
00832     // if the previous last collinding agent is the last colliding agent,
00833     // there is no offside
00834     if (mGameState->GetTime() == time)
00835     {
00836         if (mPreLastCollidingAgent == agent)
00837         {
00838             mNotOffside = true;
00839         }
00840         else
00841         {
00842             mPreLastCollidingAgent = agent;
00843             mNotOffside = false;
00844         }
00845     }
00846 
00847     // find opponent's goalkeeper and last defender positions
00848     if (! SoccerBase::GetAgentState(agent,agentState))
00849     {
00850         return false;
00851     }
00852 
00853     TTeamIndex idx = agentState->GetTeamIndex();
00854 
00855     list<shared_ptr<AgentState> > opp_agent_states;
00856     if (! SoccerBase::GetAgentStates(*mBallState, opp_agent_states, 
00857           SoccerBase::OpponentTeam(idx)))
00858     {
00859         return false;
00860     }
00861 
00862     float opp_goalkeeper_pos;
00863     float opp_defender_pos;
00864 
00865     opp_goalkeeper_pos = 0.0;
00866     opp_defender_pos   = 0.0;
00867            
00868     shared_ptr<Transform> transform_parent;
00869     shared_ptr<Body> agent_body;
00870     
00871     list<shared_ptr<AgentState> >::const_iterator it;
00872     for (it = opp_agent_states.begin(); it != opp_agent_states.end(); it++)
00873     {
00874         SoccerBase::GetTransformParent(*(*it), transform_parent);
00875         SoccerBase::GetAgentBody(transform_parent, agent_body);
00876         
00877         Vector3f opp_agent_pos = agent_body->GetPosition();
00878         
00879         if (SoccerBase::OpponentTeam(idx) == TI_LEFT)
00880         {
00881             if (opp_agent_pos[0] <= opp_goalkeeper_pos)
00882             {
00883                 opp_defender_pos   = opp_goalkeeper_pos; 
00884                 opp_goalkeeper_pos = opp_agent_pos[0];
00885             }
00886             else if (opp_agent_pos[0] <= opp_defender_pos)
00887             {
00888                 opp_defender_pos = opp_agent_pos[0];
00889             }
00890         }
00891         else
00892         {
00893             if (opp_agent_pos[0] >= opp_goalkeeper_pos)
00894             {
00895                 opp_defender_pos   = opp_goalkeeper_pos;
00896                 opp_goalkeeper_pos = opp_agent_pos[0];
00897             }
00898             else if (opp_agent_pos[0] >= opp_defender_pos)
00899             {
00900                 opp_defender_pos = opp_agent_pos[0];
00901             }
00902         }
00903     }
00904 
00905     Vector3f ball_pos = mBallBody->GetPosition();
00906 
00907     SoccerBase::GetTransformParent(*agentState, transform_parent);
00908     SoccerBase::GetAgentBody(transform_parent, agent_body);
00909     Vector3f agent_pos = agent_body->GetPosition();
00910 
00911     if ( (mGameState->GetTime() == time) && mFirstCollidingAgent )
00912     {
00913         if (((idx == TI_LEFT) && (agent_pos[0] > opp_defender_pos)
00914         && (agent_pos[0] > ball_pos[0])) ||
00915             ((idx == TI_RIGHT) && (agent_pos[0] < opp_defender_pos)
00916         && (agent_pos[0] < ball_pos[0])))
00917         {
00918             mFirstCollidingAgent = true;
00919         }
00920         else
00921         {
00922             mFirstCollidingAgent = false;
00923         }
00924     }
00925 
00926     // if the agent,that touches the ball was in 
00927     // offside position before the last shot, change the mode to offside
00928     bool offside = false;
00929 
00930     if ((idx == TI_LEFT) && !mFirstCollidingAgent && !mNotOffside)
00931     {
00932         vector<int>::const_iterator it_offside;
00933         for (
00934             it_offside = mInOffsideLeftPlayers.begin();
00935             it_offside != mInOffsideLeftPlayers.end();
00936             it_offside++)
00937         {
00938             if (agentState->GetUniformNumber() == *it_offside)
00939             {
00940                 mGameState->SetPlayMode(PM_OFFSIDE_RIGHT);
00941                 offside = true;
00942             }
00943         }
00944         if (!offside && (agent_pos[0] > opp_defender_pos))
00945             mFirstCollidingAgent = true;
00946     }
00947     else if (!mFirstCollidingAgent && !mNotOffside)
00948     {
00949         vector<int>::const_iterator it_offside;
00950         for (
00951             it_offside = mInOffsideRightPlayers.begin();
00952             it_offside != mInOffsideRightPlayers.end();
00953             it_offside++
00954             )
00955         {
00956             if (agentState->GetUniformNumber() == *it_offside)
00957             {
00958                 mGameState->SetPlayMode(PM_OFFSIDE_LEFT);
00959                 offside = true;
00960             }
00961         }
00962         if (!offside && (agent_pos[0] < opp_defender_pos))
00963             mFirstCollidingAgent = true;
00964     }
00965 
00966     // update the list of players that are in offside poistion 
00967     if ( mGameState->GetTime() == time)
00968     {
00969         mInOffsideLeftPlayers.clear();
00970         mInOffsideRightPlayers.clear();
00971 
00972         mFreeKickPos = mBallState->GetLastValidBallPosition();
00973         mFreeKickPos[2] = mBallRadius;
00974 
00975         list<shared_ptr<AgentState> > agent_states;
00976         if (! SoccerBase::GetAgentStates(*mBallState, agent_states, idx))
00977         {
00978             return false;
00979         }
00980 
00981         for (it = agent_states.begin(); it != agent_states.end(); it++)
00982         {
00983             SoccerBase::GetTransformParent(*(*it), transform_parent);
00984             SoccerBase::GetAgentBody(transform_parent, agent_body);
00985 
00986             Vector3f agent_pos = agent_body->GetPosition();
00987 
00988             if (idx == TI_LEFT)
00989             {
00990                 if ((agent_pos[0] > opp_defender_pos)
00991             && (agent_pos[0] > ball_pos[0]))
00992                 {
00993                     mInOffsideLeftPlayers.push_back((*it)->GetUniformNumber());
00994                 }
00995             }
00996             else
00997             {
00998                 if ((agent_pos[0] < opp_defender_pos)
00999             && (agent_pos[0] < ball_pos[0]))
01000                 {
01001                     mInOffsideRightPlayers.push_back((*it)->GetUniformNumber());
01002                 }
01003             }
01004         }
01005 
01006     }
01007 
01008     return true;
01009 }
01010 
01011 void
01012 SoccerRuleAspect::UpdateOffside(TTeamIndex idx)
01013 {
01014     // do nothing for the duration of mKickInPauseTime
01015     if (mGameState->GetModeTime() < mKickInPauseTime)
01016     {
01017         return;
01018     }
01019 
01020     // move away opponent team
01021     Vector3f ball_pos = mBallBody->GetPosition();
01022     ClearPlayers(mFreeKickPos, mFreeKickDist, mFreeKickMoveDist,
01023                  SoccerBase::OpponentTeam(idx));
01024 
01025     // if no player touched the ball for mDropBallTime, we move away
01026     // all players and set the play mode to play on
01027     if (mDropBallTime > 0 &&
01028         mGameState->GetModeTime() > mDropBallTime)
01029     {
01030         DropBall(mFreeKickPos);
01031         return;
01032     }
01033 
01034     // after the first agent touches the ball move to PM_PLAY_ON. the
01035     // time when the agent last touches the ball must be after the
01036     // change to the OffsideKick mode
01037     shared_ptr<AgentAspect> agent;
01038     shared_ptr<AgentState> agentState;
01039     TTime time;
01040     if (! mBallState->GetLastCollidingAgent(agent,time))
01041     {
01042         GetLog()->Error() 
01043             << "ERROR: (SoccerRuleAspect) no agent collided yet\n";
01044         return;
01045     }
01046 
01047     if (! SoccerBase::GetAgentState(agent,agentState))
01048     {
01049         return;
01050     }
01051 
01052     TTeamIndex collidingAgentIdx = agentState->GetTeamIndex();
01053 
01054     TTime lastChange = mGameState->GetLastModeChange();
01055     if (time > lastChange && collidingAgentIdx==idx)
01056     {
01057         mGameState->SetPlayMode(PM_PlayOn);
01058     } 
01059     else
01060     {
01061         // move the ball back on the free kick position
01062         MoveBall(mFreeKickPos);
01063     }
01064 }
01065 
01066 void
01067 SoccerRuleAspect::ClearPlayersWithException(const salt::Vector3f& pos, 
01068                                float radius, float min_dist, TTeamIndex idx,
01069                                shared_ptr<AgentState> agentState)
01070 {
01071     if (idx == TI_NONE || mBallState.get() == 0) return;
01072     std::list<boost::shared_ptr<AgentState> > agent_states;
01073     if (! SoccerBase::GetAgentStates(*mBallState, agent_states, idx))
01074         return;
01075 
01076     salt::BoundingSphere sphere(pos, radius);
01077     boost::shared_ptr<oxygen::Transform> transform_parent;
01078     boost::shared_ptr<oxygen::Body> agent_body;
01079     std::list<boost::shared_ptr<AgentState> >::const_iterator i;
01080     for (i = agent_states.begin(); i != agent_states.end(); ++i)
01081     {
01082         if (agentState == (*i))
01083             continue;
01084 
01085         SoccerBase::GetTransformParent(*(*i), transform_parent);
01086         // call GetAgentBody with matching AgentAspect
01087         SoccerBase::GetAgentBody(transform_parent, agent_body);
01088         // if agent is too close, move it away
01089         Vector3f new_pos = agent_body->GetPosition();
01090         if (sphere.Contains(new_pos))
01091         {
01092             float dist = salt::UniformRNG<>(min_dist, min_dist + 2.0)();
01093 
01094             if (idx == TI_LEFT)
01095             {
01096                 if (pos[0] - dist < -mFieldLength/2.0)
01097                 {
01098                     new_pos[1] = pos[1] < 0 ? pos[1] + dist : pos[1] - dist;
01099                 } else {
01100                     new_pos[0] = pos[0] - dist;
01101                 }
01102             } else {
01103                 if (pos[0] + dist > mFieldLength/2.0)
01104                 {
01105                     new_pos[1] = pos[1] < 0 ? pos[1] + dist : pos[1] - dist;
01106                 } else {
01107                     new_pos[0] = pos[0] + dist;
01108                 }
01109             }
01110             new_pos[2] = 1.0;
01111             MoveAgent(agent_body, new_pos);
01112         }
01113     }
01114 }

Generated on Thu Apr 6 15:25:40 2006 for rcssserver3d by  doxygen 1.4.4