#include "SoccerTeam.h"
#include "SoccerPitch.h"
#include "Goal.h"
#include "PlayerBase.h"
#include "GoalKeeper.h"
#include "FieldPlayer.h"
#include "utils.h"
#include "SteeringBehaviors.h"
#include "GoalKeeperStates.h"
#include "ParamLoader.h"
#include "geometry.h"
#include "EntityManager.h"
#include "MessageDispatcher.h"
#include "SoccerMessages.h"
#include "TeamStates.h"
#include "DebugConsole.h"
#include <windows.h>
using std::vector;
//----------------------------- ctor -------------------------------------
//
//------------------------------------------------------------------------
SoccerTeam::SoccerTeam(Goal* home_goal,
Goal* opponents_goal,
SoccerPitch* pitch,
team_color color):m_pOpponentsGoal(opponents_goal),
m_pHomeGoal(home_goal),
m_pOpponents(NULL),
m_pPitch(pitch),
m_Color(color),
m_dDistSqToBallOfClosestPlayer(0.0),
m_pSupportingPlayer(NULL),
m_pReceivingPlayer(NULL),
m_pControllingPlayer(NULL),
m_pPlayerClosestToBall(NULL)
{
//setup the state machine
m_pStateMachine = new StateMachine<SoccerTeam>(this);
m_pStateMachine->SetCurrentState(Defending::Instance());
m_pStateMachine->SetPreviousState(Defending::Instance());
m_pStateMachine->SetGlobalState(NULL);
//create the players and goalkeeper
CreatePlayers();
//set default steering behaviors
std::vector<PlayerBase*>::iterator it = m_Players.begin();
for (it; it != m_Players.end(); ++it)
{
(*it)->Steering()->SeparationOn();
}
//create the sweet spot calculator
m_pSupportSpotCalc = new SupportSpotCalculator(Prm.NumSupportSpotsX,
Prm.NumSupportSpotsY,
this);
}
//----------------------- dtor -------------------------------------------
//
//------------------------------------------------------------------------
SoccerTeam::~SoccerTeam()
{
delete m_pStateMachine;
std::vector<PlayerBase*>::iterator it = m_Players.begin();
for (it; it != m_Players.end(); ++it)
{
delete *it;
}
delete m_pSupportSpotCalc;
}
//-------------------------- update --------------------------------------
//
// iterates through each player's update function and calculates
// frequently accessed info
//------------------------------------------------------------------------
void SoccerTeam::Update()
{
//this information is used frequently so it's more efficient to
//calculate it just once each frame
CalculateClosestPlayerToBall();
//the team state machine switches between attack/defense behavior. It
//also handles the 'kick off' state where a team must return to their
//kick off positions before the whistle is blown
m_pStateMachine->Update();
//now update each player
std::vector<PlayerBase*>::iterator it = m_Players.begin();
for (it; it != m_Players.end(); ++it)
{
(*it)->Update();
}
}
//------------------------ CalculateClosestPlayerToBall ------------------
//
// sets m_iClosestPlayerToBall to the player closest to the ball
//------------------------------------------------------------------------
void SoccerTeam::CalculateClosestPlayerToBall()
{
double ClosestSoFar = MaxFloat;
std::vector<PlayerBase*>::iterator it = m_Players.begin();
for (it; it != m_Players.end(); ++it)
{
//calculate the dist. Use the squared value to avoid sqrt
double dist = Vec2DDistanceSq((*it)->Pos(), Pitch()->Ball()->Pos());
//keep a record of this value for each player
(*it)->SetDistSqToBall(dist);
if (dist < ClosestSoFar)
{
ClosestSoFar = dist;
m_pPlayerClosestToBall = *it;
}
}
m_dDistSqToBallOfClosestPlayer = ClosestSoFar;
}
//------------- DetermineBestSupportingAttacker ------------------------
//
// calculate the closest player to the SupportSpot
//------------------------------------------------------------------------
PlayerBase* SoccerTeam::DetermineBestSupportingAttacker()
{
double ClosestSoFar = MaxFloat;
PlayerBase* BestPlayer = NULL;
std::vector<PlayerBase*>::iterator it = m_Players.begin();
for (it; it != m_Players.end(); ++it)
{
//only attackers utilize the BestSupportingSpot
if ( ((*it)->Role() == PlayerBase::attacker) && ((*it) != m_pControllingPlayer) )
{
//calculate the dist. Use the squared value to avoid sqrt
double dist = Vec2DDistanceSq((*it)->Pos(), m_pSupportSpotCalc->GetBestSupportingSpot());
//if the distance is the closest so far and the player is not a
//goalkeeper and the player is not the one currently controlling
//the ball, keep a record of this player
if ((dist < ClosestSoFar) )
{
ClosestSoFar = dist;
BestPlayer = (*it);
}
}
}
return BestPlayer;
}
//-------------------------- FindPass ------------------------------
//
// The best pass is considered to be the pass that cannot be intercepted
// by an opponent and that is as far forward of the receiver as possible
//------------------------------------------------------------------------
bool SoccerTeam::FindPass(const PlayerBase*const passer,
PlayerBase*& receiver,
Vector2D& PassTarget,
double power,
double MinPassingDistance)const
{
std::vector<PlayerBase*>::const_iterator curPlyr = Members().begin();
double ClosestToGoalSoFar = MaxFloat;
Vector2D Target;
//iterate through all this player's team members and calculate which
//one is in a position to be passed the ball
for (curPlyr; curPlyr != Members().end(); ++curPlyr)
{
//make sure the potential receiver being examined is not this player
//and that it is further away than the minimum pass distance
if ( (*curPlyr != passer) &&
(Vec2DDistanceSq(passer->Pos(), (*curPlyr)->Pos()) >
MinPassingDistance*MinPassingDistance))
{
if (GetBestPassToReceiver(passer, *curPlyr, Target, power))
{
//if the pass target is the closest to the opponent's goal line found
// so far, keep a record of it
double Dist2Goal = fabs(Target.x - OpponentsGoal()->Center().x);
if (Dist2Goal < ClosestToGoalSoFar)
{
ClosestToGoalSoFar = Dist2Goal;
//keep a record of this player
receiver = *curPlyr;
//and the target
PassTarget = Target;
}
}
}
}//next team member
if (receiver) return true;
else return false;
}
//---------------------- GetBestPassToReceiver ---------------------------
//
// Three potential passes are calculated. One directly toward the receiver's
// current position and two that are the tangents from the ball position
// to the circle of radius 'range' from the receiver.
// These passes are then tested to see if they can be intercepted by an
// opponent and to make sure they terminate within the playing area. If
// all the passes are invalidated the function returns false. Otherwise
// the function returns the pass that takes the ball closest to the
// opponent's goal area.
//------------------------------------------------------------------------
bool SoccerTeam: