File indexing completed on 2025-01-12 06:46:29
0001 /* 0002 SPDX-FileCopyrightText: 2009 Mathias Kraus <k.hias@gmx.de> 0003 SPDX-FileCopyrightText: 2007-2008 Thomas Gallinari <tg8187@yahoo.fr> 0004 SPDX-FileCopyrightText: 2007-2008 Nathalie Liesse <nathalie.liesse@gmail.com> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 0010 #include "playeritem.h" 0011 #include "player.h" 0012 #include "bonus.h" 0013 #include "bonusitem.h" 0014 #include "bomb.h" 0015 #include "bombitem.h" 0016 #include "bombexplosionitem.h" 0017 0018 #include <QTimeLine> 0019 0020 #include <KGameRenderer> 0021 0022 const int PlayerItem::NB_FRAMES = 13; 0023 const int PlayerItem::ANIM_SPEED = 240; 0024 0025 PlayerItem::PlayerItem(Player* p_model, KGameRenderer* renderer) : CharacterItem(p_model, renderer) 0026 { 0027 connect(p_model, &Player::directionChanged, this, &PlayerItem::updateDirection); 0028 connect(p_model, &Player::gameUpdated, this, &PlayerItem::manageCollision); 0029 connect(p_model, &Player::stopped, this, &PlayerItem::stopAnim); 0030 connect(p_model, &Player::falling, this, &PlayerItem::fallingAnimation); 0031 connect(p_model, &Player::resurrected, this, &PlayerItem::resurrect); 0032 0033 // A timeLine for the Player animation 0034 m_animationTimer = new QTimeLine(); 0035 m_animationTimer->setEasingCurve(QEasingCurve::Linear); 0036 m_animationTimer->setLoopCount(0); 0037 m_animationTimer->setFrameRange(0, NB_FRAMES - 1); 0038 // Animation speed 0039 m_animationTimer->setDuration(PlayerItem::ANIM_SPEED); 0040 connect(m_animationTimer, &QTimeLine::frameChanged, this, &PlayerItem::setFrame); 0041 0042 int width = static_cast<int>(Granatier::CellSize * 0.9); 0043 int height = static_cast<int>(Granatier::CellSize * 0.9); 0044 if((static_cast<int>(Granatier::CellSize) - width) % 2 != 0) 0045 { 0046 width--; 0047 } 0048 if((static_cast<int>(Granatier::CellSize) - height) % 2 != 0) 0049 { 0050 height--; 0051 } 0052 m_itemSizeSet = QSize(width, height); 0053 m_itemSizeReal = m_itemSizeSet; 0054 0055 if(m_renderer->spriteExists(QStringLiteral("player_0"))) 0056 { 0057 setSpriteKey(QStringLiteral("player_0")); 0058 } 0059 0060 setZValue(250); 0061 0062 m_fallingAnimationCounter = 0; 0063 m_resurrectionAnimationCounter = 0; 0064 } 0065 0066 PlayerItem::~PlayerItem() 0067 { 0068 delete m_animationTimer; 0069 } 0070 0071 void PlayerItem::resurrect() 0072 { 0073 int nDirection = dynamic_cast <Player*> (m_model)->direction(); 0074 setZValue(250); 0075 m_fallingAnimationCounter = 0; 0076 m_resurrectionAnimationCounter = 10; 0077 setRenderSize(m_renderSize); 0078 if(m_renderer->spriteExists(QStringLiteral("player_0"))) 0079 { 0080 setSpriteKey(QStringLiteral("player_0")); 0081 } 0082 0083 QTransform transform; 0084 transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0); 0085 // get the angle 0086 switch(nDirection) 0087 { 0088 case Granatier::Direction::EAST: 0089 transform.rotate(0); 0090 break; 0091 case Granatier::Direction::SOUTH: 0092 transform.rotate(90); 0093 break; 0094 case Granatier::Direction::NORTH: 0095 transform.rotate(-90); 0096 break; 0097 case Granatier::Direction::WEST: 0098 transform.rotate(180); 0099 break; 0100 default: 0101 transform.rotate(0); 0102 break; 0103 } 0104 transform.translate(-m_itemSizeReal.width() / 2.0, -m_itemSizeReal.height() / 2.0); 0105 setTransform(transform); 0106 0107 startAnim(); 0108 0109 setVisible(true); 0110 } 0111 0112 void PlayerItem::updateDirection() 0113 { 0114 int nDirection = dynamic_cast <Player*> (m_model)->direction(); 0115 0116 // Rotate the item 0117 QTransform transform; 0118 transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0); 0119 // get the angle 0120 switch(nDirection) 0121 { 0122 case Granatier::Direction::EAST: 0123 transform.rotate(0); 0124 break; 0125 case Granatier::Direction::SOUTH: 0126 transform.rotate(90); 0127 break; 0128 case Granatier::Direction::NORTH: 0129 transform.rotate(-90); 0130 break; 0131 case Granatier::Direction::WEST: 0132 transform.rotate(180); 0133 break; 0134 default: 0135 transform.rotate(0); 0136 break; 0137 } 0138 transform.translate(-m_itemSizeReal.width() / 2.0, -m_itemSizeReal.height() / 2.0); 0139 setTransform(transform); 0140 } 0141 0142 void PlayerItem::updateGraphics(qreal svgScaleFactor) 0143 { 0144 updateGraphicsInternal(svgScaleFactor); 0145 updateDirection(); 0146 } 0147 0148 void PlayerItem::manageCollision() 0149 { 0150 QList<QGraphicsItem*> collidingList = collidingItems(); 0151 BonusItem* bonusItem; 0152 0153 // The signal is emitted only if the list contains more than 1 items (to exclude the case 0154 // when the player only collides with the arena) 0155 if (collidingList.size() > 1) 0156 { 0157 for (auto & i : collidingList) 0158 { 0159 // The arena and the points labels have a negative zValue which allows to exclude them from the treatment of collisions 0160 if (i->zValue() >= 300 && i->zValue() < 400) 0161 { 0162 //((ElementItem*)collidingList[i])->getModel()->doActionOnCollision((Player*)getModel()); 0163 int nExplosionID; 0164 if(i->zValue() == 315) 0165 { 0166 auto* bombItem = dynamic_cast <BombItem*> (i); 0167 nExplosionID = dynamic_cast <Bomb*> (bombItem->getModel())->explosionID(); 0168 } 0169 else 0170 { 0171 nExplosionID = dynamic_cast <BombExplosionItem*> (i)->explosionID(); 0172 } 0173 0174 if(dynamic_cast <Player*> (m_model)->shield(nExplosionID) == false) 0175 { 0176 setDead(); 0177 dynamic_cast <Player*> (m_model)->die(); 0178 } 0179 } 0180 else if (i->zValue() == 100) 0181 { 0182 bonusItem = dynamic_cast <BonusItem*> (i); 0183 if(dynamic_cast <Bonus*> (bonusItem->getModel())->isTaken() == false) 0184 { 0185 dynamic_cast <Bonus*> (bonusItem->getModel())->setTaken(); 0186 bonusItem->getModel()->doActionOnCollision(dynamic_cast <Player*> (this->getModel())); 0187 Q_EMIT bonusItemTaken(bonusItem); 0188 } 0189 } 0190 } 0191 } 0192 } 0193 0194 void PlayerItem::update(qreal p_x, qreal p_y) 0195 { 0196 ElementItem::update(p_x, p_y); 0197 0198 // If the player is moving 0199 if (((Player*)getModel())->getXSpeed() != 0 || ((Player*)getModel())->getYSpeed() != 0) 0200 { 0201 startAnim(); 0202 } 0203 } 0204 0205 void PlayerItem::startAnim() 0206 { 0207 // Start the animation timer if it is not active 0208 if (m_animationTimer->state() != QTimeLine::Running) 0209 { 0210 m_animationTimer->start(); 0211 } 0212 } 0213 0214 void PlayerItem::pauseAnim() 0215 { 0216 dynamic_cast <Player*> (m_model)->pause(); 0217 if (m_animationTimer->state() == QTimeLine::Running) 0218 { 0219 m_animationTimer->setPaused(true); 0220 } 0221 } 0222 0223 void PlayerItem::resumeAnim() 0224 { 0225 dynamic_cast <Player*> (m_model)->resume(); 0226 if (m_animationTimer->state() == QTimeLine::Paused) 0227 { 0228 m_animationTimer->setPaused(false); 0229 } 0230 } 0231 0232 void PlayerItem::stopAnim() 0233 { 0234 if(m_renderer->spriteExists(QStringLiteral("player_0"))) 0235 { 0236 setSpriteKey(QStringLiteral("player_0")); 0237 } 0238 if (m_animationTimer->state() != QTimeLine::NotRunning && m_resurrectionAnimationCounter == 0) 0239 { 0240 m_animationTimer->stop(); 0241 } 0242 } 0243 0244 void PlayerItem::fallingAnimation() 0245 { 0246 m_fallingAnimationCounter = 1; 0247 } 0248 0249 void PlayerItem::setFrame(const int p_frame) 0250 { 0251 if(m_renderer->spriteExists(QStringLiteral("player_%1").arg(p_frame))) 0252 { 0253 setSpriteKey(QStringLiteral("player_%1").arg(p_frame)); 0254 0255 if(m_fallingAnimationCounter > 0 || m_resurrectionAnimationCounter > 0) 0256 { 0257 int angle = 0; 0258 int nDirection = dynamic_cast <Player*> (m_model)->direction(); 0259 0260 // get the angle 0261 switch(nDirection) 0262 { 0263 case Granatier::Direction::EAST: 0264 angle = 0; 0265 break; 0266 case Granatier::Direction::SOUTH: 0267 angle = 90; 0268 break; 0269 case Granatier::Direction::NORTH: 0270 angle = -90; 0271 break; 0272 case Granatier::Direction::WEST: 0273 angle = 180; 0274 break; 0275 default: 0276 angle = 0; 0277 break; 0278 } 0279 0280 if(m_fallingAnimationCounter > 0) 0281 { 0282 // set z-value below the ground 0283 setZValue(-2); 0284 // shrink the item 0285 QTransform transform; 0286 transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.width() / 2.0); 0287 transform.rotate(angle); 0288 setRenderSize(m_renderSize * (1-m_fallingAnimationCounter*0.02)); 0289 transform.translate(-m_itemSizeReal.width() * (1-m_fallingAnimationCounter*0.02) / 2.0, -m_itemSizeReal.width() * (1-m_fallingAnimationCounter*0.02) / 2.0); 0290 setTransform(transform); 0291 m_fallingAnimationCounter++; 0292 0293 if(m_fallingAnimationCounter > 50) 0294 { 0295 setDead(); 0296 dynamic_cast <Player*> (m_model)->die(); 0297 setVisible(false); 0298 } 0299 } 0300 0301 if(m_resurrectionAnimationCounter > 0) 0302 { 0303 qreal resurrectionScale = 1; 0304 QTransform transform; 0305 transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.width() / 2.0); 0306 transform.rotate(angle); 0307 if(m_resurrectionAnimationCounter > 9) 0308 { 0309 resurrectionScale = 1.1; 0310 } 0311 else if(m_resurrectionAnimationCounter > 8) 0312 { 0313 resurrectionScale = 0.9; 0314 } 0315 else if(m_resurrectionAnimationCounter > 7) 0316 { 0317 resurrectionScale = 0.6; 0318 } 0319 else if(m_resurrectionAnimationCounter > 6) 0320 { 0321 resurrectionScale = 0.7; 0322 } 0323 else if(m_resurrectionAnimationCounter > 5) 0324 { 0325 resurrectionScale = 0.85; 0326 } 0327 else if(m_resurrectionAnimationCounter > 4) 0328 { 0329 resurrectionScale = 1; 0330 } 0331 else if(m_resurrectionAnimationCounter > 3) 0332 { 0333 resurrectionScale = 1.05; 0334 } 0335 else if(m_resurrectionAnimationCounter > 2) 0336 { 0337 resurrectionScale = 1.1; 0338 } 0339 else if(m_resurrectionAnimationCounter > 1) 0340 { 0341 resurrectionScale = 1.05; 0342 } 0343 else if(m_resurrectionAnimationCounter > 0) 0344 { 0345 resurrectionScale = 1; 0346 } 0347 0348 m_resurrectionAnimationCounter--; 0349 if(m_resurrectionAnimationCounter == 0) 0350 { 0351 resurrectionScale = 1; 0352 stopAnim(); 0353 } 0354 0355 setRenderSize(m_renderSize * resurrectionScale); 0356 transform.translate(-m_itemSizeReal.width() * resurrectionScale / 2.0, -m_itemSizeReal.width() * resurrectionScale / 2.0); 0357 setTransform(transform); 0358 } 0359 } 0360 } 0361 } 0362 0363 void PlayerItem::setDead() 0364 { 0365 stopAnim(); 0366 setZValue(1); 0367 if(m_resurrectionAnimationCounter != 0) 0368 { 0369 QTransform transform; 0370 transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0); 0371 setRenderSize(m_renderSize); 0372 transform.translate(-m_itemSizeReal.width() / 2.0, -m_itemSizeReal.height() / 2.0); 0373 setTransform(transform); 0374 } 0375 if(m_renderer->spriteExists(QStringLiteral("player_death"))) 0376 { 0377 setSpriteKey(QStringLiteral("player_death")); 0378 } 0379 } 0380 0381 #include "moc_playeritem.cpp"