1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51//Own
52#include "graphicsscene.h"
53#include "states.h"
54#include "boat.h"
55#include "submarine.h"
56#include "torpedo.h"
57#include "bomb.h"
58#include "animationmanager.h"
59#include "qanimationstate.h"
60#include "progressitem.h"
61#include "textinformationitem.h"
62
63//Qt
64#include <QAction>
65#include <QApplication>
66#include <QFile>
67#include <QFinalState>
68#include <QParallelAnimationGroup>
69#include <QPropertyAnimation>
70#include <QSequentialAnimationGroup>
71#include <QStateMachine>
72#include <QXmlStreamReader>
73
74GraphicsScene::GraphicsScene(int x, int y, int width, int height, Mode mode, QObject *parent)
75 : QGraphicsScene(x, y, width, height, parent), mode(mode), boat(new Boat)
76{
77 PixmapItem *backgroundItem = new PixmapItem(QStringLiteral("background"), mode);
78 backgroundItem->setZValue(1);
79 backgroundItem->setPos(ax: 0,ay: 0);
80 addItem(item: backgroundItem);
81
82 PixmapItem *surfaceItem = new PixmapItem(QStringLiteral("surface"), mode);
83 surfaceItem->setZValue(3);
84 surfaceItem->setPos(ax: 0, ay: sealLevel() - surfaceItem->boundingRect().height() / 2);
85 addItem(item: surfaceItem);
86
87 //The item that display score and level
88 progressItem = new ProgressItem(backgroundItem);
89
90 textInformationItem = new TextInformationItem(backgroundItem);
91 textInformationItem->hide();
92 //We create the boat
93 addItem(item: boat);
94 boat->setPos(ax: this->width()/2, ay: sealLevel() - boat->size().height());
95 boat->hide();
96
97 //parse the xml that contain all data of the game
98 QXmlStreamReader reader;
99 QFile file(":data.xml");
100 file.open(flags: QIODevice::ReadOnly);
101 reader.setDevice(&file);
102 LevelDescription currentLevel;
103 while (!reader.atEnd()) {
104 reader.readNext();
105 if (reader.tokenType() == QXmlStreamReader::StartElement) {
106 if (reader.name() == "submarine") {
107 SubmarineDescription desc;
108 desc.name = reader.attributes().value(qualifiedName: "name").toString();
109 desc.points = reader.attributes().value(qualifiedName: "points").toInt();
110 desc.type = reader.attributes().value(qualifiedName: "type").toInt();
111 submarinesData.append(t: desc);
112 } else if (reader.name() == "level") {
113 currentLevel.id = reader.attributes().value(qualifiedName: "id").toInt();
114 currentLevel.name = reader.attributes().value(qualifiedName: "name").toString();
115 } else if (reader.name() == "subinstance") {
116 currentLevel.submarines.append(t: qMakePair(x: reader.attributes().value(qualifiedName: "type").toInt(),
117 y: reader.attributes().value(qualifiedName: "nb").toInt()));
118 }
119 } else if (reader.tokenType() == QXmlStreamReader::EndElement) {
120 if (reader.name() == "level") {
121 levelsData.insert(akey: currentLevel.id, avalue: currentLevel);
122 currentLevel.submarines.clear();
123 }
124 }
125 }
126}
127
128qreal GraphicsScene::sealLevel() const
129{
130 return (mode == Big) ? 220 : 160;
131}
132
133void GraphicsScene::setupScene(QAction *newAction, QAction *quitAction)
134{
135 static constexpr int nLetters = 10;
136 static constexpr struct {
137 char const *pix;
138 qreal initX, initY;
139 qreal destX, destY;
140 } logoData[nLetters] = {
141 {.pix: "s", .initX: -1000, .initY: -1000, .destX: 300, .destY: 150 },
142 {.pix: "u", .initX: -800, .initY: -1000, .destX: 350, .destY: 150 },
143 {.pix: "b", .initX: -600, .initY: -1000, .destX: 400, .destY: 120 },
144 {.pix: "dash", .initX: -400, .initY: -1000, .destX: 460, .destY: 150 },
145 {.pix: "a", .initX: 1000, .initY: 2000, .destX: 350, .destY: 250 },
146 {.pix: "t", .initX: 800, .initY: 2000, .destX: 400, .destY: 250 },
147 {.pix: "t2", .initX: 600, .initY: 2000, .destX: 430, .destY: 250 },
148 {.pix: "a2", .initX: 400, .initY: 2000, .destX: 465, .destY: 250 },
149 {.pix: "q", .initX: 200, .initY: 2000, .destX: 510, .destY: 250 },
150 {.pix: "excl", .initX: 0, .initY: 2000, .destX: 570, .destY: 220 } };
151
152 QSequentialAnimationGroup *lettersGroupMoving = new QSequentialAnimationGroup(this);
153 QParallelAnimationGroup *lettersGroupFading = new QParallelAnimationGroup(this);
154
155 for (int i = 0; i < nLetters; ++i) {
156 PixmapItem * = new PixmapItem(QLatin1String(":/logo-") + logoData[i].pix, this);
157 logo->setPos(ax: logoData[i].initX, ay: logoData[i].initY);
158 logo->setZValue(i + 3);
159 //creation of the animations for moving letters
160 QPropertyAnimation *moveAnim = new QPropertyAnimation(logo, "pos", lettersGroupMoving);
161 moveAnim->setEndValue(QPointF(logoData[i].destX, logoData[i].destY));
162 moveAnim->setDuration(200);
163 moveAnim->setEasingCurve(QEasingCurve::OutElastic);
164 lettersGroupMoving->addPause(msecs: 50);
165 //creation of the animations for fading out the letters
166 QPropertyAnimation *fadeAnim = new QPropertyAnimation(logo, "opacity", lettersGroupFading);
167 fadeAnim->setDuration(800);
168 fadeAnim->setEndValue(0);
169 fadeAnim->setEasingCurve(QEasingCurve::OutQuad);
170 }
171
172 QStateMachine *machine = new QStateMachine(this);
173
174 //This state is when the player is playing
175 PlayState *gameState = new PlayState(this, machine);
176
177 //Final state
178 QFinalState *finalState = new QFinalState(machine);
179
180 //Animation when the player enter in the game
181 QAnimationState *lettersMovingState = new QAnimationState(machine);
182 lettersMovingState->setAnimation(lettersGroupMoving);
183
184 //Animation when the welcome screen disappear
185 QAnimationState *lettersFadingState = new QAnimationState(machine);
186 lettersFadingState->setAnimation(lettersGroupFading);
187
188 //if new game then we fade out the welcome screen and start playing
189 lettersMovingState->addTransition(obj: newAction, signal: &QAction::triggered, target: lettersFadingState);
190 lettersFadingState->addTransition(obj: lettersFadingState, signal: &QAnimationState::animationFinished, target: gameState);
191
192 //New Game is triggered then player start playing
193 gameState->addTransition(obj: newAction, signal: &QAction::triggered, target: gameState);
194
195 //Wanna quit, then connect to CTRL+Q
196 gameState->addTransition(obj: quitAction, signal: &QAction::triggered, target: finalState);
197 lettersMovingState->addTransition(obj: quitAction, signal: &QAction::triggered, target: finalState);
198
199 //Welcome screen is the initial state
200 machine->setInitialState(lettersMovingState);
201
202 machine->start();
203
204 //We reach the final state, then we quit
205 connect(sender: machine, signal: &QStateMachine::finished, qApp, slot: &QApplication::quit);
206}
207
208void GraphicsScene::addItem(Bomb *bomb)
209{
210 bombs.insert(value: bomb);
211 connect(sender: bomb, signal: &Bomb::bombExecutionFinished,
212 receiver: this, slot: &GraphicsScene::onBombExecutionFinished);
213 QGraphicsScene::addItem(item: bomb);
214}
215
216void GraphicsScene::addItem(Torpedo *torpedo)
217{
218 torpedos.insert(value: torpedo);
219 connect(sender: torpedo, signal: &Torpedo::torpedoExecutionFinished,
220 receiver: this, slot: &GraphicsScene::onTorpedoExecutionFinished);
221 QGraphicsScene::addItem(item: torpedo);
222}
223
224void GraphicsScene::addItem(SubMarine *submarine)
225{
226 submarines.insert(value: submarine);
227 connect(sender: submarine, signal: &SubMarine::subMarineExecutionFinished,
228 receiver: this, slot: &GraphicsScene::onSubMarineExecutionFinished);
229 QGraphicsScene::addItem(item: submarine);
230}
231
232void GraphicsScene::addItem(QGraphicsItem *item)
233{
234 QGraphicsScene::addItem(item);
235}
236
237void GraphicsScene::onBombExecutionFinished()
238{
239 Bomb *bomb = qobject_cast<Bomb *>(object: sender());
240 if (!bomb)
241 return;
242 bombs.remove(value: bomb);
243 bomb->deleteLater();
244 boat->setBombsLaunched(boat->bombsLaunched() - 1);
245}
246
247void GraphicsScene::onTorpedoExecutionFinished()
248{
249 Torpedo *torpedo = qobject_cast<Torpedo *>(object: sender());
250 if (!torpedo)
251 return;
252 torpedos.remove(value: torpedo);
253 torpedo->deleteLater();
254}
255
256void GraphicsScene::onSubMarineExecutionFinished()
257{
258 SubMarine *submarine = qobject_cast<SubMarine *>(object: sender());
259 if (!submarine)
260 return;
261 submarines.remove(value: submarine);
262 if (submarines.count() == 0)
263 emit allSubMarineDestroyed(submarine->points());
264 else
265 emit subMarineDestroyed(submarine->points());
266 submarine->deleteLater();
267}
268
269void GraphicsScene::clearScene()
270{
271 for (SubMarine *sub : qAsConst(t&: submarines)) {
272 // make sure to not go into onSubMarineExecutionFinished
273 sub->disconnect(receiver: this);
274 sub->destroy();
275 sub->deleteLater();
276 }
277
278 for (Torpedo *torpedo : qAsConst(t&: torpedos)) {
279 // make sure to not go into onTorpedoExecutionFinished
280 torpedo->disconnect(receiver: this);
281 torpedo->destroy();
282 torpedo->deleteLater();
283 }
284
285 for (Bomb *bomb : qAsConst(t&: bombs)) {
286 // make sure to not go into onBombExecutionFinished
287 bomb->disconnect(receiver: this);
288 bomb->destroy();
289 bomb->deleteLater();
290 }
291
292 submarines.clear();
293 bombs.clear();
294 torpedos.clear();
295
296 AnimationManager::self()->unregisterAllAnimations();
297
298 boat->stop();
299 boat->hide();
300 boat->setEnabled(true);
301}
302

source code of qtbase/examples/widgets/animation/sub-attaq/graphicsscene.cpp