PageRenderTime 38ms CodeModel.GetById 12ms app.highlight 21ms RepoModel.GetById 2ms app.codeStats 0ms

/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
 24#include "game.h"
 25#include "goalscoredstate.h"
 26#include "foulstate.h"
 27#include "kickoffstate.h"
 28#include "pitch.h"
 29#include "pitchscene.h"
 30#include "ball.h"
 31#include "Player.h"
 32#include "team.h"
 33#include "screengraphics.h"
 34#include "soccerutils.h"
 35
 36const QString KFirstHalf(QObject::tr("First half"));
 37const QString KSecondHalf(QObject::tr("Second half"));
 38const QString KFirstHalfET(QObject::tr("Extra Time First half"));
 39const QString KSecondHalfET(QObject::tr("Extra Time Second half"));
 40const QString KPenaltyShootOut(QObject::tr("penalty shoot out"));
 41
 42Game::Game(QStateMachine& fsm, Pitch& p)
 43    : QState(),
 44      m_fsm(fsm),
 45      m_pitch(p),
 46      m_currentState(NULL)
 47{
 48    qDebug() << "Game::Game";
 49    m_pausedState = new QState();
 50
 51    m_firstHalfState = new GameHalf(this, m_pitch,
 52                                    KFirstHalf, true, false);
 53    m_secondHalfState = new GameHalf(this, m_pitch,
 54                                     KSecondHalf, false, false);
 55    m_extraTimeFirstHalfState = new GameHalf(this, m_pitch,
 56                                             KFirstHalfET, true, true);
 57    m_extraTimeSecondHalfState = new GameHalf(this, m_pitch,
 58                                              KSecondHalfET, false, true);
 59    m_penaltiesState = new GameHalf(this, m_pitch,
 60                                    KPenaltyShootOut, true, true);
 61
 62    m_allDone = new QFinalState(this);
 63
 64    m_prePausedState = new QHistoryState(this);
 65    m_prePausedState->setHistoryType(QHistoryState::DeepHistory);
 66    m_prePausedState->setDefaultState(m_firstHalfState);
 67
 68    m_fsm.addState(this);
 69
 70    m_fsm.addState(m_pausedState);
 71
 72    m_fsm.setInitialState(this);
 73    setInitialState(m_firstHalfState);
 74
 75    m_pausedState->addTransition(&m_pitch,
 76                                 SIGNAL(continueGameClock()),
 77                                 m_prePausedState);
 78    m_firstHalfState->addTransition(m_firstHalfState, SIGNAL(finished()),
 79                                    m_secondHalfState);
 80    m_secondHalfState->addTransition(m_secondHalfState, SIGNAL(finished()),
 81                                     m_allDone);
 82    m_extraTimeFirstHalfState->addTransition(m_extraTimeFirstHalfState,
 83                                             SIGNAL(finished()),
 84                                             m_extraTimeSecondHalfState);
 85    m_extraTimeSecondHalfState->addTransition(m_extraTimeSecondHalfState,
 86                                              SIGNAL(finished()),
 87                                              m_allDone);
 88    m_penaltiesState->addTransition(m_penaltiesState, SIGNAL(finished()),
 89                                    m_allDone);
 90    connect(m_secondHalfState, SIGNAL(finished()),
 91            &m_pitch, SLOT(gameStop()));
 92}
 93
 94Game::~Game()
 95{
 96    m_currentState = NULL;
 97    delete m_pausedState;
 98    delete m_firstHalfState;
 99    delete m_secondHalfState;
100    delete m_extraTimeFirstHalfState;
101    delete m_extraTimeSecondHalfState;
102    delete m_penaltiesState;
103    delete m_allDone;
104}
105void Game::setHalfLength(int totalGameInMinutes)
106{
107    m_firstHalfState->setGameLength(totalGameInMinutes);
108    m_secondHalfState->setGameLength(totalGameInMinutes);
109    m_extraTimeFirstHalfState->setGameLength(1);
110    m_extraTimeSecondHalfState->setGameLength(1);
111}
112
113void Game::setTeamToKickOff(Team* t)
114{
115    m_firstHalfState->setTeamToKickOff(t);
116    m_secondHalfState->setTeamToKickOff(t);
117    m_extraTimeFirstHalfState->setTeamToKickOff(t);
118    m_extraTimeSecondHalfState->setTeamToKickOff(t);
119}
120
121GameHalf::GameHalf(Game* parent,
122                   Pitch& p,
123                   QString stateName,
124                   bool isFirstHalf,
125                   bool isExtraTime)
126    : QState(parent),  
127    m_game(parent),
128    m_pitch(p),
129    m_isFirstHalf(isFirstHalf),
130    m_isExtraTime(isExtraTime),
131    m_remainingTimeInHalfMs( KHalfLength )
132{
133    setObjectName(stateName);
134    qDebug() << "GameHalf::GameHalf " << objectName();
135    m_1second = new QTimer(this);
136    m_1second->setInterval(KOneSecondMs);
137
138    m_timeLineLeavePitch = new QTimeLine(KOneSecondMs*5, this);
139    m_timeLineLeavePitch->setCurveShape(QTimeLine::LinearCurve);
140    m_timeLineLeavePitch->setFrameRange(0, 100);
141
142    m_kickOffState = new KickOffState(this, &m_pitch);
143
144
145    m_playingState = new QState(this);
146    m_halfEndState = new QState(this);
147    m_goalScoredState = new GoalScoredState(this, &m_pitch);
148    m_foulState = new FoulState(this, &m_pitch);
149    m_allDoneState = new QFinalState(this);
150    setInitialState(m_kickOffState);
151
152    m_kickOffState->addTransition(m_kickOffState, SIGNAL(finished()), m_playingState);
153
154    m_playingState->addTransition(this, SIGNAL(halfOver(QString)), m_halfEndState);
155    m_playingState->addTransition(&m_pitch, SIGNAL(foul(Team*,QPointF)), m_foulState);
156    m_playingState->addTransition(m_pitch.ball(), SIGNAL(goalScored(bool)), m_goalScoredState);
157
158    m_goalScoredState->addTransition(m_goalScoredState, SIGNAL(finished()), m_kickOffState);
159
160    m_foulState->addTransition(m_foulState, SIGNAL(finished()), m_playingState);
161
162    m_halfEndState->addTransition(m_timeLineLeavePitch, SIGNAL(finished()), m_allDoneState);
163
164
165    connect(this, SIGNAL(halfOver(QString)),
166            this, SLOT(startPlayersLeavePitchAnim(QString)));
167    connect(m_timeLineLeavePitch, SIGNAL(frameChanged(int)), this, SLOT(playFrame(int)));
168
169    connect(m_1second, SIGNAL(timeout()),
170            this, SLOT(decrementGameTime()));
171
172    connect(&m_pitch, SIGNAL(foul(Team*,QPointF)),
173            this, SLOT(foulCaused(Team*,QPointF)));
174    connect(&m_pitch, SIGNAL(pauseGameClock()),
175            this, SLOT(pauseGameClock()));
176    connect(&m_pitch, SIGNAL(continueGameClock()),
177            this, SLOT(continueGameClock()));
178}
179
180void GameHalf::foulCaused(Team* orig, QPointF location)
181{
182    //qDebug() << "Game::foulCaused";
183    m_foulingTeam = orig;
184    m_foulingLocation = location;
185    m_pitch.ball()->setPos(m_foulingLocation);
186}
187
188GameHalf::~GameHalf()
189{
190//    pauseGameClock();
191    delete m_1second;
192
193    delete m_timeLineLeavePitch;
194}
195
196void GameHalf::decrementGameTime()
197{
198    m_remainingTimeInHalfMs = m_remainingTimeInHalfMs - KOneSecondMs;
199    m_pitch.updateDisplayTime(m_remainingTimeInHalfMs);
200    if (m_remainingTimeInHalfMs == 0) {
201        // players are now allowed off the pitch
202        foreach (Player *p, m_pitch.m_players) {
203            p->setAllowedOffPitch(true);
204        }
205        //qDebug() << "GameHalf::decrementGameTime half over " << objectName();
206        emit halfOver(objectName());
207    }
208}
209
210void GameHalf::startPlayersLeavePitchAnim(QString /* halfName */)
211{
212    //qDebug() << "GameHalf::startPlayersLeavePitchAnim " << objectName();
213    createPlayerAnimationItems();
214    if (m_1second->isActive())
215        m_1second->stop();
216    m_timeLineLeavePitch->start();
217}
218
219void GameHalf::pauseGameClock()
220{
221    if (m_game->currentState() != this)
222        return;
223
224    qDebug() << "GameHalf::pauseGameClock() " << objectName();
225    if (m_1second->isActive())
226        m_1second->stop();
227    else if (m_timeLineLeavePitch->state() == QTimeLine::Running)
228        m_timeLineLeavePitch->setPaused(true);
229}
230
231void GameHalf::continueGameClock()
232{
233    if (m_game->currentState() != this)
234        return;
235
236    if (m_timeLineLeavePitch->state() == QTimeLine::Paused) {
237        m_timeLineLeavePitch->setPaused(false);
238    } else if (!m_1second->isActive())
239            m_1second->start();
240}
241
242void GameHalf::playFrame(int frame)
243{
244    m_pitch.centerOn(m_playerAnimationItems.last()->item());
245
246    qreal f = frame/ 100.00;
247    foreach (QGraphicsItemAnimation *anim, m_playerAnimationItems)
248        anim->item()->setPos(anim->posAt(f));
249
250    m_pitch.scene()->update();
251}
252
253// animate from present player position to another point.
254void GameHalf::createPlayerAnimationItems()
255{
256    //qDebug() << "GameHalf::createPlayerAnimationItems " << objectName();
257    m_playerAnimationItems.clear(); // TODO XXX TIM delete all
258
259    foreach (Player *p, m_pitch.m_players) {
260        QGraphicsItemAnimation* anim = new QGraphicsItemAnimation(this);
261        anim->setItem(p);
262        m_playerAnimationItems.append(anim);
263        anim->setTimeLine(m_timeLineLeavePitch);
264
265        QPointF tmp(p->pos());
266        qreal stepX = ( m_pitch.pitchEntrancePoint().x() - tmp.x() ) / 100.0;
267        qreal stepY = ( m_pitch.pitchEntrancePoint().y() - tmp.y() ) / 100.0;
268        MWindow::Action a = calculateAction(tmp, m_pitch.pitchEntrancePoint());
269        p->setAllowedOffPitch(true);
270        p->movePlayer(a);
271
272        for (int i = 0; i < 100; ++i) {
273            QPointF newPos(tmp.x() + stepX,tmp.y() + stepY);
274            anim->setPosAt(i / 100.0, newPos);
275            tmp = newPos;
276        }
277    }
278}
279
280void GameHalf::onEntry(QEvent * /* event */)
281{
282    qDebug() << "GameHalf::onEntry " << objectName();
283    m_game->setCurrentState(this);
284
285    m_pitch.setGraphics(ScreenGraphics::ScoreText);
286    m_pitch.updateDisplayTime(remainingTimeInHalfMs());
287    if (  m_isFirstHalf ) {
288        m_pitch.homeTeam()->setDirection(Team::NorthToSouth);
289        m_pitch.setPlayerStartPositions(m_pitch.homeTeam());
290
291        m_pitch.awayTeam()->setDirection(Team::SouthToNorth);
292        m_pitch.setPlayerStartPositions(m_pitch.awayTeam());
293    } else {
294        m_pitch.awayTeam()->setDirection(Team::NorthToSouth);
295        m_pitch.setPlayerStartPositions(m_pitch.awayTeam());
296
297        m_pitch.homeTeam()->setDirection(Team::SouthToNorth);
298        m_pitch.setPlayerStartPositions(m_pitch.homeTeam());
299    }
300}
301
302void GameHalf::onExit(QEvent * /* event */)
303{
304    //qDebug() << "GameHalf::onExit() " << objectName();
305    if ((objectName() == KSecondHalfET) && m_pitch.extraTimeAllowed()) {
306        if ( m_pitch.extraTime() )
307            m_pitch.setPenaltyShootOut(true);
308        else
309            m_pitch.setPenaltyShootOut(false);
310    } else if (objectName() == KPenaltyShootOut)
311        m_pitch.setPenaltyShootOut(false);
312
313    m_pitch.scene()->removeItem(m_pitch.ball());
314
315    if (m_1second->isActive())
316        m_1second->stop();
317}
318
319