#include "sceneholder.h" #include "constants.h" #include "gameentity.h" #include "block.h" #include "actor.h" #include "bonuspoint.h" #include "point.h" #include "util.h" SceneHolder::SceneHolder(QObject *parent) : QGraphicsScene(parent), m_color(Color::none), m_pointsLeft(0) { setSceneRect(0, 0, Constants::map_size_pixel.width, Constants::map_size_pixel.height); setBackgroundBrush(Qt::black); visualMap.resize(Constants::map_size.width); for (int i = 0; i < visualMap.size(); ++i) visualMap[i].resize(Constants::map_size.height); } void SceneHolder::reset() { processDelayedItems(); /* remove actors from scene so they don't get deleted during clear */ foreach(Actor *actor, m_actors) { actor->resetAnimation(); removeItem(actor); } /* clear our stuff */ clear(); m_pointsLeft = 0; for (int i = 0; i < visualMap.size(); ++i) { visualMap[i].clear(); visualMap[i].resize(Constants::map_size.height); } /* add actors again */ foreach(Actor *actor, m_actors) addItem(actor); } void SceneHolder::processDelayedItems() { /* remove items that got marked for removal from scene */ foreach(GameEntity *item, m_oldItems) { removeItem(item); delete item; } m_oldItems.clear(); /* process death */ foreach(const Color::Color color, m_death.keys()) { Q_ASSERT(m_death[color] != NULL); m_death[color]->onDie(m_actors[color]); } m_death.clear(); } void SceneHolder::updateMap(const Transmission::map_t& map) { processDelayedItems(); /* process update */ for (unsigned int x = 0; x < Constants::map_size.width; ++x) { for (unsigned int y = 0; y < Constants::map_size.height; ++y) { const Transmission::field_t &cur = map[x][y]; if (cur == Transmission::none) continue; 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) { const Transmission::field_t &cur = map[x][y]; if (cur == Transmission::none) return; Color::Color color = static_cast(cur & Transmission::color_mask); GameEntity* item = NULL; if (cur & Transmission::empty) { GameEntity *oldItem = visualMap[x][y]; /* special handling for purging field */ if (oldItem != NULL) { /* remove item from visualmap and register item for removal in next update */ visualMap[x][y] = NULL; m_oldItems.append(oldItem); /* an item must be removed by an actor */ Actor *actor = m_actors[color]; if (actor == NULL) Q_ASSERT(false); oldItem->onDie(actor); } } if (cur == Transmission::none) { /* no update */ } else { if (cur & Transmission::block) { unsigned int neighbours = Block::None; /* 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 */ if (x > 0 && map[x - 1][y] & Transmission::block) neighbours |= Block::Left; /* check right side */ if (x < Constants::map_size.width && map[x + 1][y] & Transmission::block) neighbours |= Block::Right; /* check upside */ if (y > 0 && map[x][y - 1] & Transmission::block) neighbours |= Block::Up; /* check down side */ if (y < Constants::map_size.height && map[x][y + 1] & Transmission::block) neighbours |= Block::Down; item = new Block(color, neighbours); } if (cur & Transmission::bonuspoint) item = new BonusPoint(); if (cur & Transmission::point) { item = new Point(); connect(item, SIGNAL(destroyed()), this, SLOT(decrementPoints())); ++m_pointsLeft; } 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 { 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 */ 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 */ if (!(cur & Transmission::empty)) actor->stopEating(); qDebug() << "[SceneUpdate] actor moves: color=" << color << "direction=" << direction << "newpos=" << QPoint(x, y); } if (cur & Transmission::death) m_death[color] = visualMap[x][y]; } if (cur & Transmission::empty) { /* already handled */ } } /* add new created item to scene * remove old item on that location if there's one */ if (item != NULL) { GameEntity *oldItem = visualMap[x][y]; if (oldItem != NULL) { removeItem(oldItem); delete oldItem; } addItem(item); item->setPos(mapPositionToCoord(x, y)); visualMap[x][y] = item; } } void SceneHolder::setColor(Color::Color color) { m_color = color; } Color::Color SceneHolder::color() { return m_color; } unsigned int SceneHolder::pointsLeft() { return m_pointsLeft; } void SceneHolder::decrementPoints() { --m_pointsLeft; } void SceneHolder::setEatingOrder(QList &order) { m_eatingorder = order; } QList &SceneHolder::eatingOrder() { return m_eatingorder; } QPoint SceneHolder::mapPositionToCoord(unsigned int x, unsigned int y) { return QPoint(x * Constants::field_size.width, y * Constants::field_size.height); } QPoint SceneHolder::mapPositionToCoord(QPoint point) { return mapPositionToCoord(point.x(), point.y()); } QPoint SceneHolder::CoordToMapPosition(unsigned int x, unsigned int y) { return QPoint(x / Constants::field_size.width, y / Constants::field_size.height); } QPoint SceneHolder::CoordToMapPosition(QPoint point) { return CoordToMapPosition(point.x(), point.y()); }