From bbd2a69a962d15f74a4afcb7b66462eac9fa5008 Mon Sep 17 00:00:00 2001 From: manuel Date: Wed, 20 Apr 2011 02:19:08 +0200 Subject: game rounds finally implemented: - game rounds will be detected during the round AND - a new map will be send in the NEXT tick to the clients --- pacman-c++/actor.cpp | 11 ++++- pacman-c++/actor.h | 1 + pacman-c++/constants.h | 1 + pacman-c++/mainwidget.cpp | 4 +- pacman-c++/sceneholder.cpp | 37 +++++++++++------ pacman-c++/sceneholder.h | 3 +- pacman-c++/server.cpp | 100 +++++++++++++++++++++++++++------------------ pacman-c++/server.h | 10 +++-- 8 files changed, 109 insertions(+), 58 deletions(-) diff --git a/pacman-c++/actor.cpp b/pacman-c++/actor.cpp index cf3fc13..c8922f7 100644 --- a/pacman-c++/actor.cpp +++ b/pacman-c++/actor.cpp @@ -10,7 +10,7 @@ static QVariant myBooleanInterpolator(const bool &start, const bool &end, qreal } Actor::Actor(Color::Color color, bool local, QGraphicsItem *parent) - : GameEntity(color, parent),m_direction(Actor::None), m_local(local), + : GameEntity(color, parent), m_direction(Actor::None), m_local(local), m_wakaPlayer(NULL), m_roundPoints(0), m_gamePoints(0) { m_type = Type; @@ -112,6 +112,15 @@ bool Actor::isLocal() return m_local; } +void Actor::resetDirection() +{ + /* hide all pictures */ + for (int i = 0; i < m_images.size(); ++i) + m_images.at(i)->setVisible(false); + m_direction = Actor::None; + m_images[m_direction]->setVisible(true); +} + void Actor::move(Actor::Movement direction) { if (Constants::server) diff --git a/pacman-c++/actor.h b/pacman-c++/actor.h index 41ad232..389d7c6 100644 --- a/pacman-c++/actor.h +++ b/pacman-c++/actor.h @@ -34,6 +34,7 @@ public: PixmapItem &icon(); Movement direction(); + void resetDirection(); bool isLocal(); void move(Movement direction); bool isMoving(); diff --git a/pacman-c++/constants.h b/pacman-c++/constants.h index 20a0e15..f9f40f9 100644 --- a/pacman-c++/constants.h +++ b/pacman-c++/constants.h @@ -51,6 +51,7 @@ namespace Constants { const unsigned int weight_hunt = 10; const unsigned int weight_bonus_point = 3; const unsigned int weight_point = 1; + const unsigned int weight_colorblock = 5; } } diff --git a/pacman-c++/mainwidget.cpp b/pacman-c++/mainwidget.cpp index 82099c4..eb032bd 100644 --- a/pacman-c++/mainwidget.cpp +++ b/pacman-c++/mainwidget.cpp @@ -149,7 +149,9 @@ void MainWidget::tick() if (m_updatepacket.eating_order_size() > 0) { Q_ASSERT(m_scene != NULL); - m_scene->removeActors(); + m_scene->reset(); + + /* fetch eating order */ QList order; for(int i = 0; i < m_updatepacket.eating_order_size(); ++i) order.append(static_cast(m_updatepacket.eating_order(i) & Transmission::color_mask)); diff --git a/pacman-c++/sceneholder.cpp b/pacman-c++/sceneholder.cpp index 1610b7e..56e0fff 100644 --- a/pacman-c++/sceneholder.cpp +++ b/pacman-c++/sceneholder.cpp @@ -18,6 +18,13 @@ SceneHolder::SceneHolder(QObject *parent) visualMap[i].resize(Constants::map_size.height); } +void SceneHolder::reset() +{ + /* reset actor directions */ + foreach(Actor *actor, m_actors) + actor->resetDirection(); +} + void SceneHolder::updateMap(const Transmission::map_t& map) { /* remove items that got marked for removal from scene */ @@ -42,6 +49,9 @@ void SceneHolder::updateMap(const Transmission::map_t& map) updateMap(map, x, y); } } + + if (m_pointsLeft == 0) + emit allPointsRemoved(); } void SceneHolder::updateMap(const Transmission::map_t& map, const unsigned int x, unsigned int y) @@ -83,30 +93,30 @@ void SceneHolder::updateMap(const Transmission::map_t& map, const unsigned int x if (cur == Transmission::none) { - // no update + /* no update */ } else { if (cur & Transmission::block) { unsigned int neighbours = Block::None; - // check for old block first + /* check for old block first */ if (visualMap[x][y] != NULL) { Block *oldItem = qgraphicsitem_cast(visualMap[x][y]); if (oldItem != NULL) neighbours = oldItem->neighbours(); } - // check left side + /* check left side */ if (x > 0 && map[x - 1][y] & Transmission::block) neighbours |= Block::Left; - // check right side + /* check right side */ if (x < Constants::map_size.width && map[x + 1][y] & Transmission::block) neighbours |= Block::Right; - // check upside + /* check upside */ if (y > 0 && map[x][y - 1] & Transmission::block) neighbours |= Block::Up; - // check down side + /* check down side */ if (y < Constants::map_size.height && map[x][y + 1] & Transmission::block) neighbours |= Block::Down; item = new Block(color, neighbours); @@ -124,6 +134,11 @@ void SceneHolder::updateMap(const Transmission::map_t& map, const unsigned int x if (cur & Transmission::pacman) { + /* WARNING: do NOT add actor to visualMap as visualMap-items may + * get deleted during update and actors are referenced in_mactors too + * if you REALLY need that you need to changed updateMap so that all actors + * will be moved before any new items get allocated (totally untested) + */ Actor *actor = m_actors.value(color, NULL); if (actor == NULL) { @@ -136,11 +151,11 @@ void SceneHolder::updateMap(const Transmission::map_t& map, const unsigned int x { Actor::Movement direction = Util::transmissionMovementToActor( cur & Transmission::direction_mask); - /* WARNING: do NOT add actor to visualMap as visualMap-items may - * get deleted during update and actors are referenced in_mactors too - * if you REALLY need that you need to changed updateMap so that all actors - * will be moved before any new items get allocated (totally untested) + /* direction Actor::None is used on round change (i.e. new actor positions) + * it is animation-safe to use it for this direction only */ + if (direction == Actor::None) + actor->setPos(mapPositionToCoord(x, y)); actor->move(direction); /* that's kind a hack but working right now * I think that will fall on our's hat sooner or later @@ -194,8 +209,6 @@ unsigned int SceneHolder::pointsLeft() void SceneHolder::decrementPoints() { --m_pointsLeft; - if (m_pointsLeft == 0) - emit allPointsRemoved(); } void SceneHolder::setEatingOrder(QList &order) diff --git a/pacman-c++/sceneholder.h b/pacman-c++/sceneholder.h index c61de58..9340850 100644 --- a/pacman-c++/sceneholder.h +++ b/pacman-c++/sceneholder.h @@ -16,6 +16,7 @@ public: SceneHolder(QObject *parent = 0); virtual ~SceneHolder() {}; + void reset(); unsigned int pointsLeft(); void updateMap(const Transmission::map_t& map); void updateMap(const Transmission::map_t& map, const unsigned int x, const unsigned int y); @@ -56,7 +57,7 @@ protected: /* a actor can only eat his upper neighbour * the order of the neighbours is determined by the colors order (sent from server) * please note that !pl1.canEat(pl2, ...) doesn't necessarily mean that pl2 can eat pl1 - * order MUST be in this format: [col1, [col2, ..., colN], col1] + * order MUST be in this format: [col1, [col2 ... colN], col1] */ QList m_eatingorder; diff --git a/pacman-c++/server.cpp b/pacman-c++/server.cpp index 72ee995..be45a66 100644 --- a/pacman-c++/server.cpp +++ b/pacman-c++/server.cpp @@ -11,7 +11,8 @@ Server::Server(QWidget *parent) : SceneHolder(parent), m_bindaddress(QHostAddress::Any), - m_port(Constants::Networking::port), m_rounds(3), m_numbots(0), m_curRound(0) + m_port(Constants::Networking::port), m_numbots(0), + m_rounds(3), m_curRound(0), m_roundFinished(false) { /* determine max players by using order array */ for(m_maxplayers = 0; Color::order[m_maxplayers] != Color::none; ++m_maxplayers); @@ -24,41 +25,65 @@ bool Server::run() m_eatingorder.append(Color::order[i]); m_eatingorder.append(Color::order[0]); + m_tickTimer = new QTimer(this); + m_tickTimer->setInterval(Constants::tick); + connect(m_tickTimer, SIGNAL(timeout()), this, SLOT(tick())); + qDebug() << "[Server] Running server..."; qDebug() << "[Server] Max players:" << m_maxplayers; - qDebug() << "[Server] Number of rounds:" << m_rounds; qDebug() << "[Server] Number of bots:" << m_numbots; + qDebug() << "[Server] Number of rounds:" << m_rounds; if (!waitForClientConnections()) return false; + connect(this, SIGNAL(allPointsRemoved()), this, SLOT(setRoundFinished())); initRoundMap(); - - m_tickTimer = new QTimer(this); - connect(m_tickTimer, SIGNAL(timeout()), this, SLOT(tick())); - m_tickTimer->start(Constants::tick); - return true; } void Server::tick() { //qDebug() << "[Tick] Doing server update"; - foreach (Color::Color color, m_bots) - botCalculate(m_actors[color]); - Transmission::map_t map = calculateUpdates(); - updateMap(map); + if (m_roundFinished) + { + // TODO: call this when a pacman get's eaten + /* first finish previous round */ + foreach(Actor *actor, m_actors) + actor->finishRound(); + + ++m_curRound; + if(m_curRound < m_rounds) + initRoundMap(); + else + { + /* end of game */ + qDebug() << "All round finished. Exiting..."; + m_tickTimer->stop(); + qApp->quit(); + } + } + else + { + /* let the bots move */ + foreach (Color::Color color, m_bots) + botCalculate(m_actors[color]); - /* add a random bonus point */ - QPoint pos = addRandomPoint(map, Transmission::bonuspoint); - if (!pos.isNull()) - updateMap(map, pos.x(), pos.y()); + /* move on the virtual map */ + Transmission::map_t map = calculateUpdates(); + updateMap(map); - /* add/remove random colorized block */ - if (this->property("coloredblocks").toBool()) - colorizeBlocks(map); + /* add a random bonus point */ + QPoint pos = addRandomPoint(map, Transmission::bonuspoint); + if (!pos.isNull()) + updateMap(map, pos.x(), pos.y()); - sendUpdate(map); - Util::deleteMap(map); + /* add/remove random colorized block */ + if (this->property("coloredblocks").toBool()) + colorizeBlocks(map); + + sendUpdate(map); + Util::deleteMap(map); + } } Transmission::map_t Server::calculateUpdates() @@ -364,10 +389,7 @@ void Server::botCalculate(Actor *actor) /* check if neighbour is a block */ Block *block = qgraphicsitem_cast(item); if (block != NULL && block->color() != actor->color()) - { i.remove(); - continue; - } } /* we're enclosed by blocks */ @@ -410,7 +432,13 @@ void Server::botCalculate(Actor *actor) int olddistance = (actorpos - otherpos).manhattanLength(); int newdistance = (newpos - otherpos).manhattanLength(); if (newdistance >= olddistance) - i.setValue(i.value() += Constants::AI::weight_afraid); + i.setValue(i.value() + Constants::AI::weight_afraid); + + /* check for blocks of own color: other pacman can't follow their */ + GameEntity *item = visualMap[newpos.x()][newpos.y()]; + Block *block = qgraphicsitem_cast(item); + if (block != NULL && block->color() == actor->color()) + i.setValue(i.value() + Constants::AI::weight_colorblock); } /* check for new positions in hunt list */ @@ -419,7 +447,7 @@ void Server::botCalculate(Actor *actor) int olddistance = (actorpos - otherpos).manhattanLength(); int newdistance = (newpos - otherpos).manhattanLength(); if (newdistance <= olddistance) - i.setValue(i.value() += Constants::AI::weight_hunt); + i.setValue(i.value() + Constants::AI::weight_hunt); } /* check for bonuspoint */ @@ -482,24 +510,15 @@ void Server::keyPressUpdate() } } -void Server::onRoundFinished() +void Server::setRoundFinished(bool value) { - // TODO: call this when a pacman get's eaten - foreach(Actor *actor, m_actors) - actor->finishRound(); - - initRoundMap(); - ++m_curRound; - - /* end of game */ - if(m_curRound >= m_rounds) - m_tickTimer->stop(); + m_roundFinished = value; } void Server::initRoundMap() { - /* delete actors first */ - removeActors(); + qDebug() << "[initRoundMap] New round starts..."; + m_tickTimer->stop(); /* create new map */ Transmission::map_t map = Util::createDemoMap(); @@ -523,7 +542,9 @@ void Server::initRoundMap() Util::deleteMap(map); map = NULL; - connect(this, SIGNAL(allPointsRemoved()), this, SLOT(onRoundFinished()), Qt::UniqueConnection); + m_roundFinished = false; + m_actorMovements.clear(); + m_tickTimer->start(); } bool Server::parseCommandline() @@ -564,6 +585,7 @@ bool Server::parseCommandline() opt.setOption("rounds", 'r'); out << " -r, --rounds [1..n]" << endl << " Number of rounds to play" << endl + << " Default: " << m_rounds << endl << endl; opt.setFlag("nocolorblocks"); out << " -h, --help" << endl diff --git a/pacman-c++/server.h b/pacman-c++/server.h index 6dd138b..a5afbfe 100644 --- a/pacman-c++/server.h +++ b/pacman-c++/server.h @@ -41,7 +41,7 @@ protected: protected slots: /* called when a round is finished */ - void onRoundFinished(); + void setRoundFinished(bool value = true); protected: QMap m_clientConnections; @@ -61,10 +61,12 @@ protected: QHostAddress m_bindaddress; unsigned int m_port; unsigned int m_maxplayers; - unsigned int m_rounds; // number of rounds (>= 1) unsigned int m_numbots; - - unsigned int m_curRound; // current round starting with 0 + /* number of rounds (>= 1) */ + unsigned int m_rounds; + /* current round, starting at 0 */ + unsigned int m_curRound; + bool m_roundFinished; QTimer *m_tickTimer; -- cgit v1.2.3