⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 soccerteam.cpp

📁 用人工智能实现的足球机器人人仿真比赛的程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "SoccerTeam.h"
#include "SoccerPitch.h"
#include "Goal.h"
#include "PlayerBase.h"
#include "GoalKeeper.h"
#include "FieldPlayer.h"
#include "misc/utils.h"
#include "SteeringBehaviors.h"
#include "GoalKeeperStates.h"
#include "ParamLoader.h"
#include "2D/geometry.h"
#include "Game/EntityManager.h"
#include "Messaging/MessageDispatcher.h"
#include "SoccerMessages.h"
#include "TeamStates.h"
#include "Debug/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::GetBestPassToReceiver(const PlayerBase* const passer,
                                       const PlayerBase* const receiver,
                                       Vector2D&               PassTarget,
                                       double                   power)const
{  
  //first, calculate how much time it will take for the ball to reach 
  //this receiver, if the receiver was to remain motionless 
  double time = Pitch()->Ball()->TimeToCoverDistance(Pitch()->Ball()->Pos(),
                                                    receiver->Pos(),
                                                    power);

  //return false if ball cannot reach the receiver after having been
  //kicked with the given power
  if (time < 0) return false;

  //the maximum distance the receiver can cover in this time
  double InterceptRange = time * receiver->MaxSpeed();
  
  //Scale the intercept range
  const double ScalingFactor = 0.3;
  InterceptRange *= ScalingFactor;

  //now calculate the pass targets which are positioned at the intercepts
  //of the tangents from the ball to the receiver's range circle.
  Vector2D ip1, ip2;

  GetTangentPoints(receiver->Pos(),
                   InterceptRange,
                   Pitch()->Ball()->Pos(),
                   ip1,
                   ip2);
 
  const int NumPassesToTry = 3;
  Vector2D Passes[NumPassesToTry] = {ip1, receiver->Pos(), ip2};
  
  
  // this pass is the best found so far if it is:
  //
  //  1. Further upfield than the closest valid pass for this receiver
  //     found so far
  //  2. Within the playing area
  //  3. Cannot be intercepted by any opponents

  double ClosestSoFar = MaxFloat;
  bool  bResult      = false;

  for (int pass=0; pass<NumPassesToTry; ++pass)
  {    
    double dist = fabs(Passes[pass].x - OpponentsGoal()->Center().x);

    if (( dist < ClosestSoFar) &&
        Pitch()->PlayingArea()->Inside(Passes[pass]) &&
        isPassSafeFromAllOpponents(Pitch()->Ball()->Pos(),
                                   Passes[pass],
                                   receiver,
                                   power))
        
    {
      ClosestSoFar = dist;
      PassTarget   = Passes[pass];
      bResult      = true;
    }
  }

  return bResult;
}

//----------------------- isPassSafeFromOpponent -------------------------
//
//  test if a pass from 'from' to 'to' can be intercepted by an opposing
//  player
//------------------------------------------------------------------------
bool SoccerTeam::isPassSafeFromOpponent(Vector2D    from,
                                        Vector2D    target,
                                        const PlayerBase* const receiver,
                                        const PlayerBase* const opp,
                                        double       PassingForce)const
{
  //move the opponent into local space.
  Vector2D ToTarget = target - from;
  Vector2D ToTargetNormalized = Vec2DNormalize(ToTarget);

  Vector2D LocalPosOpp = PointToLocalSpace(opp->Pos(),
                                         ToTargetNormalized,
                                         ToTargetNormalized.Perp(),
                                         from);

  //if opponent is behind the kicker then pass is considered okay(this is 
  //based on the assumption that the ball is going to be kicked with a 
  //velocity greater than the opponent's max velocity)
  if ( LocalPosOpp.x < 0 )
  {     
    return true;
  }
  
  //if the opponent is further away than the target we need to consider if
  //the opponent can reach the position before the receiver.
  if (Vec2DDistanceSq(from, target) < Vec2DDistanceSq(opp->Pos(), from))
  {
    if (receiver)
    {
      if ( Vec2DDistanceSq(target, opp->Pos())  > 
           Vec2DDistanceSq(target, receiver->Pos()) )
      {
        return true;
      }

      else
      {
        return false;
      }

    }

    else
    {
      return true;
    } 
  }
  
  //calculate how long it takes the ball to cover the distance to the 
  //position orthogonal to the opponents position
  double TimeForBall = 
  Pitch()->Ball()->TimeToCoverDistance(Vector2D(0,0),
                                       Vector2D(LocalPosOpp.x, 0),
                                       PassingForce);

  //now calculate how far the opponent can run in this time
  double reach = opp->MaxSpeed() * TimeForBall +
                Pitch()->Ball()->BRadius()+
                opp->BRadius();

  //if the distance to the opponent's y position is less than his running
  //range plus the radius of the ball and the opponents radius then the
  //ball can be intercepted
  if ( fabs(LocalPosOpp.y) < reach )
  {
    return false;
  }

  return true;
}

//---------------------- isPassSafeFromAllOpponents ----------------------
//
//  tests a pass from position 'from' to position 'target' against each member
//  of the opposing team. Returns true if the pass can be made without
//  getting intercepted
//------------------------------------------------------------------------
bool SoccerTeam::isPassSafeFromAllOpponents(Vector2D                from,
                                            Vector2D                target,
                                            const PlayerBase* const receiver,
                                            double     PassingForce)const
{
  std::vector<PlayerBase*>::const_iterator opp = Opponents()->Members().begin();

  for (opp; opp != Opponents()->Members().end(); ++opp)
  {
    if (!isPassSafeFromOpponent(from, target, receiver, *opp, PassingForce))
    {
      debug_on
        
      return false;
    }
  }

  return true;
}

//------------------------ CanShoot --------------------------------------
//
//  Given a ball position, a kicking power and a reference to a vector2D
//  this function will sample random positions along the opponent's goal-
//  mouth and check to see if a goal can be scored if the ball was to be
//  kicked in that direction with the given power. If a possible shot is 
//  found, the function will immediately return true, with the target 
//  position stored in the vector ShotTarget.
//------------------------------------------------------------------------
bool SoccerTeam::CanShoot(Vector2D  BallPos,
                          double     power, 
                          Vector2D& ShotTarget)const
{
  //the number of randomly created shot targets this method will test 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -