From ce20694e0db010b5d65bdd2ee81a410efbf99e3d Mon Sep 17 00:00:00 2001 From: manuel Date: Mon, 2 May 2011 15:50:23 +0200 Subject: w000h00 --- pacman-c++/actor.cpp | 43 +++++++++++- pacman-c++/actor.h | 9 ++- pacman-c++/audio.h | 2 +- pacman-c++/bonuspoint.cpp | 1 - pacman-c++/mainwidget.cpp | 2 +- pacman-c++/sceneholder.cpp | 100 +++++++++++++++++---------- pacman-c++/sceneholder.h | 1 + pacman-c++/server.cpp | 166 +++++++++++++++++++++++++++++++++++++++++---- pacman-c++/util.cpp | 6 +- 9 files changed, 269 insertions(+), 61 deletions(-) diff --git a/pacman-c++/actor.cpp b/pacman-c++/actor.cpp index 2dced34..9c2d2fa 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_reset(true), m_wakaPlayer(NULL), m_roundPoints(0), m_gamePoints(0) { m_type = Type; @@ -62,6 +62,7 @@ Actor::Actor(Color::Color color, bool local, QGraphicsItem *parent) for (int i = 0; i < 11; i++) { PixmapItem *img = new PixmapItem(m_pix, this); + img->setZValue(zValue() * 10); m_images.append(img); int x = i * Constants::sprite_offset + Constants::sprite_margin; int y = 5 * Constants::sprite_offset + Constants::sprite_margin; @@ -130,13 +131,28 @@ Actor::Movement Actor::direction() return m_direction; } + +void Actor::setDirection(Movement direction) +{ + m_direction = direction; +} + bool Actor::isLocal() { return m_local; } -void Actor::resetAnimation() +bool Actor::hadReset() { + if (!m_reset) + return false; + m_reset = false; + return true; +} + +void Actor::reset() +{ + m_reset = true; if (Constants::server) return; @@ -154,6 +170,21 @@ void Actor::resetAnimation() m_images[m_direction]->setVisible(true); } +void Actor::move(QPoint newpos) +{ + QPoint oldpos = pos().toPoint(); + Actor::Movement direction = Actor::None; + if (oldpos.x() - newpos.x() < 0) + direction = Actor::Right; + else if (oldpos.x() - newpos.x() > 0) + direction = Actor::Left; + else if (oldpos.y() - newpos.y() < 0) + direction = Actor::Down; + else if (oldpos.y() - newpos.y() > 0) + direction = Actor::Up; + move(direction); +} + void Actor::move(Actor::Movement direction) { if (Constants::server) @@ -244,12 +275,18 @@ bool Actor::canEat(Actor *other, const QList &order) return (order.at(idx + 1) == other->color()); } +void Actor::onDie(Actor *other) +{ + other->eatingPacman(); + die(); +} + void Actor::die() { if (Constants::server) return; - resetAnimation(); + reset(); m_images[m_direction]->setVisible(false); m_dieing->start(); if (m_local) diff --git a/pacman-c++/actor.h b/pacman-c++/actor.h index eb04c71..e7d3ebc 100644 --- a/pacman-c++/actor.h +++ b/pacman-c++/actor.h @@ -34,9 +34,12 @@ public: PixmapItem &icon(); Movement direction(); - void resetAnimation(); + void setDirection(Movement direction); + void reset(); + bool hadReset(); bool isLocal(); void move(Movement direction); + void move(QPoint newpos); bool isMoving(); void die(); void eatingFruit(); @@ -44,13 +47,14 @@ public: void startEating(); void stopEating(); bool canEat(Actor *other, const QList &order); + virtual void onDie(Actor *); unsigned int getRoundPoints(); unsigned int getGamePoints(); void addRoundPoints(unsigned int amount); void finishRound(bool died = false); - static QPoint movementToPoint(const Actor::Movement direction); + static QPoint movementToPoint(const Movement direction); private: void moveByServer(Movement direction); @@ -61,6 +65,7 @@ private: Movement m_direction; PixmapItem m_icon; bool m_local; + bool m_reset; GaplessAudioPlayer *m_wakaPlayer; unsigned int m_roundPoints; diff --git a/pacman-c++/audio.h b/pacman-c++/audio.h index 9a4feec..6aec42d 100644 --- a/pacman-c++/audio.h +++ b/pacman-c++/audio.h @@ -25,7 +25,7 @@ namespace Sound }; const unsigned int length[] = { - 4310, 2090, 570, 570, 1720 + 4310, 2090, 570, 570, 1720, }; }; diff --git a/pacman-c++/bonuspoint.cpp b/pacman-c++/bonuspoint.cpp index a6736c4..033b7c8 100644 --- a/pacman-c++/bonuspoint.cpp +++ b/pacman-c++/bonuspoint.cpp @@ -36,4 +36,3 @@ void BonusPoint::onDie(Actor *actor) { actor->eatingFruit(); } - diff --git a/pacman-c++/mainwidget.cpp b/pacman-c++/mainwidget.cpp index f164219..3c77765 100644 --- a/pacman-c++/mainwidget.cpp +++ b/pacman-c++/mainwidget.cpp @@ -141,7 +141,7 @@ void MainWidget::tick() Q_ASSERT(worked); Q_UNUSED(worked); - /* eating order data set inidicates a new round */ + /* eating order data set indicates a new round */ if (m_updatepacket.eating_order_size() > 0) { Q_ASSERT(m_scene != NULL); diff --git a/pacman-c++/sceneholder.cpp b/pacman-c++/sceneholder.cpp index 1ecf31b..f6b8145 100644 --- a/pacman-c++/sceneholder.cpp +++ b/pacman-c++/sceneholder.cpp @@ -25,7 +25,7 @@ void SceneHolder::reset() /* remove actors from scene so they don't get deleted during clear */ foreach(Actor *actor, m_actors) { - actor->resetAnimation(); + actor->reset(); removeItem(actor); } @@ -88,8 +88,20 @@ void SceneHolder::updateMap(const Transmission::map_t& map, const unsigned int x if (cur == Transmission::none) return; + /* we may have multiple colors in one position (e.g during eating another pacman) */ Color::Color color = static_cast(cur & Transmission::color_mask); - GameEntity* item = NULL; + QList colors; + if (color == Color::none) + colors.append(Color::none); + foreach(Color::Color col, m_eatingorder.toSet()) + { + if (color & col) + colors.append(col); + } + Q_ASSERT(colors.count() > 0); + + /* for now complain if there are more colors or it's a Transmission::death packet */ + Q_ASSERT(colors.count() == 1 || cur & Transmission::death); if (cur & Transmission::empty) { @@ -102,13 +114,13 @@ void SceneHolder::updateMap(const Transmission::map_t& map, const unsigned int x m_oldItems.append(oldItem); /* an item must be removed by an actor */ - Actor *actor = m_actors[color]; - if (actor == NULL) - Q_ASSERT(false); + Actor *actor = m_actors[colors.at(0)]; + Q_ASSERT(actor != NULL); oldItem->onDie(actor); } } + GameEntity *item = NULL; if (cur == Transmission::none) { /* no update */ @@ -137,7 +149,7 @@ void SceneHolder::updateMap(const Transmission::map_t& map, const unsigned int x /* check down side */ if (y < Constants::map_size.height && map[x][y + 1] & Transmission::block) neighbours |= Block::Down; - item = new Block(color, neighbours); + item = new Block(colors.at(0), neighbours); } if (cur & Transmission::bonuspoint) @@ -152,41 +164,55 @@ 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) - { - actor = new Actor(color, (color == m_color)); - m_actors[color] = actor; - addItem(actor); - actor->setPos(mapPositionToCoord(x, y)); - } - else + foreach(color, colors) { - Actor::Movement direction = Util::transmissionMovementToActor( - cur & Transmission::direction_mask); - /* direction Actor::None is used on round change (i.e. new actor positions) - * it is animation-safe to use it for this direction only + /* 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) */ - if (direction == Actor::None) + Actor *actor = m_actors.value(color, NULL); + if (actor == NULL) + { + actor = new Actor(color, (color == m_color)); + m_actors[color] = actor; + addItem(actor); 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 - */ - if (!(cur & Transmission::empty)) - actor->stopEating(); - qDebug() << "[SceneUpdate] actor moves: color=" << color - << "direction=" << direction << "newpos=" << QPoint(x, y); + actor->hadReset(); + } + else + { + /* check for death */ + if (cur & Transmission::death) + { + foreach(Color::Color col, colors) + { + if (color == col) + continue; + if (m_actors[col]->canEat(actor, m_eatingorder)) + { + m_death[col] = actor; + break; + } + } + } + + /* move actor */ + if (actor->hadReset()) + actor->setPos(mapPositionToCoord(x, y)); + else + actor->move(mapPositionToCoord(x, y)); + + /* that's kind a hack but working right now */ + if (!(cur & Transmission::empty)) + actor->stopEating(); + qDebug() << "[SceneUpdate] actor moves: color=" << color + << "newpos=" << QPoint(x, y); + } + + if ((cur & Transmission::death) && visualMap[x][y] != NULL) + m_death[color] = visualMap[x][y]; } - - - if (cur & Transmission::death) - m_death[color] = visualMap[x][y]; } if (cur & Transmission::empty) diff --git a/pacman-c++/sceneholder.h b/pacman-c++/sceneholder.h index f36c31e..dcc10bf 100644 --- a/pacman-c++/sceneholder.h +++ b/pacman-c++/sceneholder.h @@ -51,6 +51,7 @@ protected: * must be remove one tick later */ QList m_oldItems; + /* we need to store items that killed an actor too (e.g. colored blocks) */ QMap m_death; /* my local color */ diff --git a/pacman-c++/server.cpp b/pacman-c++/server.cpp index ef271f0..2b43bb9 100644 --- a/pacman-c++/server.cpp +++ b/pacman-c++/server.cpp @@ -44,7 +44,7 @@ bool Server::run() void Server::tick() { - qDebug() << "[Tick] Doing server update"; + //qDebug() << "[Tick] Doing server update"; if (m_finishRound) stopGame(true); if (!m_running) @@ -78,6 +78,7 @@ void Server::tick() Transmission::map_t Server::calculateUpdates() { + QMap > movements; Transmission::map_t map = Util::createEmptyMap(); QMutableMapIterator i(m_actorMovements); @@ -105,12 +106,9 @@ invalid_direction: if (newMapPosition.y() >= visualMap[newMapPosition.x()].size()) newMapPosition.setY(visualMap[newMapPosition.x()].size() - 1); - // - // TODO: support actors eating each other - GameEntity *oldItem = visualMap[mapPosition.x()][mapPosition.y()]; - /* check if there's an item at new location of actor */ GameEntity *item = visualMap[newMapPosition.x()][newMapPosition.y()]; + GameEntity *oldItem = visualMap[mapPosition.x()][mapPosition.y()]; if (item != NULL && oldItem != item) { qDebug() << "[Calc] Found item at new actor location"; @@ -128,14 +126,13 @@ invalid_direction: map[newMapPosition.x()][newMapPosition.y()] = Transmission::empty | actor->color(); else if (survive == GameEntity::DestroyedActor) { + map[newMapPosition.x()][newMapPosition.y()] = Transmission::death | actor->color(); m_actors[item->color()]->addRoundPoints(actor->getRoundPoints()); actor->finishRound(true); - map[newMapPosition.x()][newMapPosition.y()] = Transmission::death | actor->color(); setFinishRound(); } } } - // /* movement didn't work - e.g. was blocked */ if (mapPosition == newMapPosition) @@ -156,19 +153,108 @@ invalid_direction: } } - map[newMapPosition.x()][newMapPosition.y()] |= Transmission::pacman | - color | Util::actorMovementToTransmission(direction); + /* store movement for collision */ + movements.insert(color, QPair(mapPosition, newMapPosition)); + + /* set direction (used for collision detection) */ + actor->setDirection(direction); /* DEBUG: uncomments to disable auto-movement */ //direction = Actor::None; + /* actor is not moving anymore: remove from list */ if (direction == Actor::None) - { - /* set actor to non-moving */ - m_actorMovements[color] = Actor::None; i.remove(); + } + + /* check for actor collision */ + QList blocked; + foreach(Color::Color color, movements.keys()) + { + Actor *actor = m_actors[color]; + QPoint oldpos = movements[color].first; + QPoint newpos = movements[color].second; + QPoint scenepos = actor->pos().toPoint(); + + /* first move actor to new position */ + actor->move(actor->direction()); + + /* next check for collisions */ + Actor *orderer = NULL; + Actor *meal = NULL; + foreach(Actor *other, m_actors) + { + if (actor == other) + continue; + if (!actor->collidesWithItem(other)) + continue; + /* both move in the same direction */ + if (actor->direction() == other->direction()) + continue; + + if (other->canEat(actor, m_eatingorder)) + { + qDebug() << "[Collision] Actor" << actor->color() << "got EATEN by" << other->color(); + orderer = other; + meal = actor; + break; + } + else if (actor->canEat(other, m_eatingorder)) + { + qDebug() << "[Collision] Actor" << actor->color() << "EATS" << other->color(); + orderer = actor; + meal = other; + blocked.append(other); + break; + } + else + { + qDebug() << "[Collision] Actor" << actor->color() << "got BLOCKED by" << other->color(); + blocked.append(actor); + /* no break here */ + } + } + + /* update map depending on collision */ + if (orderer != NULL && meal != NULL) + { + map[newpos.x()][newpos.y()] |= Transmission::pacman | Transmission::death + | orderer->color() | meal->color(); + orderer->addRoundPoints(meal->getRoundPoints()); + meal->finishRound(true); + setFinishRound(); + } + else if (blocked.contains(actor)) + { + /* move actor back early cause he won't move */ + actor->setPos(scenepos); + map[oldpos.x()][oldpos.y()] |= Transmission::pacman | color; + } + else + { + map[newpos.x()][newpos.y()] |= Transmission::pacman | color; } } + + /* move all actors back to their origin position */ + foreach(Color::Color color, movements.keys()) + m_actors[color]->setPos(mapPositionToCoord(movements[color].first)); + + foreach(Color::Color col, m_eatingorder.toSet()) + { + QList found; + for (unsigned int x = 0; x < Constants::map_size.width; ++x) + { + for (unsigned int y = 0; y < Constants::map_size.height; ++y) + { + if ((map[x][y] & Transmission::color_mask) & col) + found.append(QPoint(x, y)); + } + } + if (found.count() > 1) + qDebug() << "found" << found << "fields with color=" << col; + } + return map; } @@ -519,6 +605,60 @@ void Server::initRoundMap() Util::placeActors(map, m_maxplayers, Color::order); Util::fillPoints(map); +#if 0 // actor eating actor tests + m_actorMovements.clear(); +#if 0 + //works + map[0][0] = Color::order[0] | Transmission::pacman; + map[0][1] = Color::order[1] | Transmission::pacman; + m_actorMovements.insert(Color::order[0], Actor::Down); +#elif 0 + //works + map[0][0] = Color::order[0] | Transmission::pacman; + map[0][3] = Color::order[1] | Transmission::pacman; + m_actorMovements.insert(Color::order[0], Actor::Down); +#elif 0 + //works + map[0][0] = Color::order[0] | Transmission::pacman; + map[0][4] = Color::order[1] | Transmission::pacman; + m_actorMovements.insert(Color::order[0], Actor::Down); +#elif 0 + //works + map[0][0] = Color::order[0] | Transmission::pacman; + map[0][5] = Color::order[1] | Transmission::pacman; + m_actorMovements.insert(Color::order[0], Actor::Down); +#elif 0 + //works + map[0][0] = Color::order[1] | Transmission::pacman; + map[0][5] = Color::order[0] | Transmission::pacman; + m_actorMovements.insert(Color::order[1], Actor::Down); +#elif 0 + //works + map[0][0] = Color::order[0] | Transmission::pacman; + map[0][5] = Color::order[1] | Transmission::pacman; + m_actorMovements.insert(Color::order[0], Actor::Down); + m_actorMovements.insert(Color::order[1], Actor::Up); +#elif 0 + //works + map[0][0] = Color::order[0] | Transmission::pacman; + map[0][6] = Color::order[1] | Transmission::pacman; + m_actorMovements.insert(Color::order[0], Actor::Down); + m_actorMovements.insert(Color::order[1], Actor::Up); +#elif 0 + //works + map[0][0] = Color::order[0] | Transmission::pacman; + map[0][7] = Color::order[1] | Transmission::pacman; + m_actorMovements.insert(Color::order[0], Actor::Down); + m_actorMovements.insert(Color::order[1], Actor::Up); +#elif 1 + //works + map[0][0] = Color::order[0] | Transmission::pacman; + map[0][1] = Color::order[1] | Transmission::pacman; + m_actorMovements.insert(Color::order[0], Actor::Down); + m_actorMovements.insert(Color::order[1], Actor::Down); +#endif +#endif + /* save positions of blocks for later usage */ m_blocks.clear(); for (unsigned int x = 0; x < Constants::map_size.width; ++x) @@ -696,7 +836,7 @@ bool Server::parseCommandline() { bool ok; unsigned int rounds = QString(opt.getValue("rounds")).toUInt(&ok); - if (!ok || rounds == 0) + if (!ok) { qCritical() << "Invalid number of rounds: " << opt.getValue("rounds") << endl; return false; diff --git a/pacman-c++/util.cpp b/pacman-c++/util.cpp index f8396f9..bef7f0c 100644 --- a/pacman-c++/util.cpp +++ b/pacman-c++/util.cpp @@ -79,7 +79,7 @@ namespace Util { #if 0 for(unsigned int i = 0; i < players; ++i) - map[i][0] = colors[i] | Transmission::pacman | Transmission::direction_none; + map[i][0] = colors[i] | Transmission::pacman; return; #endif @@ -112,8 +112,8 @@ namespace Util { int rand = (int) (validpos.size() * (qrand() / (RAND_MAX + 1.0))); QPoint newpos = validpos.at(rand); - map[newpos.x()][newpos.y()] = colors[i] | Transmission::pacman | Transmission::direction_none; - qDebug() << "Actor" << i << "at" << newpos; + map[newpos.x()][newpos.y()] = colors[i] | Transmission::pacman; + qDebug() << "[Place] Actor" << i << "at" << newpos; actors.append(newpos); validpos.removeAt(rand); -- cgit v1.2.3