scene.h 6.46 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*******************************************************************
 *
 * Copyright 2006 Dmitry Suzdalev <dimsuz@gmail.com>
 *
 * This file is part of the KDE project "KLines"
 *
 * KLines is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * KLines is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
18
 * along with KLines; see the file COPYING.  If not, write to
19
20
21
22
23
24
25
26
27
 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 ********************************************************************/
#ifndef KL_SCENE_H
#define KL_SCENE_H

#include <QGraphicsScene>
#include <QGraphicsView>
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
28
29
#include <KRandomSequence>

30
31
32
33
#include "commondefs.h"

static const int FIELD_SIZE=9;

Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
34
class KLinesAnimator;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
35
class BallItem;
36
class QGraphicsRectItem;
37

38
39
40
/**
 *  Displays and drives the game
 */
41
42
class KLinesScene : public QGraphicsScene
{
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
43
    Q_OBJECT
44
public:
45
    explicit KLinesScene( QObject *parent );
46
    ~KLinesScene();
47
48
49
    /**
     *  Resizes scene
     */
50
    void resizeScene( int width, int height );
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
51
52
53
54
    /**
     *  Brings in next three balls to scene
     */
    void nextThreeBalls();
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
55
56
57
58
59
60
61
62
    /**
     *  This score points will be added as an additional bonus to
     *  every score resulted from ball erasing event.
     *  For example 1 score point is added if the game is played with
     *  hidden preview widget.
     *  By default no bonus is added.
     */
    void setBonusScorePoints( int points ) { m_bonusScore = points; }
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
63
64
65
66
    /**
     *  Returns colors of the 3 balls in the next turn
     */
    QList<BallColor> nextColors() const { return m_nextColors; }
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
67
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
68
69
     *  Returns ballitem in field position pos or 0 if there
     *  is no item there
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
70
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
71
    BallItem* ballAt( const FieldPos& pos ) { return m_field[pos.x][pos.y]; }
72
73
74
75
    /**
     * Overloaded above function
     */
    BallItem* ballAt( int x, int y ) { return m_field[x][y]; }
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
76
77
78
    /**
     *  Field coords to pixel coords
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
79
80
81
82
    inline QPointF fieldToPix(const FieldPos& fpos) const
    {
        return QPointF( m_playFieldOrigin.x()+fpos.x*m_cellSize + m_cellSize * 0.05 ,
                        m_playFieldOrigin.y()+fpos.y*m_cellSize + m_cellSize * 0.05 );
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
83
    }
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
84
85
86
    /**
     *  Pixel coords to field coords
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
87
88
89
90
91
    inline FieldPos pixToField( const QPointF& p ) const
    {
        return FieldPos(static_cast<int>(( p.x()-m_playFieldOrigin.x() )/m_cellSize),
                        static_cast<int>(( p.y()-m_playFieldOrigin.y() )/m_cellSize));
    }
92
public slots:
93
94
95
96
    /**
     *  Starts new game
     */
    void startNewGame();
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
97
98
99
100
101
102
103
104
    /**
     *  Ends current and starts next turn explicitly
     */
    void endTurn();
    /**
     *  Undoes one move
     */
    void undo();
105
    /**
106
     *  Moves keyboard-playing focus rect to the left
107
108
109
     */
    void moveFocusLeft();
    /**
110
     *  Moves keyboard-playing focus rect to the right
111
112
113
     */
    void moveFocusRight();
    /**
114
     *  Moves keyboard-playing focus rect to the up
115
116
117
     */
    void moveFocusUp();
    /**
118
     *  Moves keyboard-playing focus rect to the down
119
120
121
122
123
124
     */
    void moveFocusDown();
    /**
     *  Takes corresponding action on cell under focus rect
     */
    void cellSelected();
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
125
126
signals:
    void scoreChanged(int);
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
127
    void enableUndo(bool);
128
    void nextColorsChanged();
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
129
    void gameOver(int);
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
130
131
private slots:
    void moveAnimFinished();
132
133
    void removeAnimFinished();
    void bornAnimFinished();
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
134
135
private:
    /**
136
137
     *  Creates a ball and places it in random free cell
     *  @param c color of the ball
138
     *  @return ball placed
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
139
     */
140
    BallItem* randomlyPlaceBall(BallColor c);
141
142
143
    /**
     *  Searches for 5 or more balls in a row and deletes them from field
     */
144
    bool searchAndErase();
145
    /**
Mauricio Piacentini's avatar
Mauricio Piacentini committed
146
     *  This function takes one of two actions:
147
     *  If there's a ball at fpos, it will be selected.
148
     *  Otherwise if the cell at fpos is empty and there's
149
150
151
152
     *  a selected ball in some other cell it will be moved to fpos
     *  (if the move is possible, of course)
     */
    void selectOrMove( const FieldPos& fpos );
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
153
154
155
156
    /**
     *  Saves game state information to be used during undo
     */
    void saveUndoInfo();
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
157

158
    virtual void drawBackground( QPainter*, const QRectF& );
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
159
    virtual void mousePressEvent( QGraphicsSceneMouseEvent* );
160

Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
161
162
163
164
165
166
    /**
     *  This array represents the play field.
     *  Each cell holds the pointer to BallItem
     *  or 0 if there's no ball in that cell
     */
    BallItem* m_field[FIELD_SIZE][FIELD_SIZE];
167
168
169
170
    /**
     *  Used to start game animations
     *  This object knows how to do some ball animations
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
171
    KLinesAnimator* m_animator;
172
173
174
    /**
     * We need random numbers in this game
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
175
    KRandomSequence m_randomSeq;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
176
177
178
179
    /**
     * Origin of playfield
     */
    QPoint m_playFieldOrigin;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
180
    /**
181
     *  Position of selected ball (-1,-1) if none
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
182
     */
183
    FieldPos m_selPos;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
184
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
185
186
187
188
189
     *  Number of free cells in the field
     */
    int m_numFreeCells;
    /**
     *  Current game score
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
190
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
191
    int m_score;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
192
193
194
195
196
    /**
     *  Bonus points added to score upon ball erasing
     *  @see setBonusScorePoints()
     */
    int m_bonusScore;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
197
198
199
200
    /**
     *  Cell size in pixels
     */
    int m_cellSize;
201
202
203
204
    /**
     *  Varable which is needed for little trick (tm).
     *  Read more about it in removeAnimFinished() slot
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
205
    bool m_placeBalls;
206
207
208
209
    /**
     *  Items pending for removal after remove-anim finishes
     */
    QList<BallItem*> m_itemsToDelete;
210
211
212
213
    /**
     *  Colors of the next turn's balls
     */
    QList<BallColor> m_nextColors;
214
215
216
217
    /**
     *  Keyboard-playing focus indication
     */
    QGraphicsRectItem *m_focusItem;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233

    /**
     *  Struct for holding game state - used on undos
     */
    struct UndoInfo
    {
        int numFreeCells;
        int score;
        QList<BallColor> nextColors;
        BallColor fcolors[FIELD_SIZE][FIELD_SIZE];
    };
    /**
     *  Holds game state for undo.
     *  It is saved before every new turn
     */
    UndoInfo m_undoInfo;
234
235
236
237
238
239
240
241
242
243
244
};

class KLinesView : public QGraphicsView
{
public:
    KLinesView( KLinesScene* scene, QWidget *parent );
private:
    void resizeEvent(QResizeEvent *);
};

#endif