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