File indexing completed on 2024-12-01 03:46:16
0001 /* 0002 SPDX-FileCopyrightText: 2009 Mathias Kraus <k.hias@gmx.de> 0003 SPDX-FileCopyrightText: 2007-2008 Thomas Gallinari <tg8187@yahoo.fr> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "bombitem.h" 0009 #include "bomb.h" 0010 #include "settings.h" 0011 0012 #include <QTimer> 0013 #include <QGraphicsView> 0014 0015 #include <KGameRenderer> 0016 0017 const int nBombPulseTime = 100; 0018 0019 BombItem::BombItem(Bomb* p_model, KGameRenderer* renderer) : ElementItem (p_model, renderer) 0020 { 0021 setSpriteKey(QStringLiteral("bomb")); 0022 setZValue(210); 0023 connect(p_model, &Bomb::bombDetonated, this, &BombItem::startDetonation); 0024 connect(p_model, &Bomb::falling, this, &BombItem::fallingAnimation); 0025 connect(this, &BombItem::bombItemFinished, p_model, &Bomb::slot_detonationCompleted); 0026 0027 int width = static_cast<int>(Granatier::CellSize * 0.9); 0028 int height = static_cast<int>(Granatier::CellSize * 0.9); 0029 if((static_cast<int>(Granatier::CellSize) - width) % 2 != 0) 0030 { 0031 width--; 0032 } 0033 if((static_cast<int>(Granatier::CellSize) - height) % 2 != 0) 0034 { 0035 height--; 0036 } 0037 m_itemSizeSet = QSize(width, height); 0038 m_itemSizeReal = m_itemSizeSet; 0039 0040 m_animationCounter = 0; 0041 // Define the timer which sets the puls frequency 0042 m_pulseTimer = new QTimer(this); 0043 m_pulseTimer->setInterval(nBombPulseTime); 0044 m_pulseTimer->start(); 0045 connect(m_pulseTimer, &QTimer::timeout, this, &BombItem::pulse); 0046 0047 m_explosionTimer = nullptr; 0048 m_listExplosionTiming = { 0049 Settings::self()->blastTime1(), 0050 Settings::self()->blastTime2(), 0051 Settings::self()->blastTime3(), 0052 Settings::self()->blastTime4(), 0053 Settings::self()->blastTime5(), 0054 }; 0055 0056 m_fallingAnimationCounter = 0; 0057 m_dudBomb = false; 0058 } 0059 0060 BombItem::~BombItem() 0061 { 0062 delete m_pulseTimer; 0063 delete m_explosionTimer; 0064 } 0065 0066 QPainterPath BombItem::shape() const 0067 { 0068 QPainterPath path; 0069 // Temporary variable to keep the boundingRect available 0070 QRectF rect = boundingRect(); 0071 0072 // Calculation of the shape 0073 QRectF shapeRect = QRectF( rect.x()+rect.width()/8, rect.y()+rect.height()/8, rect.width()*3.0/4.0, rect.height()*3.0/4.0 ); 0074 path.addEllipse(shapeRect); 0075 return path; 0076 } 0077 0078 void BombItem::pauseAnim() 0079 { 0080 dynamic_cast <Bomb*> (m_model)->pause(); 0081 if(m_pulseTimer) 0082 { 0083 m_pulseTimer->stop(); 0084 } 0085 if(m_explosionTimer) 0086 { 0087 m_explosionTimer->stop(); 0088 } 0089 } 0090 0091 void BombItem::resumeAnim() 0092 { 0093 if(m_pulseTimer && !m_dudBomb) 0094 { 0095 m_pulseTimer->start(); 0096 } 0097 if(m_explosionTimer) 0098 { 0099 m_explosionTimer->start(); 0100 } 0101 dynamic_cast <Bomb*> (m_model)->resume(); 0102 } 0103 0104 void BombItem::update(qreal p_x, qreal p_y) 0105 { 0106 // Compute the top-right coordinates of the item 0107 qreal x = p_x - m_itemSizeSet.width() / 2; 0108 qreal y = p_y - m_itemSizeSet.height() / 2; 0109 // Updates the view coordinates 0110 setPos(x, y); 0111 m_x = static_cast<int>(p_x); 0112 m_y = static_cast<int>(p_y); 0113 } 0114 0115 void BombItem::startDetonation() 0116 { 0117 if(m_pulseTimer) 0118 { 0119 m_pulseTimer->stop(); 0120 delete m_pulseTimer; 0121 m_pulseTimer = nullptr; 0122 } 0123 m_animationCounter = 0; 0124 QTransform transform; 0125 transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0); 0126 setRenderSize(m_renderSize); 0127 transform.translate(-m_itemSizeReal.width() / 2.0, -m_itemSizeReal.height() / 2.0); 0128 setTransform(transform); 0129 dynamic_cast <Bomb*> (m_model)->setXSpeed(0); 0130 dynamic_cast <Bomb*> (m_model)->setYSpeed(0); 0131 0132 // Define the timer which sets the explosion frequency 0133 m_explosionTimer = new QTimer(this); 0134 m_explosionTimer->setInterval(m_listExplosionTiming.at(0)); 0135 m_explosionTimer->setSingleShot(true); 0136 m_explosionTimer->start(); 0137 connect(m_explosionTimer, &QTimer::timeout, this, &BombItem::updateAnimation); 0138 0139 int width = static_cast<int>(Granatier::CellSize * 1.1); 0140 int height = static_cast<int>(Granatier::CellSize * 1.1); 0141 if((static_cast<int>(Granatier::CellSize) - width) % 2 != 0) 0142 { 0143 width--; 0144 } 0145 if((static_cast<int>(Granatier::CellSize) - height) % 2 != 0) 0146 { 0147 height--; 0148 } 0149 m_itemSizeSet = QSize(width, height); 0150 m_itemSizeReal = m_itemSizeSet; 0151 setSpriteKey(QStringLiteral("bomb_blast_core_0")); 0152 setZValue(300+15); //300+maxBombPower+5 0153 updateGraphics(scale()); 0154 update(m_x, m_y); 0155 } 0156 0157 void BombItem::pulse() 0158 { 0159 if(m_fallingAnimationCounter == 0) 0160 { 0161 m_animationCounter++; 0162 if (m_animationCounter % 2 == 0) 0163 { 0164 m_animationCounter = 0; 0165 int viewWidth = static_cast<int>(m_renderSize.width() * 0.98); 0166 int viewHeight = static_cast<int>(m_renderSize.height() * 0.98); 0167 if((m_renderSize.width() - viewWidth) % 2 != 0) 0168 { 0169 viewWidth--; 0170 } 0171 if((m_renderSize.height() - viewHeight) % 2 != 0) 0172 { 0173 viewHeight--; 0174 } 0175 0176 //calculate the real item size after change of the render size 0177 QPointF sceneTopLeft = scene()->views().first()->mapToScene(QPoint(0, 0)); 0178 QPointF sceneBottomRight = scene()->views().first()->mapToScene(QPoint(viewWidth, viewHeight)); 0179 0180 qreal sceneWidth = sceneBottomRight.x() - sceneTopLeft.x(); 0181 qreal sceneHeight = sceneBottomRight.y() - sceneTopLeft.y(); 0182 0183 // shrink the item 0184 QTransform transform; 0185 transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0); 0186 setRenderSize(QSize(viewWidth, viewHeight)); 0187 transform.translate(-sceneWidth / 2.0, -sceneHeight / 2.0); 0188 setTransform(transform); 0189 } 0190 else 0191 { 0192 QTransform transform; 0193 transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0); 0194 setRenderSize(m_renderSize); 0195 transform.translate(-m_itemSizeReal.width() / 2.0, -m_itemSizeReal.height() / 2.0); 0196 setTransform(transform); 0197 } 0198 } 0199 else 0200 { 0201 // shrink the item 0202 QTransform transform; 0203 transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0); 0204 setRenderSize(m_renderSize * (1-m_fallingAnimationCounter*0.02)); 0205 transform.translate(-m_itemSizeReal.width() * (1-m_fallingAnimationCounter*0.02) / 2.0, -m_itemSizeReal.height() * (1-m_fallingAnimationCounter*0.02) / 2.0); 0206 setTransform(transform); 0207 m_fallingAnimationCounter++; 0208 0209 if(m_fallingAnimationCounter > 50) 0210 { 0211 m_pulseTimer->stop(); 0212 m_dudBomb = true; 0213 Q_EMIT bombItemFinished(this); 0214 } 0215 } 0216 } 0217 0218 void BombItem::updateAnimation() 0219 { 0220 m_animationCounter++; 0221 if (m_animationCounter > 4) 0222 { 0223 Q_EMIT bombItemFinished(this); 0224 m_animationCounter = 0; 0225 return; 0226 } 0227 QString strElemetId = QStringLiteral("bomb_blast_core_%1").arg(m_animationCounter); 0228 setSpriteKey(strElemetId); 0229 updateGraphics(scale()); 0230 update(m_x, m_y); 0231 0232 Q_EMIT animationFrameChanged(this, m_animationCounter); 0233 m_explosionTimer->setInterval(m_listExplosionTiming.at(m_animationCounter)); 0234 m_explosionTimer->start(); 0235 } 0236 0237 void BombItem::updateMortar(int nMortarState, int nMortarRampEnd, int nMortarPeak, int nMortarGround) 0238 { 0239 if(m_pulseTimer) 0240 { 0241 m_pulseTimer->stop(); 0242 delete m_pulseTimer; 0243 m_pulseTimer = nullptr; 0244 } 0245 0246 if(nMortarState <= 0) 0247 { 0248 setVisible(false); 0249 setZValue(-1); 0250 } 0251 else if(nMortarState <= nMortarGround) 0252 { 0253 updateMortarAnimation(nMortarState, nMortarRampEnd, nMortarPeak); 0254 } 0255 else 0256 { 0257 if(!m_pulseTimer) 0258 { 0259 m_pulseTimer = new QTimer(this); 0260 m_pulseTimer->setInterval(nBombPulseTime); 0261 m_animationCounter = 1; // set to one, to start pulsing with a small bomb 0262 m_pulseTimer->start(); 0263 connect(m_pulseTimer, &QTimer::timeout, this, &BombItem::pulse); 0264 } 0265 QTransform transform; 0266 transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0); 0267 setRenderSize(m_renderSize); 0268 transform.translate(-m_itemSizeReal.width() / 2.0, -m_itemSizeReal.height() / 2.0); 0269 setTransform(transform); 0270 setVisible(true); 0271 setZValue(210); 0272 } 0273 } 0274 0275 void BombItem::updateMortarAnimation(int animationCounter, int nMortarRampEnd, int nMortarPeak) 0276 { 0277 qreal mortarScale = 1; 0278 int mortarZValue = 210; 0279 QTransform transform; 0280 0281 if(animationCounter < nMortarRampEnd) 0282 { 0283 mortarZValue = 210; 0284 } 0285 else 0286 { 0287 mortarZValue = 800; 0288 } 0289 0290 int frame = animationCounter - nMortarRampEnd; 0291 int peak = nMortarPeak - nMortarRampEnd; 0292 0293 mortarScale = 1.5 - (frame-peak) * (frame-peak) / static_cast<qreal>(peak*peak) * 0.5; 0294 0295 transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0); 0296 setRenderSize(m_renderSize * mortarScale); 0297 transform.translate(-m_itemSizeReal.width() * mortarScale / 2.0, -m_itemSizeReal.height() * mortarScale / 2.0); 0298 setTransform(transform); 0299 0300 setVisible(true); 0301 setZValue(mortarZValue); 0302 } 0303 0304 void BombItem::fallingAnimation() 0305 { 0306 m_fallingAnimationCounter = 1; 0307 // set z-value below the ground 0308 setZValue(-2); 0309 m_pulseTimer->setInterval(1000 / Granatier::FPS); 0310 } 0311 0312 #include "moc_bombitem.cpp"