summaryrefslogtreecommitdiffstats
path: root/pacman-c++/client/mainwidget.cpp
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2011-05-05 00:57:07 +0200
committermanuel <manuel@mausz.at>2011-05-05 00:57:07 +0200
commitce48af53646cd9e7ec762fc1ac176b3aa620b11d (patch)
treef8fbf2cae8c7d0cbac2696a8f4cf94410bfb4928 /pacman-c++/client/mainwidget.cpp
parente54ccad07e256ba877bd41d70bd358bd0085bd1e (diff)
downloadfoop-ce48af53646cd9e7ec762fc1ac176b3aa620b11d.tar.gz
foop-ce48af53646cd9e7ec762fc1ac176b3aa620b11d.tar.bz2
foop-ce48af53646cd9e7ec762fc1ac176b3aa620b11d.zip
- refactorized the whole project and made a few subprojects
- replaced tcp with enet - added connect dialog - some smaller bugfixes
Diffstat (limited to 'pacman-c++/client/mainwidget.cpp')
-rw-r--r--pacman-c++/client/mainwidget.cpp390
1 files changed, 390 insertions, 0 deletions
diff --git a/pacman-c++/client/mainwidget.cpp b/pacman-c++/client/mainwidget.cpp
new file mode 100644
index 0000000..f6f088b
--- /dev/null
+++ b/pacman-c++/client/mainwidget.cpp
@@ -0,0 +1,390 @@
1#include "mainwidget.h"
2#include "actor.h"
3#include "block.h"
4#include "constants.h"
5#include "util.h"
6#include "pacman.pb.h"
7#include <QStringBuilder>
8
9MainWidget::MainWidget(QWidget *parent)
10 : QWidget(parent), m_currentKey(Transmission::none), m_running(false),
11 m_host(NULL), m_peer(NULL), m_scene(NULL), m_maxplayers(0)
12{
13 m_host = enet_host_create(NULL, 1, 1, 0, 0);
14 if (m_host == NULL)
15 {
16 QMessageBox::critical(this, "Error", "An error occurred while trying to create an ENet client host");
17 qCritical() << "An error occurred while trying to create an ENet client host";
18 return;
19 }
20
21 /* create audio player */
22 m_ambientPlayer = new GaplessAudioPlayer(Sound::Ambient, 100, this);
23
24 m_recvTimer = new QTimer(this);
25 m_recvTimer->setInterval(Constants::tick / 2);
26 connect(m_recvTimer, SIGNAL(timeout()), this, SLOT(tick()));
27}
28
29MainWidget::~MainWidget()
30{
31 doDisconnect();
32 if (m_host != NULL)
33 {
34 enet_host_destroy(m_host);
35 m_host = NULL;
36 }
37}
38
39void MainWidget::doConnect(QString srv, unsigned int port)
40{
41 Color::Color color = connectToServer(srv, port);
42 if (color == Color::none)
43 {
44 QMessageBox::critical(this, "Error", "Failed to connect to server");
45 return;
46 }
47
48 /* create our scene */
49 m_scene = new SceneHolder(this);
50 m_scene->setColor(color);
51 m_scene->showWaitingForPlayers(true);
52 createGui();
53
54 m_recvTimer->start();
55 emit connected(true);
56 qDebug() << "[Connect] mycolor=" << m_scene->color();
57}
58
59void MainWidget::deleteLayout(QLayout *layout)
60{
61 if (layout == NULL)
62 return;
63
64 foreach(QObject *obj, layout->children())
65 {
66 QLayout *inLayout = qobject_cast<QLayout*>(obj);
67 deleteLayout(inLayout);
68 }
69
70 QLayoutItem *child;
71 while ((child = layout->takeAt(0)) != NULL)
72 {
73 child->widget()->deleteLater();
74 delete child;
75 }
76
77 delete layout;
78}
79
80void MainWidget::doDisconnect()
81{
82 stopGame();
83 m_recvTimer->stop();
84 closeENetPeer();
85 deleteLayout(layout());
86 m_playerScoreLayouts.clear();
87 emit connected(false);
88}
89
90bool MainWidget::connected()
91{
92 return m_peer != NULL;
93}
94
95void MainWidget::createGui()
96{
97 setFocusPolicy(Qt::StrongFocus);
98
99 /* first one is always the own score */
100 QVBoxLayout *layout = new QVBoxLayout(this);
101 layout->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
102 QHBoxLayout *scoreLayout = new QHBoxLayout();
103 for (unsigned int i = 0; i < m_maxplayers; ++i)
104 {
105 QGridLayout *playerLayout = new QGridLayout();
106 playerLayout->addWidget(new QLabel("Current:", this), 0, 0);
107 playerLayout->addWidget(new QLabel("Total:", this), 1, 0);
108 playerLayout->addWidget(new QLabel("0", this), 0, 1, Qt::AlignLeft);
109 playerLayout->addWidget(new QLabel("0", this), 1, 1, Qt::AlignLeft);
110 playerLayout->setColumnStretch(1, 10);
111 playerLayout->setSizeConstraint(QLayout::SetMinimumSize);
112
113 QGroupBox *scoreBox = new QGroupBox(QString("Player %1").arg(i + 1), this);
114 scoreBox->setObjectName(QString("actor%1").arg(i + 1));
115 scoreBox->setCheckable(true);
116 scoreBox->setDisabled(i >= m_maxplayers);
117 connect(scoreBox, SIGNAL(clicked()), this, SLOT(playerScoreClicked()));
118
119 scoreBox->setLayout(playerLayout);
120 m_playerScoreLayouts.append(playerLayout);
121
122 if (Color::order[i] == m_scene->color())
123 scoreLayout->insertWidget(0, scoreBox);
124 else
125 scoreLayout->addWidget(scoreBox);
126 }
127 layout->addLayout(scoreLayout);
128
129 QGraphicsView *window = new QGraphicsView(m_scene, this);
130 window->setFrameStyle(0);
131 window->setFixedSize(m_scene->sceneRect().size().toSize());
132 window->setWindowFlags(window->windowFlags() & ~Qt::WindowMaximizeButtonHint);
133 window->setFocusPolicy(Qt::NoFocus);
134 layout->addWidget(window, 0, Qt::AlignCenter);
135
136 QFile css(":/stylesheet");
137 css.open(QFile::ReadOnly);
138 qApp->setStyleSheet(QLatin1String(css.readAll()));
139
140 /* add dummy layout at the end which gets streched when resizing */
141 QHBoxLayout *spacer = new QHBoxLayout();
142 layout->addLayout(spacer, 10);
143
144 setLayout(layout);
145}
146
147void MainWidget::updateScore(const ProtoBuf::MapUpdate& packet)
148{
149 for(unsigned i = 0; i < m_maxplayers; ++i)
150 {
151 QGridLayout *score = m_playerScoreLayouts.at(i);
152 QLabel *turnPointsLbl = dynamic_cast<QLabel *>(score->itemAtPosition(0, 1)->widget());
153 turnPointsLbl->setText(QString::number(packet.round_points(i)));
154
155 QLabel *allPointsLbl = dynamic_cast<QLabel *>(score->itemAtPosition(1, 1)->widget());
156 allPointsLbl->setText(QString::number(packet.game_points(i)));
157 }
158}
159
160Transmission::field_t MainWidget::translateKey(int key)
161{
162 switch(key)
163 {
164 case Qt::Key_W:
165 case Qt::Key_Up:
166 return Transmission::direction_up;
167 break;
168 case Qt::Key_S:
169 case Qt::Key_Down:
170 return Transmission::direction_down;
171 break;
172 case Qt::Key_A:
173 case Qt::Key_Left:
174 return Transmission::direction_left;
175 break;
176 case Qt::Key_D:
177 case Qt::Key_Right:
178 return Transmission::direction_right;
179 break;
180 default:
181 return Transmission::direction_none;
182 }
183}
184
185void MainWidget::tick()
186{
187 ENetEvent event;
188 while (enet_host_service(m_host, &event, 1) > 0)
189 {
190 switch (event.type)
191 {
192 case ENET_EVENT_TYPE_DISCONNECT:
193 m_peer = NULL;
194 doDisconnect();
195 break;
196 case ENET_EVENT_TYPE_RECEIVE:
197 tick(&event);
198 enet_packet_destroy(event.packet);
199 break;
200 default:
201 break;
202 }
203 }
204}
205
206void MainWidget::tick(ENetEvent *event)
207{
208 QSharedPointer<QByteArray> data = Util::receivePacket(event->packet);
209 bool worked = m_updatepacket.ParseFromArray(data->data(), data->size());
210 Q_ASSERT(worked);
211 Q_UNUSED(worked);
212
213 /* eating order data set indicates a new round */
214 if (m_updatepacket.eating_order_size() > 0)
215 {
216 Q_ASSERT(m_scene != NULL);
217 m_scene->reset();
218
219 /* fetch eating order */
220 QList<Color::Color> order;
221 for(int i = 0; i < m_updatepacket.eating_order_size(); ++i)
222 order.append(static_cast<Color::Color>(m_updatepacket.eating_order(i) & Transmission::color_mask));
223 m_scene->setEatingOrder(order);
224
225 /* stop game */
226 stopGame();
227
228 /* and restart game */
229 QTimer *timer = new QTimer(this);
230 timer->setSingleShot(true);
231 timer->setInterval(Sound::length[Sound::Intro] + Constants::tick);
232 connect(timer, SIGNAL(timeout()), this, SLOT(startGame()));
233 timer->start();
234 AudioManager::self()->play(Sound::Intro, true);
235 }
236
237 Transmission::map_t map = Util::createUninitialisedMap();
238 Q_ASSERT(m_updatepacket.field_size() == (int) (Constants::map_size.width * Constants::map_size.height));
239 int i = 0;
240 for (unsigned int x = 0; x < Constants::map_size.width; ++x)
241 {
242 for (unsigned int y = 0; y < Constants::map_size.height; ++y)
243 {
244 map[x][y] = m_updatepacket.field(i);
245 ++i;
246 }
247 }
248 m_scene->updateMap(map);
249 Util::deleteMap(map);
250 updateScore(m_updatepacket);
251
252 if (m_updatepacket.eating_order_size() > 0)
253 {
254 m_scene->showWaitingForPlayers(false);
255 m_scene->showEatingText();
256 }
257}
258
259void MainWidget::keyPressEvent(QKeyEvent* event)
260{
261 if (event->isAutoRepeat())
262 return;
263
264 QWidget::keyPressEvent(event);
265 Transmission::field_t newKey = translateKey(event->key());
266 if (newKey == Transmission::direction_none)
267 return;
268 bool sendUpdate = (m_currentKey != newKey);
269 m_currentKey = newKey;
270 if (sendUpdate)
271 sendKeyUpdate();
272}
273
274void MainWidget::sendKeyUpdate()
275{
276 if (m_currentKey == Transmission::direction_none)
277 return;
278 qDebug() << "[SendKey] key=" << m_currentKey;
279 ProtoBuf::KeyPressUpdate packet;
280 packet.set_newkey(m_currentKey);
281 Util::sendPacket(packet, m_peer, m_host);
282}
283
284void MainWidget::keyReleaseEvent(QKeyEvent* event)
285{
286 if (event->isAutoRepeat())
287 return;
288
289 QWidget::keyReleaseEvent(event);
290 m_currentKey = Transmission::none;
291 return;
292}
293
294void MainWidget::startGame()
295{
296 disconnect(AudioManager::self()->audioPlayer(), NULL, this, SLOT(startGame()));
297 m_scene->showEatingText(false);
298 m_running = true;
299 sendKeyUpdate();
300 m_ambientPlayer->play();
301}
302
303void MainWidget::stopGame()
304{
305 m_running = false;
306 m_ambientPlayer->pause();
307}
308
309void MainWidget::setAmbientMuted(bool muted)
310{
311 m_ambientPlayer->setMuted(muted);
312}
313
314void MainWidget::playerScoreClicked()
315{
316 QGroupBox *tmp = qobject_cast<QGroupBox *>(sender());
317 tmp->setChecked(true);
318 return;
319}
320
321Color::Color MainWidget::connectToServer(QString srv, unsigned int port)
322{
323 qDebug() << "[Connect] server=" << srv << "port=" << port;
324
325 /* connect to server */
326 closeENetPeer();
327 ENetAddress address;
328 enet_address_set_host(&address, qPrintable(srv));
329 address.port = Constants::Networking::port;
330 m_peer = enet_host_connect(m_host, &address, 1, 0);
331 if (m_peer == NULL)
332 {
333 qCritical() << "No available peers for initiating an ENet connection";
334 return Color::none;
335 }
336
337 ENetEvent event;
338 bool worked = (enet_host_service(m_host, &event, Constants::Networking::connection_timeout) > 0
339 && event.type == ENET_EVENT_TYPE_CONNECT);
340 if (worked)
341 {
342 /* additional init: first packet is our color */
343 worked = (enet_host_service(m_host, &event, Constants::Networking::packet_timeout) > 0
344 && event.type == ENET_EVENT_TYPE_RECEIVE);
345 if (worked)
346 {
347 /* receive color */
348 QSharedPointer<QByteArray> data = Util::receivePacket(event.packet);
349 enet_packet_destroy(event.packet);
350 ProtoBuf::Init packet;
351 worked = packet.ParseFromArray(data->data(), data->size());
352 Q_ASSERT(worked);
353 Q_UNUSED(worked);
354 m_maxplayers = packet.maxplayers();
355 return static_cast<Color::Color>(packet.color() & Transmission::color_mask);
356 }
357 }
358 enet_peer_reset(m_peer);
359 m_peer = NULL;
360 return Color::none;
361}
362
363void MainWidget::closeENetPeer()
364{
365 if (m_peer != NULL && m_peer->state != ENET_PEER_STATE_DISCONNECTED)
366 {
367 /* allow up to 3 seconds for the disconnect to succeed
368 * and drop any packets received packets
369 */
370 enet_peer_disconnect(m_peer, 0);
371 ENetEvent event;
372 while (enet_host_service(m_host, &event, 3000) > 0)
373 {
374 switch (event.type)
375 {
376 case ENET_EVENT_TYPE_RECEIVE:
377 enet_packet_destroy(event.packet);
378 break;
379 case ENET_EVENT_TYPE_DISCONNECT:
380 m_peer = NULL;
381 return;
382 default:
383 break;
384 }
385 }
386
387 enet_peer_reset(m_peer);
388 }
389 m_peer = NULL;
390}