1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 //Own
43 #include "boat.h"
44 #include "boat_p.h"
45 #include "bomb.h"
46 #include "pixmapitem.h"
47 #include "graphicsscene.h"
48 #include "animationmanager.h"
49 #include "qanimationstate.h"
50 
51 //Qt
52 #include <QtCore/QPropertyAnimation>
53 #include <QtCore/QStateMachine>
54 #include <QtCore/QHistoryState>
55 #include <QtCore/QFinalState>
56 #include <QtCore/QState>
57 #include <QtCore/QSequentialAnimationGroup>
58 
setupDestroyAnimation(Boat * boat)59 static QAbstractAnimation *setupDestroyAnimation(Boat *boat)
60 {
61     QSequentialAnimationGroup *group = new QSequentialAnimationGroup(boat);
62     for (int i = 1; i <= 4; i++) {
63         PixmapItem *step = new PixmapItem(QString("explosion/boat/step%1").arg(i),GraphicsScene::Big, boat);
64         step->setZValue(6);
65         step->setOpacity(0);
66 
67         //fade-in
68         QPropertyAnimation *anim = new QPropertyAnimation(step, "opacity");
69         anim->setEndValue(1);
70         anim->setDuration(100);
71         group->insertAnimation(i-1, anim);
72 
73         //and then fade-out
74         QPropertyAnimation *anim2 = new QPropertyAnimation(step, "opacity");
75         anim2->setEndValue(0);
76         anim2->setDuration(100);
77         group->addAnimation(anim2);
78     }
79 
80     AnimationManager::self()->registerAnimation(group);
81     return group;
82 }
83 
84 
85 
Boat()86 Boat::Boat() : PixmapItem(QString("boat"), GraphicsScene::Big),
87     speed(0), bombsAlreadyLaunched(0), direction(Boat::None), movementAnimation(0)
88 {
89     setZValue(4);
90     setFlags(QGraphicsItem::ItemIsFocusable);
91 
92     //The movement animation used to animate the boat
93     movementAnimation = new QPropertyAnimation(this, "pos");
94 
95     //The destroy animation used to explode the boat
96     destroyAnimation = setupDestroyAnimation(this);
97 
98     //We setup the state machine of the boat
99     machine = new QStateMachine(this);
100     QState *moving = new QState(machine);
101     StopState *stopState = new StopState(this, moving);
102     machine->setInitialState(moving);
103     moving->setInitialState(stopState);
104     MoveStateRight *moveStateRight = new MoveStateRight(this, moving);
105     MoveStateLeft *moveStateLeft = new MoveStateLeft(this, moving);
106     LaunchStateRight *launchStateRight = new LaunchStateRight(this, machine);
107     LaunchStateLeft *launchStateLeft = new LaunchStateLeft(this, machine);
108 
109     //then setup the transitions for the rightMove state
110     KeyStopTransition *leftStopRight = new KeyStopTransition(this, QEvent::KeyPress, Qt::Key_Left);
111     leftStopRight->setTargetState(stopState);
112     KeyMoveTransition *leftMoveRight = new KeyMoveTransition(this, QEvent::KeyPress, Qt::Key_Left);
113     leftMoveRight->setTargetState(moveStateRight);
114     KeyMoveTransition *rightMoveRight = new KeyMoveTransition(this, QEvent::KeyPress, Qt::Key_Right);
115     rightMoveRight->setTargetState(moveStateRight);
116     KeyMoveTransition *rightMoveStop = new KeyMoveTransition(this, QEvent::KeyPress, Qt::Key_Right);
117     rightMoveStop->setTargetState(moveStateRight);
118 
119     //then setup the transitions for the leftMove state
120     KeyStopTransition *rightStopLeft = new KeyStopTransition(this, QEvent::KeyPress, Qt::Key_Right);
121     rightStopLeft->setTargetState(stopState);
122     KeyMoveTransition *rightMoveLeft = new KeyMoveTransition(this, QEvent::KeyPress, Qt::Key_Right);
123     rightMoveLeft->setTargetState(moveStateLeft);
124     KeyMoveTransition *leftMoveLeft = new KeyMoveTransition(this, QEvent::KeyPress,Qt::Key_Left);
125     leftMoveLeft->setTargetState(moveStateLeft);
126     KeyMoveTransition *leftMoveStop = new KeyMoveTransition(this, QEvent::KeyPress,Qt::Key_Left);
127     leftMoveStop->setTargetState(moveStateLeft);
128 
129     //We set up the right move state
130     moveStateRight->addTransition(leftStopRight);
131     moveStateRight->addTransition(leftMoveRight);
132     moveStateRight->addTransition(rightMoveRight);
133     stopState->addTransition(rightMoveStop);
134 
135     //We set up the left move state
136     moveStateLeft->addTransition(rightStopLeft);
137     moveStateLeft->addTransition(leftMoveLeft);
138     moveStateLeft->addTransition(rightMoveLeft);
139     stopState->addTransition(leftMoveStop);
140 
141     //The animation is finished, it means we reached the border of the screen, the boat is stopped so we move to the stop state
142     moveStateLeft->addTransition(movementAnimation, SIGNAL(finished()), stopState);
143     moveStateRight->addTransition(movementAnimation, SIGNAL(finished()), stopState);
144 
145     //We set up the keys for dropping bombs
146     KeyLaunchTransition *upFireLeft = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Up);
147     upFireLeft->setTargetState(launchStateRight);
148     KeyLaunchTransition *upFireRight = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Up);
149     upFireRight->setTargetState(launchStateRight);
150     KeyLaunchTransition *upFireStop = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Up);
151     upFireStop->setTargetState(launchStateRight);
152     KeyLaunchTransition *downFireLeft = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Down);
153     downFireLeft->setTargetState(launchStateLeft);
154     KeyLaunchTransition *downFireRight = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Down);
155     downFireRight->setTargetState(launchStateLeft);
156     KeyLaunchTransition *downFireMove = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Down);
157     downFireMove->setTargetState(launchStateLeft);
158 
159     //We set up transitions for fire up
160     moveStateRight->addTransition(upFireRight);
161     moveStateLeft->addTransition(upFireLeft);
162     stopState->addTransition(upFireStop);
163 
164     //We set up transitions for fire down
165     moveStateRight->addTransition(downFireRight);
166     moveStateLeft->addTransition(downFireLeft);
167     stopState->addTransition(downFireMove);
168 
169     //Finally the launch state should come back to its original state
170     QHistoryState *historyState = new QHistoryState(moving);
171     launchStateLeft->addTransition(historyState);
172     launchStateRight->addTransition(historyState);
173 
174     QFinalState *final = new QFinalState(machine);
175 
176     //This state play the destroyed animation
177     QAnimationState *destroyedState = new QAnimationState(machine);
178     destroyedState->setAnimation(destroyAnimation);
179 
180     //Play a nice animation when the boat is destroyed
181     moving->addTransition(this, SIGNAL(boatDestroyed()), destroyedState);
182 
183     //Transition to final state when the destroyed animation is finished
184     destroyedState->addTransition(destroyedState, SIGNAL(animationFinished()), final);
185 
186     //The machine has finished to be executed, then the boat is dead
187     connect(machine,SIGNAL(finished()), this, SIGNAL(boatExecutionFinished()));
188 
189 }
190 
run()191 void Boat::run()
192 {
193     //We register animations
194     AnimationManager::self()->registerAnimation(movementAnimation);
195     AnimationManager::self()->registerAnimation(destroyAnimation);
196     machine->start();
197 }
198 
stop()199 void Boat::stop()
200 {
201     movementAnimation->stop();
202     machine->stop();
203 }
204 
updateBoatMovement()205 void Boat::updateBoatMovement()
206 {
207     if (speed == 0 || direction == Boat::None) {
208         movementAnimation->stop();
209         return;
210     }
211 
212     movementAnimation->stop();
213 
214     if (direction == Boat::Left) {
215         movementAnimation->setEndValue(QPointF(0,y()));
216         movementAnimation->setDuration(x()/speed*15);
217     }
218     else /*if (direction == Boat::Right)*/ {
219         movementAnimation->setEndValue(QPointF(scene()->width()-size().width(),y()));
220         movementAnimation->setDuration((scene()->width()-size().width()-x())/speed*15);
221     }
222     movementAnimation->start();
223 }
224 
destroy()225 void Boat::destroy()
226 {
227     movementAnimation->stop();
228     emit boatDestroyed();
229 }
230 
bombsLaunched() const231 int Boat::bombsLaunched() const
232 {
233     return bombsAlreadyLaunched;
234 }
235 
setBombsLaunched(int number)236 void Boat::setBombsLaunched(int number)
237 {
238     if (number > MAX_BOMB) {
239         qWarning("Boat::setBombsLaunched : It impossible to launch that number of bombs");
240         return;
241     }
242     bombsAlreadyLaunched = number;
243 }
244 
currentSpeed() const245 int Boat::currentSpeed() const
246 {
247     return speed;
248 }
249 
setCurrentSpeed(int speed)250 void Boat::setCurrentSpeed(int speed)
251 {
252     if (speed > 3 || speed < 0) {
253         qWarning("Boat::setCurrentSpeed: The boat can't run on that speed");
254         return;
255     }
256     this->speed = speed;
257 }
258 
currentDirection() const259 enum Boat::Movement Boat::currentDirection() const
260 {
261     return direction;
262 }
263 
setCurrentDirection(Movement direction)264 void Boat::setCurrentDirection(Movement direction)
265 {
266     this->direction = direction;
267 }
268 
type() const269 int Boat::type() const
270 {
271     return Type;
272 }
273