/game.cpp

http://cutefootball.googlecode.com/ · C++ · 319 lines · 241 code · 51 blank · 27 comment · 26 complexity · eae12e83472426069f2e29dfa4bdb27d MD5 · raw file

  1. /*
  2. * Copyright 2010,2011 Timothy Rochford
  3. *
  4. * This file is part of CuteFootball.
  5. *
  6. * CuteFootball is free software: you can redistribute it and/or modify
  7. * it under the terms of the Lesser GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * CuteFootball is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * Lesser GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the Lesser GNU General Public License
  17. * along with CuteFootball. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include <QStateMachine>
  21. #include <QFinalState>
  22. #include <QHistoryState>
  23. #include "game.h"
  24. #include "goalscoredstate.h"
  25. #include "foulstate.h"
  26. #include "kickoffstate.h"
  27. #include "pitch.h"
  28. #include "pitchscene.h"
  29. #include "ball.h"
  30. #include "Player.h"
  31. #include "team.h"
  32. #include "screengraphics.h"
  33. #include "soccerutils.h"
  34. const QString KFirstHalf(QObject::tr("First half"));
  35. const QString KSecondHalf(QObject::tr("Second half"));
  36. const QString KFirstHalfET(QObject::tr("Extra Time First half"));
  37. const QString KSecondHalfET(QObject::tr("Extra Time Second half"));
  38. const QString KPenaltyShootOut(QObject::tr("penalty shoot out"));
  39. Game::Game(QStateMachine& fsm, Pitch& p)
  40. : QState(),
  41. m_fsm(fsm),
  42. m_pitch(p),
  43. m_currentState(NULL)
  44. {
  45. qDebug() << "Game::Game";
  46. m_pausedState = new QState();
  47. m_firstHalfState = new GameHalf(this, m_pitch,
  48. KFirstHalf, true, false);
  49. m_secondHalfState = new GameHalf(this, m_pitch,
  50. KSecondHalf, false, false);
  51. m_extraTimeFirstHalfState = new GameHalf(this, m_pitch,
  52. KFirstHalfET, true, true);
  53. m_extraTimeSecondHalfState = new GameHalf(this, m_pitch,
  54. KSecondHalfET, false, true);
  55. m_penaltiesState = new GameHalf(this, m_pitch,
  56. KPenaltyShootOut, true, true);
  57. m_allDone = new QFinalState(this);
  58. m_prePausedState = new QHistoryState(this);
  59. m_prePausedState->setHistoryType(QHistoryState::DeepHistory);
  60. m_prePausedState->setDefaultState(m_firstHalfState);
  61. m_fsm.addState(this);
  62. m_fsm.addState(m_pausedState);
  63. m_fsm.setInitialState(this);
  64. setInitialState(m_firstHalfState);
  65. m_pausedState->addTransition(&m_pitch,
  66. SIGNAL(continueGameClock()),
  67. m_prePausedState);
  68. m_firstHalfState->addTransition(m_firstHalfState, SIGNAL(finished()),
  69. m_secondHalfState);
  70. m_secondHalfState->addTransition(m_secondHalfState, SIGNAL(finished()),
  71. m_allDone);
  72. m_extraTimeFirstHalfState->addTransition(m_extraTimeFirstHalfState,
  73. SIGNAL(finished()),
  74. m_extraTimeSecondHalfState);
  75. m_extraTimeSecondHalfState->addTransition(m_extraTimeSecondHalfState,
  76. SIGNAL(finished()),
  77. m_allDone);
  78. m_penaltiesState->addTransition(m_penaltiesState, SIGNAL(finished()),
  79. m_allDone);
  80. connect(m_secondHalfState, SIGNAL(finished()),
  81. &m_pitch, SLOT(gameStop()));
  82. }
  83. Game::~Game()
  84. {
  85. m_currentState = NULL;
  86. delete m_pausedState;
  87. delete m_firstHalfState;
  88. delete m_secondHalfState;
  89. delete m_extraTimeFirstHalfState;
  90. delete m_extraTimeSecondHalfState;
  91. delete m_penaltiesState;
  92. delete m_allDone;
  93. }
  94. void Game::setHalfLength(int totalGameInMinutes)
  95. {
  96. m_firstHalfState->setGameLength(totalGameInMinutes);
  97. m_secondHalfState->setGameLength(totalGameInMinutes);
  98. m_extraTimeFirstHalfState->setGameLength(1);
  99. m_extraTimeSecondHalfState->setGameLength(1);
  100. }
  101. void Game::setTeamToKickOff(Team* t)
  102. {
  103. m_firstHalfState->setTeamToKickOff(t);
  104. m_secondHalfState->setTeamToKickOff(t);
  105. m_extraTimeFirstHalfState->setTeamToKickOff(t);
  106. m_extraTimeSecondHalfState->setTeamToKickOff(t);
  107. }
  108. GameHalf::GameHalf(Game* parent,
  109. Pitch& p,
  110. QString stateName,
  111. bool isFirstHalf,
  112. bool isExtraTime)
  113. : QState(parent),
  114. m_game(parent),
  115. m_pitch(p),
  116. m_isFirstHalf(isFirstHalf),
  117. m_isExtraTime(isExtraTime),
  118. m_remainingTimeInHalfMs( KHalfLength )
  119. {
  120. setObjectName(stateName);
  121. qDebug() << "GameHalf::GameHalf " << objectName();
  122. m_1second = new QTimer(this);
  123. m_1second->setInterval(KOneSecondMs);
  124. m_timeLineLeavePitch = new QTimeLine(KOneSecondMs*5, this);
  125. m_timeLineLeavePitch->setCurveShape(QTimeLine::LinearCurve);
  126. m_timeLineLeavePitch->setFrameRange(0, 100);
  127. m_kickOffState = new KickOffState(this, &m_pitch);
  128. m_playingState = new QState(this);
  129. m_halfEndState = new QState(this);
  130. m_goalScoredState = new GoalScoredState(this, &m_pitch);
  131. m_foulState = new FoulState(this, &m_pitch);
  132. m_allDoneState = new QFinalState(this);
  133. setInitialState(m_kickOffState);
  134. m_kickOffState->addTransition(m_kickOffState, SIGNAL(finished()), m_playingState);
  135. m_playingState->addTransition(this, SIGNAL(halfOver(QString)), m_halfEndState);
  136. m_playingState->addTransition(&m_pitch, SIGNAL(foul(Team*,QPointF)), m_foulState);
  137. m_playingState->addTransition(m_pitch.ball(), SIGNAL(goalScored(bool)), m_goalScoredState);
  138. m_goalScoredState->addTransition(m_goalScoredState, SIGNAL(finished()), m_kickOffState);
  139. m_foulState->addTransition(m_foulState, SIGNAL(finished()), m_playingState);
  140. m_halfEndState->addTransition(m_timeLineLeavePitch, SIGNAL(finished()), m_allDoneState);
  141. connect(this, SIGNAL(halfOver(QString)),
  142. this, SLOT(startPlayersLeavePitchAnim(QString)));
  143. connect(m_timeLineLeavePitch, SIGNAL(frameChanged(int)), this, SLOT(playFrame(int)));
  144. connect(m_1second, SIGNAL(timeout()),
  145. this, SLOT(decrementGameTime()));
  146. connect(&m_pitch, SIGNAL(foul(Team*,QPointF)),
  147. this, SLOT(foulCaused(Team*,QPointF)));
  148. connect(&m_pitch, SIGNAL(pauseGameClock()),
  149. this, SLOT(pauseGameClock()));
  150. connect(&m_pitch, SIGNAL(continueGameClock()),
  151. this, SLOT(continueGameClock()));
  152. }
  153. void GameHalf::foulCaused(Team* orig, QPointF location)
  154. {
  155. //qDebug() << "Game::foulCaused";
  156. m_foulingTeam = orig;
  157. m_foulingLocation = location;
  158. m_pitch.ball()->setPos(m_foulingLocation);
  159. }
  160. GameHalf::~GameHalf()
  161. {
  162. // pauseGameClock();
  163. delete m_1second;
  164. delete m_timeLineLeavePitch;
  165. }
  166. void GameHalf::decrementGameTime()
  167. {
  168. m_remainingTimeInHalfMs = m_remainingTimeInHalfMs - KOneSecondMs;
  169. m_pitch.updateDisplayTime(m_remainingTimeInHalfMs);
  170. if (m_remainingTimeInHalfMs == 0) {
  171. // players are now allowed off the pitch
  172. foreach (Player *p, m_pitch.m_players) {
  173. p->setAllowedOffPitch(true);
  174. }
  175. //qDebug() << "GameHalf::decrementGameTime half over " << objectName();
  176. emit halfOver(objectName());
  177. }
  178. }
  179. void GameHalf::startPlayersLeavePitchAnim(QString /* halfName */)
  180. {
  181. //qDebug() << "GameHalf::startPlayersLeavePitchAnim " << objectName();
  182. createPlayerAnimationItems();
  183. if (m_1second->isActive())
  184. m_1second->stop();
  185. m_timeLineLeavePitch->start();
  186. }
  187. void GameHalf::pauseGameClock()
  188. {
  189. if (m_game->currentState() != this)
  190. return;
  191. qDebug() << "GameHalf::pauseGameClock() " << objectName();
  192. if (m_1second->isActive())
  193. m_1second->stop();
  194. else if (m_timeLineLeavePitch->state() == QTimeLine::Running)
  195. m_timeLineLeavePitch->setPaused(true);
  196. }
  197. void GameHalf::continueGameClock()
  198. {
  199. if (m_game->currentState() != this)
  200. return;
  201. if (m_timeLineLeavePitch->state() == QTimeLine::Paused) {
  202. m_timeLineLeavePitch->setPaused(false);
  203. } else if (!m_1second->isActive())
  204. m_1second->start();
  205. }
  206. void GameHalf::playFrame(int frame)
  207. {
  208. m_pitch.centerOn(m_playerAnimationItems.last()->item());
  209. qreal f = frame/ 100.00;
  210. foreach (QGraphicsItemAnimation *anim, m_playerAnimationItems)
  211. anim->item()->setPos(anim->posAt(f));
  212. m_pitch.scene()->update();
  213. }
  214. // animate from present player position to another point.
  215. void GameHalf::createPlayerAnimationItems()
  216. {
  217. //qDebug() << "GameHalf::createPlayerAnimationItems " << objectName();
  218. m_playerAnimationItems.clear(); // TODO XXX TIM delete all
  219. foreach (Player *p, m_pitch.m_players) {
  220. QGraphicsItemAnimation* anim = new QGraphicsItemAnimation(this);
  221. anim->setItem(p);
  222. m_playerAnimationItems.append(anim);
  223. anim->setTimeLine(m_timeLineLeavePitch);
  224. QPointF tmp(p->pos());
  225. qreal stepX = ( m_pitch.pitchEntrancePoint().x() - tmp.x() ) / 100.0;
  226. qreal stepY = ( m_pitch.pitchEntrancePoint().y() - tmp.y() ) / 100.0;
  227. MWindow::Action a = calculateAction(tmp, m_pitch.pitchEntrancePoint());
  228. p->setAllowedOffPitch(true);
  229. p->movePlayer(a);
  230. for (int i = 0; i < 100; ++i) {
  231. QPointF newPos(tmp.x() + stepX,tmp.y() + stepY);
  232. anim->setPosAt(i / 100.0, newPos);
  233. tmp = newPos;
  234. }
  235. }
  236. }
  237. void GameHalf::onEntry(QEvent * /* event */)
  238. {
  239. qDebug() << "GameHalf::onEntry " << objectName();
  240. m_game->setCurrentState(this);
  241. m_pitch.setGraphics(ScreenGraphics::ScoreText);
  242. m_pitch.updateDisplayTime(remainingTimeInHalfMs());
  243. if ( m_isFirstHalf ) {
  244. m_pitch.homeTeam()->setDirection(Team::NorthToSouth);
  245. m_pitch.setPlayerStartPositions(m_pitch.homeTeam());
  246. m_pitch.awayTeam()->setDirection(Team::SouthToNorth);
  247. m_pitch.setPlayerStartPositions(m_pitch.awayTeam());
  248. } else {
  249. m_pitch.awayTeam()->setDirection(Team::NorthToSouth);
  250. m_pitch.setPlayerStartPositions(m_pitch.awayTeam());
  251. m_pitch.homeTeam()->setDirection(Team::SouthToNorth);
  252. m_pitch.setPlayerStartPositions(m_pitch.homeTeam());
  253. }
  254. }
  255. void GameHalf::onExit(QEvent * /* event */)
  256. {
  257. //qDebug() << "GameHalf::onExit() " << objectName();
  258. if ((objectName() == KSecondHalfET) && m_pitch.extraTimeAllowed()) {
  259. if ( m_pitch.extraTime() )
  260. m_pitch.setPenaltyShootOut(true);
  261. else
  262. m_pitch.setPenaltyShootOut(false);
  263. } else if (objectName() == KPenaltyShootOut)
  264. m_pitch.setPenaltyShootOut(false);
  265. m_pitch.scene()->removeItem(m_pitch.ball());
  266. if (m_1second->isActive())
  267. m_1second->stop();
  268. }