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 documentation 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 | #include <QtWidgets> |
52 | |
53 | #include "window.h" |
54 | #include "movementtransition.h" |
55 | |
56 | //![0] |
57 | Window::Window() |
58 | { |
59 | pX = 5; |
60 | pY = 5; |
61 | //![0] |
62 | |
63 | QFontDatabase database; |
64 | QFont font; |
65 | if (database.families().contains(str: "Monospace" )) { |
66 | font = QFont("Monospace" ); |
67 | } |
68 | else { |
69 | const QStringList fontFamilies = database.families(); |
70 | for (const QString &family : fontFamilies ) { |
71 | if (database.isFixedPitch(family)) { |
72 | font = QFont(family); |
73 | break; |
74 | } |
75 | } |
76 | } |
77 | font.setPointSize(12); |
78 | setFont(font); |
79 | |
80 | //![1] |
81 | setupMap(); |
82 | buildMachine(); |
83 | } |
84 | //![1] |
85 | |
86 | void Window::setStatus(const QString &status) |
87 | { |
88 | myStatus = status; |
89 | repaint(); |
90 | } |
91 | |
92 | QString Window::status() const |
93 | { |
94 | return myStatus; |
95 | } |
96 | |
97 | void Window::paintEvent(QPaintEvent * /* event */) |
98 | { |
99 | QFontMetrics metrics(font()); |
100 | QPainter painter(this); |
101 | int fontHeight = metrics.height(); |
102 | int fontWidth = metrics.horizontalAdvance('X'); |
103 | int yPos = fontHeight; |
104 | int xPos; |
105 | |
106 | painter.fillRect(r: rect(), c: Qt::black); |
107 | painter.setPen(Qt::white); |
108 | |
109 | painter.drawText(p: QPoint(0, yPos), s: status()); |
110 | |
111 | for (int y = 0; y < HEIGHT; ++y) { |
112 | yPos += fontHeight; |
113 | xPos = 0; |
114 | |
115 | for (int x = 0; x < WIDTH; ++x) { |
116 | if (y == pY && x == pX) { |
117 | xPos += fontWidth; |
118 | continue; |
119 | } |
120 | |
121 | painter.setPen(Qt::white); |
122 | |
123 | double x1 = static_cast<double>(pX); |
124 | double y1 = static_cast<double>(pY); |
125 | double x2 = static_cast<double>(x); |
126 | double y2 = static_cast<double>(y); |
127 | |
128 | if (x2<x1) { |
129 | x2+=0.5; |
130 | } else if (x2>x1) { |
131 | x2-=0.5; |
132 | } |
133 | |
134 | if (y2<y1) { |
135 | y2+=0.5; |
136 | } else if (y2>y1) { |
137 | y2-=0.5; |
138 | } |
139 | |
140 | double dx = x2 - x1; |
141 | double dy = y2 - y1; |
142 | |
143 | double length = qSqrt(v: dx*dx+dy*dy); |
144 | |
145 | dx /= length; |
146 | dy /= length; |
147 | |
148 | double xi = x1; |
149 | double yi = y1; |
150 | |
151 | while (length > 0) { |
152 | int cx = static_cast<int>(xi+0.5); |
153 | int cy = static_cast<int>(yi+0.5); |
154 | |
155 | if (x2 == cx && y2 == cy) |
156 | break; |
157 | |
158 | if (!(x1==cx && y1==cy) |
159 | && (map[cx][cy] == '#' || (length-10) > 0)) { |
160 | painter.setPen(QColor(60,60,60)); |
161 | break; |
162 | } |
163 | |
164 | xi += dx; |
165 | yi += dy; |
166 | --length; |
167 | } |
168 | |
169 | painter.drawText(p: QPoint(xPos, yPos), s: map[x][y]); |
170 | xPos += fontWidth; |
171 | } |
172 | } |
173 | painter.setPen(Qt::white); |
174 | painter.drawText(p: QPoint(pX * fontWidth, (pY + 2) * fontHeight), s: QChar('@')); |
175 | } |
176 | |
177 | QSize Window::sizeHint() const |
178 | { |
179 | QFontMetrics metrics(font()); |
180 | |
181 | return QSize(metrics.horizontalAdvance('X') * WIDTH, metrics.height() * (HEIGHT + 1)); |
182 | } |
183 | |
184 | //![2] |
185 | void Window::buildMachine() |
186 | { |
187 | machine = new QStateMachine; |
188 | |
189 | QState *inputState = new QState(machine); |
190 | inputState->assignProperty(object: this, name: "status" , value: "Move the rogue with 2, 4, 6, and 8" ); |
191 | |
192 | MovementTransition *transition = new MovementTransition(this); |
193 | inputState->addTransition(transition); |
194 | //![2] |
195 | |
196 | //![3] |
197 | QState *quitState = new QState(machine); |
198 | quitState->assignProperty(object: this, name: "status" , value: "Really quit(y/n)?" ); |
199 | |
200 | QKeyEventTransition *yesTransition = new |
201 | QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Y); |
202 | yesTransition->setTargetState(new QFinalState(machine)); |
203 | quitState->addTransition(transition: yesTransition); |
204 | |
205 | QKeyEventTransition *noTransition = |
206 | new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_N); |
207 | noTransition->setTargetState(inputState); |
208 | quitState->addTransition(transition: noTransition); |
209 | //![3] |
210 | |
211 | //![4] |
212 | QKeyEventTransition *quitTransition = |
213 | new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Q); |
214 | quitTransition->setTargetState(quitState); |
215 | inputState->addTransition(transition: quitTransition); |
216 | //![4] |
217 | |
218 | //![5] |
219 | machine->setInitialState(inputState); |
220 | |
221 | connect(sender: machine, signal: &QStateMachine::finished, |
222 | qApp, slot: &QApplication::quit); |
223 | |
224 | machine->start(); |
225 | } |
226 | //![5] |
227 | |
228 | void Window::movePlayer(Direction direction) |
229 | { |
230 | switch (direction) { |
231 | case Left: |
232 | if (map[pX - 1][pY] != '#') |
233 | --pX; |
234 | break; |
235 | case Right: |
236 | if (map[pX + 1][pY] != '#') |
237 | ++pX; |
238 | break; |
239 | case Up: |
240 | if (map[pX][pY - 1] != '#') |
241 | --pY; |
242 | break; |
243 | case Down: |
244 | if (map[pX][pY + 1] != '#') |
245 | ++pY; |
246 | break; |
247 | } |
248 | repaint(); |
249 | } |
250 | |
251 | void Window::setupMap() |
252 | { |
253 | for (int x = 0; x < WIDTH; ++x) |
254 | for (int y = 0; y < HEIGHT; ++y) { |
255 | if (x == 0 || x == WIDTH - 1 || y == 0 || y == HEIGHT - 1 || QRandomGenerator::global()->bounded(highest: 40) == 0) |
256 | map[x][y] = '#'; |
257 | else |
258 | map[x][y] = '.'; |
259 | } |
260 | } |
261 | |
262 | |