#include "actor.h" #include "util.h" #include #include #include static QVariant myBooleanInterpolator(const bool &start, const bool &end, qreal progress) { return (progress == 1.0) ? end : start; } Actor::Actor(Color::Color color, bool local, QGraphicsItem *parent) : GameEntity(color, parent),m_direction(Actor::None), m_local(local), m_wakaPlayer(NULL), m_roundPoints(0), m_gamePoints(0) { m_type = Type; /* DON'T set any pixmap here. we've a pixmap in the animation * but we need a sprite for the collision detection */ setSprite(Constants::sprite_margin, Constants::sprite_margin, Constants::field_size.width, Constants::field_size.height); /* higher player "over" lower player */ setZValue(m_color * 10); /* rest of the ctor is only for clients */ if (Constants::server) return; /* our actor pixmap. created after server part */ m_pix = ":/" + QString("actor%1").arg(Util::floorLog2(color) + 1); /* setup icon for player */ m_icon.setPixmap(m_pix); m_icon.setSprite(Constants::sprite_margin, Constants::sprite_margin, Constants::field_size.width, Constants::field_size.height); /* setup static images first * they are visible if no animation is running * and will be the first in m_images */ for (int i = 0; i < 5; i++) { PixmapItem *img = new PixmapItem(m_pix, this); m_images.append(img); int x = i * Constants::sprite_offset + Constants::sprite_margin; int y = Actor::None * Constants::sprite_offset + Constants::sprite_margin; img->setSprite(x, y, Constants::field_size.width, Constants::field_size.height); img->setZValue(zValue()); img->setVisible(false); } /* setup animation stuff */ qRegisterAnimationInterpolator(myBooleanInterpolator); m_moving = new QParallelAnimationGroup(this); m_eating.append(NULL); // Actor::None m_eating.append(setupEatingAnimation(Actor::Left)); m_eating.append(setupEatingAnimation(Actor::Right)); m_eating.append(setupEatingAnimation(Actor::Up)); m_eating.append(setupEatingAnimation(Actor::Down)); /* setup waka sound */ if (local) m_wakaPlayer = new GaplessAudioPlayer(Sound::WakaWaka, 100, this); /* make the picture showing the current direction visible */ m_images[m_direction]->setVisible(true); } QSequentialAnimationGroup *Actor::setupEatingAnimation(Actor::Movement direction) { QSequentialAnimationGroup *eating = new QSequentialAnimationGroup(this); eating->setLoopCount(-1); for (int i = 0; i < 4; i++) { PixmapItem *img = new PixmapItem(m_pix, this); m_images.append(img); int x = i * Constants::sprite_offset + Constants::sprite_margin; int y = direction * Constants::sprite_offset + Constants::sprite_margin; img->setSprite(x, y, Constants::field_size.width, Constants::field_size.height); img->setZValue(zValue()); img->setVisible(false); QPropertyAnimation *fadein = new QPropertyAnimation(img, "visible", eating); fadein->setDuration(0); fadein->setEndValue(true); eating->addPause(100); QPropertyAnimation *fadeout = new QPropertyAnimation(img, "visible", eating); fadeout->setDuration(0); fadeout->setEndValue(false); QPropertyAnimation *move = new QPropertyAnimation(img, "pos", m_moving); move->setDuration(Constants::tick - 30); move->setEndValue(QPoint(0, 0)); } return eating; } PixmapItem &Actor::icon() { return m_icon; } Actor::Movement Actor::direction() { return m_direction; } bool Actor::isLocal() { return m_local; } void Actor::move(Actor::Movement direction) { if (Constants::server) return moveByServer(direction); /* stop current animation if direction changed */ if (direction != m_direction) { /* hide all pictures */ for (int i = 0; i < m_images.size(); ++i) m_images.at(i)->setVisible(false); if (m_eating[m_direction] != NULL) m_eating[m_direction]->stop(); } QPointF endpos(0, 0); switch(direction) { case Actor::None: break; case Actor::Left: endpos.setX(static_cast(Constants::field_size.width) * -1); break; case Actor::Right: endpos.setX(Constants::field_size.width); break; case Actor::Up: endpos.setY(static_cast(Constants::field_size.height) * -1); break; case Actor::Down: endpos.setY(Constants::field_size.height); break; default: Q_ASSERT(false); break; } for(int i = 0; i < m_moving->animationCount(); ++i) { QPropertyAnimation *move = dynamic_cast(m_moving->animationAt(i)); move->setStartValue(QPoint(0, 0) - endpos); } setPos(pos() + endpos); /* start new animation if direction changed */ if (direction != m_direction) { if (direction == Actor::None) m_images[m_direction]->setVisible(true); else m_eating[direction]->start(); } /* start moving animation */ if (direction != Actor::None) m_moving->start(); m_direction = direction; } void Actor::moveByServer(Actor::Movement direction) { QPointF endpos(0, 0); switch(direction) { case Actor::None: break; case Actor::Left: endpos.setX(static_cast(Constants::field_size.width) * -1); break; case Actor::Right: endpos.setX(Constants::field_size.width); break; case Actor::Up: endpos.setY(static_cast(Constants::field_size.height) * -1); break; case Actor::Down: endpos.setY(Constants::field_size.height); break; default: Q_ASSERT(false); break; } setPos(pos() + endpos); m_direction = direction; } bool Actor::isMoving() { return (m_moving->state() == QAbstractAnimation::Running); } void Actor::die() { if (!m_local) return; AudioManager::self()->play(Sound::Die); } void Actor::eatingFruit() { if (!m_local) return; AudioManager::self()->play(Sound::EatingFruit); } void Actor::eatingPacman() { if (!m_local) return; AudioManager::self()->play(Sound::EatingGhost); } void Actor::startEating() { if (!m_local || !m_wakaPlayer->isWorking()) return; m_wakaPlayer->play(); } void Actor::stopEating() { if (!m_local || !m_wakaPlayer->isWorking()) return; m_wakaPlayer->pause(); } unsigned int Actor::getRoundPoints() { return m_roundPoints; } unsigned int Actor::getGamePoints() { return m_gamePoints; } void Actor::addRoundPoints(unsigned int amount) { m_roundPoints += amount; } void Actor::finishRound() { m_gamePoints += m_roundPoints; m_roundPoints = 0; }