/**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtDeclarative module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gameengine.h" #include "plugins/levelplugininterface.h" #include "InvSounds.h" #include #include #include #include const int TIMER_SPEED = 80; GameEngine::GameEngine(QObject* parent) :QObject(parent) { m_timerId = 0; m_doEnemyMissile = 1500 / TIMER_SPEED; m_GameGml = 0; m_gameLevel = 0; clearQmlObjects(); // For random QTime time = QTime::currentTime(); qsrand((uint)time.msec()); // Sound engine m_soundEngine = new CInvSounds(this); // Device profile m_silent = false; #ifdef Q_OS_SYMBIAN iVibrate = CHWRMVibra::NewL(); #endif // Get device profile, is it silent? #if defined Q_OS_SYMBIAN || defined Q_WS_MAEMO_5 m_systemDeviceInfo = new QSystemDeviceInfo(this); QObject::connect(m_systemDeviceInfo,SIGNAL(currentProfileChanged(QSystemDeviceInfo::Profile)),this, SLOT(currentProfileChanged(QSystemDeviceInfo::Profile))); QSystemDeviceInfo::Profile p = m_systemDeviceInfo->currentProfile(); if (p == QSystemDeviceInfo::SilentProfile) { m_silent = true; } #endif } GameEngine::~GameEngine() { #ifdef Q_OS_SYMBIAN delete iVibrate; #endif } void GameEngine::gameStartSound() { if (!m_silent) m_soundEngine->gameStartSound(); } #if defined Q_OS_SYMBIAN || defined Q_WS_MAEMO_5 void GameEngine::currentProfileChanged(QSystemDeviceInfo::Profile p) { if (p == QSystemDeviceInfo::SilentProfile) { enableSounds(QVariant(false)); } else { enableSounds(QVariant(true)); } } #endif void GameEngine::enableSounds(QVariant enable) { m_silent = !enable.toBool(); if (m_silent) this->m_soundEngine->enableSounds(false); else this->m_soundEngine->enableSounds(true); } QVariant GameEngine::randInt(QVariant low, QVariant high) { // Random number between low and high return qrand() % ((high.toInt() + 1) - low.toInt()) + low.toInt(); } void GameEngine::setGameLevel(LevelPluginInterface* level) { // Set used game level m_gameLevel = level; if (m_gameLevel) { // Set used sound from the level into sound engine m_soundEngine->enableSounds(m_gameLevel->levelSounds()); // Invoke QML to take new level in use QMetaObject::invokeMethod(m_GameGml, "levelReadyForCreation", Qt::AutoConnection); m_doEnemyMissile = m_gameLevel->enemyFireSpeed().toInt() / TIMER_SPEED; } } void GameEngine::setPluginList(QList plugins) { m_pluginList = plugins; } QVariant GameEngine::pluginList() { QStringList list; QPluginLoader* loader; foreach (loader,m_pluginList) { QString s = loader->fileName(); s = s.mid(s.lastIndexOf("/")+1); s = s.left(s.lastIndexOf(".")); s = s.toUpper(); #ifdef Q_WS_MAEMO_5 if (s.contains("LIB")) { s = s.right(s.length() - (s.indexOf("LIB")+3)); } #endif list.append(s); } return QVariant(list); } void GameEngine::pauseLevel(QVariant doPause) { bool enableTimer = !doPause.toBool(); enableEngineTimer(QVariant(enableTimer)); QMetaObject::invokeMethod(m_levelQml, "pause", Qt::AutoConnection,Q_ARG(QVariant, doPause)); } void GameEngine::findQmlObjects() { if (m_GameGml) { qDebug() << "GameEngine::findQmlObjects()"; // Find Missiles objects m_missileList.clear(); m_enemyMissileList.clear(); findMissiles(m_GameGml); // Set QMLs setLevelQml(m_GameGml->findChild("level")); setEnemiesGridQml(m_GameGml->findChild("enemiesGrid")); setMyShipQml(m_GameGml->findChild("myShip")); // Find Enemies objects m_enemyList.clear(); qDebug() << "GameEngine::findQmlObjects() find enemies from: level QML"; findEnemies(m_levelQml); } else { qDebug() << "GameEngine::findQmlObjects() rootObject NULL"; } } void GameEngine::clearQmlObjects() { m_missileList.clear(); m_enemyMissileList.clear(); m_enemyList.clear(); m_levelQml = 0; m_enemiesGridGml = 0; m_myShipGml = 0; //m_GameGml = 0; // NOTE: Do not delete this } void GameEngine::findMissiles(QObject *rootObject) { if (rootObject) { QObjectList list = rootObject->children(); QObject* item; foreach (item,list) { if (item->children().count()>0) { findMissiles(item); } else { if (rootObject->objectName()=="missile") { QDeclarativeItem* missile = static_cast(rootObject); m_missileList.append(missile); } else if (rootObject->objectName()=="enemy_missile") { QDeclarativeItem* enemyMissile = static_cast(rootObject); m_enemyMissileList.append(enemyMissile); } } } } else { qDebug() << "GameEngine::findMissiles() rootObject NULL"; } } void GameEngine::findEnemies(QObject *rootObject) { if (rootObject) { QObjectList list = rootObject->children(); QObject* item; foreach (item,list) { if (item->children().count()>0 && item->objectName()!="enemy") { //qDebug() << "Enemy children found from: " << item->objectName(); findEnemies(item); } else { if (item->objectName()=="enemy") { //qDebug() << "Enemy child founds: " << item->objectName(); QDeclarativeItem* enemy = static_cast(item); m_enemyList.append(enemy); } } } } else { qDebug() << "GameEngine::findEnemies() rootObject NULL"; } } void GameEngine::setEnemiesGridQml(QObject* o) { m_enemiesGridGml = static_cast(o); } void GameEngine::setMyShipQml(QObject* o) { m_myShipGml = static_cast(o); } void GameEngine::setGameQml(QObject* o) { m_GameGml = static_cast(o); } void GameEngine::timerEvent(QTimerEvent *e) { if (e->timerId()==m_timerId) { // Do hit test doHitTest(); m_doEnemyMissile--; if (m_gameLevel && m_doEnemyMissile<0) { m_doEnemyMissile = m_gameLevel->enemyFireSpeed().toInt() / TIMER_SPEED; // Do emeny missile launch doEnemyMissile(); } } } void GameEngine::enableEngineTimer(QVariant enable) { if (m_gameLevel) { if (m_timerId==0 && enable.toBool()) { m_timerId = QObject::startTimer(TIMER_SPEED); } else if (m_timerId != 0 && !enable.toBool()) { QObject::killTimer(m_timerId); m_timerId = 0; } } } void GameEngine::selectVisibleEnemy(int& start, int& end) { QDeclarativeItem* enemy = 0; for (int i=0 ; iopacity()==1) { start = i; break; } } enemy = 0; for (int e=m_enemyList.count()-1 ; e>0 ; e--) { enemy = m_enemyList[e]; if (enemy->opacity()==1) { end = e; break; } } } void GameEngine::doEnemyMissile() { QMutexLocker locker(&m_enemyListMutex); QDeclarativeItem* missile = 0; QDeclarativeItem* enemy = 0; // Find free missile foreach (missile, m_enemyMissileList) { if (missile->opacity()==0){ // Random select enemy who fire int start=0; int end=0; selectVisibleEnemy(start,end); int whoWillFire = randInt(QVariant(start),QVariant(end)).toInt(); if (m_enemyList.count() < whoWillFire+1) break; enemy = m_enemyList.at(whoWillFire); if (enemy && enemy->opacity()==1) { QPointF enemyP = enemy->pos(); if (m_enemiesGridGml) { enemyP += m_enemiesGridGml->pos(); } //qDebug() << "QMetaObject::invokeMethod() - fireEnemyMissile"; QMetaObject::invokeMethod(m_GameGml, "fireEnemyMissile", Qt::AutoConnection, Q_ARG(QVariant, enemyP.x()+enemy->boundingRect().width()/4), Q_ARG(QVariant, enemyP.y()+enemy->boundingRect().height()), Q_ARG(QVariant, m_GameGml->boundingRect().height())); } break; } } } void GameEngine::doHitTest() { QMutexLocker locker(&m_enemyListMutex); QDeclarativeItem* missile = 0; QDeclarativeItem* enemy = 0; // No enemies? if (m_enemyList.count()==0) { enableEngineTimer(QVariant(false)); qDebug() << "No enemies left"; gameOver(true); return; } if (!m_myShipGml) { return; } // Check ship collision if (m_myShipGml->opacity()==1) { for (int e=0; eopacity()==0) { break; } QPointF enemyP = enemy->pos(); if (m_enemiesGridGml) { enemyP += m_enemiesGridGml->pos(); } QRectF enemyR(enemyP,QSize(enemy->boundingRect().width(),enemy->boundingRect().height())); // Collision? if (enemyR.contains(m_myShipGml->pos())) { enableEngineTimer(QVariant(false)); // Collision explosion QPointF myP = m_myShipGml->pos(); playSound(1); QMetaObject::invokeMethod(m_levelQml, "explode", Qt::AutoConnection, Q_ARG(QVariant, myP.x()+m_myShipGml->boundingRect().width()/2), Q_ARG(QVariant, myP.y()+m_myShipGml->boundingRect().height())); m_myShipGml->setOpacity(0); gameOver(false); qDebug() << "Collision"; return; } // Enemy too deep? else if (enemyR.bottomLeft().y() > m_myShipGml->pos().y()+m_myShipGml->pos().y()*0.1) { enableEngineTimer(QVariant(false)); // Enemy too deep explosion QPointF myP = m_myShipGml->pos(); playSound(1); QMetaObject::invokeMethod(m_levelQml, "explode", Qt::AutoConnection, Q_ARG(QVariant, myP.x()+m_myShipGml->boundingRect().width()/2), Q_ARG(QVariant, myP.y()+m_myShipGml->boundingRect().height())); m_myShipGml->setOpacity(0); gameOver(false); qDebug() << "Enemy too deep"; return; } } } // Check your missiles hit to enemies foreach (missile, m_missileList) { if (missile->opacity()==1){ for (int e=0; eopacity()<1) { break; } QPointF missileP = missile->pos(); missileP.setX(missileP.rx() + missile->boundingRect().width()/2); QPointF enemyP = enemy->pos(); if (m_enemiesGridGml) { enemyP += m_enemiesGridGml->pos(); } QRectF r(enemyP,QSize(enemy->boundingRect().width(),enemy->boundingRect().height())); if (r.contains(missileP)) { // Hit ! playSound(0); //qDebug() << "QMetaObject::invokeMethod() - explode"; QMetaObject::invokeMethod(m_levelQml, "explode", Qt::AutoConnection, Q_ARG(QVariant, enemyP.x()+enemy->boundingRect().width()/2), Q_ARG(QVariant, enemyP.y()+enemy->boundingRect().height())); missile->setOpacity(0); //fastVibra(); if (m_enemiesGridGml) { // Set transparent placeholder for enemy when using GridView enemy->setProperty("source",QVariant("file:/"+m_gameLevel->pathToTransparentEnemyPic().toString())); } else { // Hide enemy after explode enemy->setOpacity(0); } // Remove enemy from list m_enemyList.removeAt(e); e--; } enemy = 0; } } } // Check enemies missiles hit to you if (m_myShipGml->opacity()==1) { foreach (missile, m_enemyMissileList) { if (missile->opacity()==1){ QPointF missileP = missile->pos(); missileP.setX(missileP.rx() + missile->boundingRect().width()/2); QPointF myP = m_myShipGml->pos(); QRectF r(myP,QSize(m_myShipGml->boundingRect().width(),m_myShipGml->boundingRect().height())); if (r.contains(missileP)) { // Hit ! playSound(1); //qDebug() << "QMetaObject::invokeMethod() - explode"; QMetaObject::invokeMethod(m_levelQml, "explode", Qt::AutoConnection, Q_ARG(QVariant, myP.x()+m_myShipGml->boundingRect().width()/2), Q_ARG(QVariant, myP.y()+m_myShipGml->boundingRect().height())); missile->setOpacity(0); m_myShipGml->setOpacity(0); break; } } } } else { // You was killed enableEngineTimer(QVariant(false)); gameOver(false); qDebug() << "You was killed by enemy missile"; } } void GameEngine::playSound(QVariant index) { if (!m_silent) { int i = index.toInt(); m_soundEngine->playSound(i); } } void GameEngine::playSounds(QVariant index, QVariant count) { if (!m_silent) { m_soundEngine->playSounds(index.toInt(),count.toInt()); } } void GameEngine::playInternalSound(QVariant index) { if (!m_silent) { m_soundEngine->playInternalSound(index.toInt()); } } void GameEngine::playInternalSounds(QVariant index, QVariant count) { if (!m_silent) { m_soundEngine->playInternalSounds(index.toInt(),count.toInt()); } } void GameEngine::gameOver(bool youWin) { qDebug() << "GameEngine::gameOver() "<< youWin; QMetaObject::invokeMethod(m_GameGml, "gameOver", Qt::AutoConnection,Q_ARG(QVariant, youWin)); } void GameEngine::pauseGame() { QMetaObject::invokeMethod(m_GameGml, "pauseGame", Qt::AutoConnection); } QVariant GameEngine::isSymbian() { #ifdef Q_OS_SYMBIAN return QVariant(true); #else return QVariant(false); #endif } QVariant GameEngine::isMaemo() { #ifdef Q_WS_MAEMO_5 return QVariant(true); #else return QVariant(false); #endif } QVariant GameEngine::isWindows() { #ifdef Q_OS_WIN return QVariant(true); #else return QVariant(false); #endif } void GameEngine::vibra() { #ifdef Q_OS_SYMBIAN if (iVibrate){ TRAPD(err, iVibrate->StartVibraL(4000,KHWRMVibraMaxIntensity)); } #endif } void GameEngine::fastVibra() { #ifdef Q_OS_SYMBIAN if (iVibrate){ TRAPD(err, iVibrate->StartVibraL(100,KHWRMVibraMaxIntensity)); } #endif } void GameEngine::openLink(QVariant link) { QDesktopServices::openUrl(QUrl(link.toString())); }