examples/graphicsview/portedasteroids/view.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the examples of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 /*
       
    43  * KAsteroids - Copyright (c) Martin R. Jones 1997
       
    44  *
       
    45  * Part of the KDE project
       
    46  */
       
    47 
       
    48 #include <stdlib.h>
       
    49 #include <math.h>
       
    50 #include <qapplication.h>
       
    51 #include <qnamespace.h>
       
    52 #include <q3accel.h>
       
    53 #include <qmessagebox.h>
       
    54 #include <q3scrollview.h>
       
    55 #include <qdir.h>
       
    56 #include <QGraphicsItem>
       
    57 //Added by qt3to4:
       
    58 #include <QTimerEvent>
       
    59 #include <QPixmap>
       
    60 #include <QResizeEvent>
       
    61 #include <QShowEvent>
       
    62 
       
    63 #include "view.h"
       
    64 
       
    65 #define IMG_BACKGROUND ":/trolltech/examples/graphicsview/portedasteroids/bg.png"
       
    66 
       
    67 #define REFRESH_DELAY           33
       
    68 #define SHIP_SPEED              0.3
       
    69 #define MISSILE_SPEED           10.0
       
    70 #define SHIP_STEPS              64
       
    71 #define ROTATE_RATE             2
       
    72 #define SHIELD_ON_COST          1
       
    73 #define SHIELD_HIT_COST         30
       
    74 #define BRAKE_ON_COST           4
       
    75 
       
    76 #define MAX_ROCK_SPEED          2.5
       
    77 #define MAX_POWERUP_SPEED       1.5
       
    78 #define MAX_SHIP_SPEED		12
       
    79 #define MAX_BRAKES              5
       
    80 #define MAX_SHIELDS             5
       
    81 #define MAX_FIREPOWER		5
       
    82 
       
    83 #define TEXT_SPEED              4
       
    84 
       
    85 #define PI_X_2                  6.283185307
       
    86 #ifndef M_PI
       
    87 #define M_PI 3.141592654
       
    88 #endif
       
    89 
       
    90 static struct
       
    91 {
       
    92     int id;
       
    93     const char *path;
       
    94     int frames;
       
    95 }
       
    96 kas_animations [] =
       
    97 {
       
    98     { ID_ROCK_LARGE,       "rock1/rock1%1.png",       32 },
       
    99     { ID_ROCK_MEDIUM,      "rock2/rock2%1.png",       32 },
       
   100     { ID_ROCK_SMALL,       "rock3/rock3%1.png",       32 },
       
   101     { ID_SHIP,             "ship/ship%1.png",         32 },
       
   102     { ID_MISSILE,          "missile/missile.png",      1 },
       
   103     { ID_BIT,              "bits/bits%1.png",         16 },
       
   104     { ID_EXHAUST,          "exhaust/exhaust.png",      1 },
       
   105     { ID_ENERGY_POWERUP,   "powerups/energy.png",      1 },
       
   106 //    { ID_TELEPORT_POWERUP, "powerups/teleport%1.png", 12 },
       
   107     { ID_BRAKE_POWERUP,    "powerups/brake.png",       1 },
       
   108     { ID_SHIELD_POWERUP,   "powerups/shield.png",      1 },
       
   109     { ID_SHOOT_POWERUP,    "powerups/shoot.png",       1 },
       
   110     { ID_SHIELD,           "shield/shield%1.png",      6 },
       
   111     { 0,                   0,                          0 }
       
   112 };
       
   113 
       
   114 KAsteroidsView::KAsteroidsView( QWidget *parent, const char *name )
       
   115     : QWidget( parent, name ),
       
   116       field(0, 0, 640, 440),
       
   117       view(&field,this)
       
   118 {
       
   119     view.setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
       
   120     view.setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
       
   121     view.setCacheMode(QGraphicsView::CacheBackground);
       
   122     view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
       
   123     view.setOptimizationFlags(QGraphicsView::DontClipPainter
       
   124                               | QGraphicsView::DontSavePainterState
       
   125                               | QGraphicsView::DontAdjustForAntialiasing);
       
   126     view.viewport()->setFocusProxy( this );
       
   127     rocks.setAutoDelete( TRUE );
       
   128     missiles.setAutoDelete( TRUE );
       
   129     bits.setAutoDelete( TRUE );
       
   130     powerups.setAutoDelete( TRUE );
       
   131     exhaust.setAutoDelete( TRUE );
       
   132 
       
   133     QPixmap pm( IMG_BACKGROUND );
       
   134     field.setBackgroundBrush( pm );
       
   135 
       
   136     textSprite = new QGraphicsTextItem( 0, &field );
       
   137     QFont font( "helvetica", 18 );
       
   138     textSprite->setFont( font );
       
   139     textSprite->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
       
   140 
       
   141     shield = 0;
       
   142     shieldOn = FALSE;
       
   143     refreshRate = REFRESH_DELAY;
       
   144 
       
   145     initialized = readSprites();
       
   146 
       
   147     shieldTimer = new QTimer( this );
       
   148     connect( shieldTimer, SIGNAL(timeout()), this, SLOT(hideShield()) );
       
   149     mTimerId = -1;
       
   150 
       
   151     shipPower = MAX_POWER_LEVEL;
       
   152     vitalsChanged = TRUE;
       
   153     can_destroy_powerups = FALSE;
       
   154 
       
   155     mPaused = TRUE;
       
   156 
       
   157     if ( !initialized ) {
       
   158 	textSprite->setHtml( tr("<font color=red>Error: Cannot read sprite images</font>") );
       
   159 	textSprite->setPos( (field.width()-textSprite->boundingRect().width()) / 2,
       
   160 			    (field.height()-textSprite->boundingRect().height()) / 2 );
       
   161     }
       
   162 }
       
   163 
       
   164 // - - -
       
   165 
       
   166 KAsteroidsView::~KAsteroidsView()
       
   167 {
       
   168 }
       
   169 
       
   170 // - - -
       
   171 
       
   172 void KAsteroidsView::reset()
       
   173 {
       
   174     if ( !initialized )
       
   175 	return;
       
   176     rocks.clear();
       
   177     missiles.clear();
       
   178     bits.clear();
       
   179     powerups.clear();
       
   180     exhaust.clear();
       
   181 
       
   182     shotsFired = 0;
       
   183     shotsHit = 0;
       
   184 
       
   185     rockSpeed = 1.0;
       
   186     powerupSpeed = 1.0;
       
   187     mFrameNum = 0;
       
   188     mPaused = FALSE;
       
   189 
       
   190     ship->hide();
       
   191     shield->hide();
       
   192 /*
       
   193     if ( mTimerId >= 0 ) {
       
   194 	killTimer( mTimerId );
       
   195 	mTimerId = -1;
       
   196     }
       
   197 */
       
   198 }
       
   199 
       
   200 // - --
       
   201 
       
   202 void KAsteroidsView::newGame()
       
   203 {
       
   204     if ( !initialized )
       
   205 	return;
       
   206     if ( shieldOn )
       
   207     {
       
   208       shield->hide();
       
   209       shieldOn = FALSE;
       
   210     }
       
   211     reset();
       
   212     if ( mTimerId < 0 )
       
   213 	mTimerId = startTimer( REFRESH_DELAY );
       
   214     emit updateVitals();
       
   215 }
       
   216 
       
   217 // - - -
       
   218 
       
   219 void KAsteroidsView::endGame()
       
   220 {
       
   221 }
       
   222 
       
   223 void KAsteroidsView::pause( bool p )
       
   224 {
       
   225     if ( !initialized )
       
   226 	return;
       
   227     if ( !mPaused && p ) {
       
   228 	if ( mTimerId >= 0 ) {
       
   229 	    killTimer( mTimerId );
       
   230 	    mTimerId = -1;
       
   231 	}
       
   232     } else if ( mPaused && !p )
       
   233 	mTimerId = startTimer( REFRESH_DELAY );
       
   234     mPaused = p;
       
   235 }
       
   236 
       
   237 // - - -
       
   238 
       
   239 void KAsteroidsView::newShip()
       
   240 {
       
   241     if ( !initialized )
       
   242 	return;
       
   243     ship->setPos( width()/2, height()/2 );
       
   244     ship->setFrame( 0 );
       
   245     shield->setPos( width()/2, height()/2 );
       
   246     shield->setFrame( 0 );
       
   247     ship->setVelocity( 0.0, 0.0 );
       
   248     shipDx = 0;
       
   249     shipDy = 0;
       
   250     shipAngle = 0;
       
   251     rotateL = FALSE;
       
   252     rotateR = FALSE;
       
   253     thrustShip = FALSE;
       
   254     shootShip = FALSE;
       
   255     brakeShip = FALSE;
       
   256     teleportShip = FALSE;
       
   257     shieldOn = TRUE;
       
   258     shootDelay = 0;
       
   259     shipPower = MAX_POWER_LEVEL;
       
   260     rotateRate = ROTATE_RATE;
       
   261     rotateSlow = 0;
       
   262 
       
   263     mBrakeCount = 0;
       
   264     mTeleportCount = 0;
       
   265     mShootCount = 0;
       
   266 
       
   267     ship->show();
       
   268     shield->show();
       
   269     mShieldCount = 1;   // just in case the ship appears on a rock.
       
   270     shieldTimer->start( 1000, TRUE );
       
   271 }
       
   272 
       
   273 void KAsteroidsView::setShield( bool s )
       
   274 {
       
   275     if ( !initialized )
       
   276 	return;
       
   277     if ( shieldTimer->isActive() && !s ) {
       
   278 	shieldTimer->stop();
       
   279 	hideShield();
       
   280     } else {
       
   281 	shieldOn = s && mShieldCount;
       
   282     }
       
   283 }
       
   284 
       
   285 void KAsteroidsView::brake( bool b )
       
   286 {
       
   287     if ( !initialized )
       
   288 	return;
       
   289     if ( mBrakeCount )
       
   290     {
       
   291 	if ( brakeShip && !b )
       
   292 	{
       
   293 	    rotateL = FALSE;
       
   294 	    rotateR = FALSE;
       
   295 	    thrustShip = FALSE;
       
   296 	    rotateRate = ROTATE_RATE;
       
   297 	}
       
   298 
       
   299 	brakeShip = b;
       
   300     }
       
   301 }
       
   302 
       
   303 // - - -
       
   304 
       
   305 bool KAsteroidsView::readSprites()
       
   306 {
       
   307     QString sprites_prefix = ":/trolltech/examples/graphicsview/portedasteroids/sprites/";
       
   308 
       
   309     int i = 0;
       
   310     while ( kas_animations[i].id )
       
   311     {
       
   312         QList<QPixmap> anim;
       
   313         QString wildcard = sprites_prefix + kas_animations[i].path;
       
   314         wildcard.replace("%1", "*");
       
   315         QFileInfo fi(wildcard);
       
   316         foreach (QString entry, QDir(fi.path(), fi.fileName()).entryList())
       
   317             anim << QPixmap(fi.path() + "/" + entry);
       
   318 	animation.insert( kas_animations[i].id, anim );
       
   319 	i++;
       
   320     }
       
   321 
       
   322     ship = new AnimatedPixmapItem( animation[ID_SHIP], &field );
       
   323     ship->hide();
       
   324 
       
   325     shield = new KShield( animation[ID_SHIELD], &field );
       
   326     shield->hide();
       
   327 
       
   328     return (!ship->image(0).isNull() && !shield->image(0).isNull());
       
   329 }
       
   330 
       
   331 // - - -
       
   332 
       
   333 void KAsteroidsView::addRocks( int num )
       
   334 {
       
   335     if ( !initialized )
       
   336 	return;
       
   337     for ( int i = 0; i < num; i++ )
       
   338     {
       
   339 	KRock *rock = new KRock( animation[ID_ROCK_LARGE], &field,
       
   340 			     ID_ROCK_LARGE, randInt(2), randInt(2) ? -1 : 1 );
       
   341 	double dx = (2.0 - randDouble()*4.0) * rockSpeed;
       
   342 	double dy = (2.0 - randDouble()*4.0) * rockSpeed;
       
   343 	rock->setVelocity( dx, dy );
       
   344 	rock->setFrame( randInt( rock->frameCount() ) );
       
   345 	if ( dx > 0 )
       
   346 	{
       
   347 	    if ( dy > 0 )
       
   348 		rock->setPos( 5, 5 );
       
   349 	    else
       
   350 		rock->setPos( 5, field.height() - 25 );
       
   351             rock->setFrame( 0 );
       
   352 	}
       
   353 	else
       
   354 	{
       
   355 	    if ( dy > 0 )
       
   356 		rock->setPos( field.width() - 25, 5 );
       
   357 	    else
       
   358 		rock->setPos( field.width() - 25, field.height() - 25 );
       
   359             rock->setFrame( 0 );
       
   360 	}
       
   361 	rock->show();
       
   362 	rocks.append( rock );
       
   363     }
       
   364 }
       
   365 
       
   366 // - - -
       
   367 
       
   368 void KAsteroidsView::showText( const QString &text, const QColor &color, bool scroll )
       
   369 {
       
   370     if ( !initialized )
       
   371 	return;
       
   372     textSprite->setHtml( QString("<font color=#%1%2%3>%4</font>")
       
   373                          .arg(color.red(), 2, 16, QLatin1Char('0'))
       
   374                          .arg(color.green(), 2, 16, QLatin1Char('0'))
       
   375                          .arg(color.blue(), 2, 16, QLatin1Char('0'))
       
   376                          .arg(text) );
       
   377     Q_UNUSED(color);
       
   378     // ### Porting: no such thing textSprite->setColor( color );
       
   379 
       
   380     if ( scroll ) {
       
   381 	textSprite->setPos( (field.width()-textSprite->boundingRect().width()) / 2,
       
   382 			    -textSprite->boundingRect().height() );
       
   383 	textDy = TEXT_SPEED;
       
   384     } else {
       
   385 	textSprite->setPos( (field.width()-textSprite->boundingRect().width()) / 2,
       
   386                             (field.height()-textSprite->boundingRect().height()) / 2 );
       
   387 	textDy = 0;
       
   388     }
       
   389     textSprite->show();
       
   390 }
       
   391 
       
   392 // - - -
       
   393 
       
   394 void KAsteroidsView::hideText()
       
   395 {
       
   396     textDy = -TEXT_SPEED;
       
   397 }
       
   398 
       
   399 // - - -
       
   400 
       
   401 void KAsteroidsView::resizeEvent(QResizeEvent* event)
       
   402 {
       
   403     QWidget::resizeEvent(event);
       
   404     field.setSceneRect(0, 0, width()-4, height()-4);
       
   405     view.resize(width(),height());
       
   406 }
       
   407 
       
   408 // - - -
       
   409 
       
   410 void KAsteroidsView::timerEvent( QTimerEvent * )
       
   411 {
       
   412     field.advance();
       
   413 
       
   414     AnimatedPixmapItem *rock;
       
   415 
       
   416     // move rocks forward
       
   417     for ( rock = rocks.first(); rock; rock = rocks.next() ) {
       
   418 	((KRock *)rock)->nextFrame();
       
   419 	wrapSprite( rock );
       
   420     }
       
   421 
       
   422     wrapSprite( ship );
       
   423 
       
   424     // check for missile collision with rocks.
       
   425     processMissiles();
       
   426 
       
   427     // these are generated when a ship explodes
       
   428     for ( KBit *bit = bits.first(); bit; bit = bits.next() )
       
   429     {
       
   430 	if ( bit->expired() )
       
   431 	{
       
   432 	    bits.removeRef( bit );
       
   433 	}
       
   434 	else
       
   435 	{
       
   436 	    bit->growOlder();
       
   437 	    bit->setFrame( ( bit->frame()+1 ) % bit->frameCount() );
       
   438 	}
       
   439     }
       
   440 
       
   441     for ( KExhaust *e = exhaust.first(); e; e = exhaust.next() )
       
   442 	exhaust.removeRef( e );
       
   443 
       
   444     // move / rotate ship.
       
   445     // check for collision with a rock.
       
   446     processShip();
       
   447 
       
   448     // move powerups and check for collision with player and missiles
       
   449     processPowerups();
       
   450 
       
   451     if ( textSprite->isVisible() )
       
   452     {
       
   453 	if ( textDy < 0 &&
       
   454 	     textSprite->boundingRect().y() <= -textSprite->boundingRect().height() ) {
       
   455 	    textSprite->hide();
       
   456 	} else {
       
   457 	    textSprite->moveBy( 0, textDy );
       
   458 	}
       
   459 
       
   460 	if ( textSprite->sceneBoundingRect().y() > (field.height()-textSprite->boundingRect().height())/2 )
       
   461 	    textDy = 0;
       
   462     }
       
   463 
       
   464     if ( vitalsChanged && !(mFrameNum % 10) ) {
       
   465 	emit updateVitals();
       
   466 	vitalsChanged = FALSE;
       
   467     }
       
   468 
       
   469     mFrameNum++;
       
   470 }
       
   471 
       
   472 void KAsteroidsView::wrapSprite( QGraphicsItem *s )
       
   473 {
       
   474     int x = int(s->x() + s->boundingRect().width() / 2);
       
   475     int y = int(s->y() + s->boundingRect().height() / 2);
       
   476 
       
   477     if ( x > field.width() )
       
   478 	s->setPos( s->x() - field.width(), s->y() );
       
   479     else if ( x < 0 )
       
   480 	s->setPos( field.width() + s->x(), s->y() );
       
   481 
       
   482     if ( y > field.height() )
       
   483 	s->setPos( s->x(), s->y() - field.height() );
       
   484     else if ( y < 0 )
       
   485 	s->setPos( s->x(), field.height() + s->y() );
       
   486 }
       
   487 
       
   488 // - - -
       
   489 
       
   490 void KAsteroidsView::rockHit( AnimatedPixmapItem *hit )
       
   491 {
       
   492     KPowerup *nPup = 0;
       
   493     int rnd = int(randDouble()*30.0) % 30;
       
   494     switch( rnd )
       
   495     {
       
   496       case 4:
       
   497       case 5:
       
   498           nPup = new KPowerup( animation[ID_ENERGY_POWERUP], &field,
       
   499                                ID_ENERGY_POWERUP );
       
   500 	break;
       
   501       case 10:
       
   502 //        nPup = new KPowerup( animation[ID_TELEPORT_POWERUP], &field,
       
   503 //                             ID_TELEPORT_POWERUP );
       
   504 	break;
       
   505       case 15:
       
   506           nPup = new KPowerup( animation[ID_BRAKE_POWERUP], &field,
       
   507                                ID_BRAKE_POWERUP );
       
   508 	break;
       
   509       case 20:
       
   510           nPup = new KPowerup( animation[ID_SHIELD_POWERUP], &field,
       
   511                                ID_SHIELD_POWERUP );
       
   512 	break;
       
   513       case 24:
       
   514       case 25:
       
   515           nPup = new KPowerup( animation[ID_SHOOT_POWERUP], &field,
       
   516                                ID_SHOOT_POWERUP );
       
   517 	break;
       
   518     }
       
   519     if ( nPup )
       
   520     {
       
   521 	double r = 0.5 - randDouble();
       
   522 	nPup->setPos( hit->x(), hit->y() );
       
   523         nPup->setFrame( 0 );
       
   524 	nPup->setVelocity( hit->xVelocity() + r, hit->yVelocity() + r );
       
   525 	powerups.append( nPup );
       
   526     }
       
   527 
       
   528     if ( hit->type() == ID_ROCK_LARGE || hit->type() == ID_ROCK_MEDIUM )
       
   529     {
       
   530 	// break into smaller rocks
       
   531 	double addx[4] = { 1.0, 1.0, -1.0, -1.0 };
       
   532 	double addy[4] = { -1.0, 1.0, -1.0, 1.0 };
       
   533 
       
   534 	double dx = hit->xVelocity();
       
   535 	double dy = hit->yVelocity();
       
   536 
       
   537 	double maxRockSpeed = MAX_ROCK_SPEED * rockSpeed;
       
   538 	if ( dx > maxRockSpeed )
       
   539 	    dx = maxRockSpeed;
       
   540 	else if ( dx < -maxRockSpeed )
       
   541 	    dx = -maxRockSpeed;
       
   542 	if ( dy > maxRockSpeed )
       
   543 	    dy = maxRockSpeed;
       
   544 	else if ( dy < -maxRockSpeed )
       
   545 	    dy = -maxRockSpeed;
       
   546 
       
   547 	AnimatedPixmapItem *nrock;
       
   548 
       
   549 	for ( int i = 0; i < 4; i++ )
       
   550 	{
       
   551 	    double r = rockSpeed/2 - randDouble()*rockSpeed;
       
   552 	    if ( hit->type() == ID_ROCK_LARGE )
       
   553 	    {
       
   554 		nrock = new KRock( animation[ID_ROCK_MEDIUM], &field,
       
   555                                    ID_ROCK_MEDIUM, randInt(2), randInt(2) ? -1 : 1 );
       
   556 		emit rockHit( 0 );
       
   557 	    }
       
   558 	    else
       
   559 	    {
       
   560 		nrock = new KRock( animation[ID_ROCK_SMALL], &field,
       
   561                                    ID_ROCK_SMALL, randInt(2), randInt(2) ? -1 : 1 );
       
   562 		emit rockHit( 1 );
       
   563 	    }
       
   564 
       
   565 	    nrock->setPos( hit->x(), hit->y() );
       
   566             nrock->setFrame( 0 );
       
   567 	    nrock->setVelocity( dx+addx[i]*rockSpeed+r, dy+addy[i]*rockSpeed+r );
       
   568 	    nrock->setFrame( randInt( nrock->frameCount() ) );
       
   569 	    rocks.append( nrock );
       
   570 	}
       
   571     }
       
   572     else if ( hit->type() == ID_ROCK_SMALL )
       
   573 	emit rockHit( 2 );
       
   574     rocks.removeRef( hit );
       
   575     if ( rocks.count() == 0 )
       
   576 	emit rocksRemoved();
       
   577 }
       
   578 
       
   579 void KAsteroidsView::reducePower( int val )
       
   580 {
       
   581     shipPower -= val;
       
   582     if ( shipPower <= 0 )
       
   583     {
       
   584 	shipPower = 0;
       
   585 	thrustShip = FALSE;
       
   586 	if ( shieldOn )
       
   587 	{
       
   588 	    shieldOn = FALSE;
       
   589 	    shield->hide();
       
   590 	}
       
   591     }
       
   592     vitalsChanged = TRUE;
       
   593 }
       
   594 
       
   595 void KAsteroidsView::addExhaust( double x, double y, double dx,
       
   596 				 double dy, int count )
       
   597 {
       
   598     for ( int i = 0; i < count; i++ )
       
   599     {
       
   600 	KExhaust *e = new KExhaust( animation[ID_EXHAUST], &field );
       
   601 	e->setPos( x + 2 - randDouble()*4, y + 2 - randDouble()*4 );
       
   602 	e->setVelocity( dx, dy );
       
   603 	exhaust.append( e );
       
   604     }
       
   605 }
       
   606 
       
   607 void KAsteroidsView::processMissiles()
       
   608 {
       
   609     KMissile *missile;
       
   610 
       
   611     // if a missile has hit a rock, remove missile and break rock into smaller
       
   612     // rocks or remove completely.
       
   613     Q3PtrListIterator<KMissile> it(missiles);
       
   614 
       
   615     for ( ; it.current(); ++it )
       
   616     {
       
   617 	missile = it.current();
       
   618 	missile->growOlder();
       
   619 
       
   620 	if ( missile->expired() )
       
   621 	{
       
   622 	    missiles.removeRef( missile );
       
   623 	    continue;
       
   624 	}
       
   625 
       
   626 	wrapSprite( missile );
       
   627 
       
   628 	QList<QGraphicsItem *> hits = missile->collidingItems(Qt::IntersectsItemBoundingRect);
       
   629 	QList<QGraphicsItem *>::Iterator hit;
       
   630 	for ( hit = hits.begin(); hit != hits.end(); ++hit )
       
   631 	{
       
   632 	    if ( (*hit)->type() >= ID_ROCK_LARGE &&
       
   633 		 (*hit)->type() <= ID_ROCK_SMALL && (*hit)->collidesWithItem(missile) )
       
   634 	    {
       
   635                 shotsHit++;
       
   636                 rockHit( static_cast<AnimatedPixmapItem *>(*hit) );
       
   637                 missiles.removeRef( missile );
       
   638                 break;
       
   639 	    }
       
   640 	}
       
   641     }
       
   642 }
       
   643 
       
   644 // - - -
       
   645 
       
   646 void KAsteroidsView::processShip()
       
   647 {
       
   648     if ( ship->isVisible() )
       
   649     {
       
   650 	if ( shieldOn )
       
   651 	{
       
   652 	    shield->show();
       
   653 	    reducePower( SHIELD_ON_COST );
       
   654 	    static int sf = 0;
       
   655 	    sf++;
       
   656 
       
   657 	    if ( sf % 2 )
       
   658 		shield->setFrame( (shield->frame()+1) % shield->frameCount() );
       
   659 	    shield->setPos( ship->x() - 9, ship->y() - 9 );
       
   660 
       
   661 	    QList<QGraphicsItem *> hits = shield->collidingItems(Qt::IntersectsItemBoundingRect);
       
   662 	    QList<QGraphicsItem *>::Iterator it;
       
   663 	    for ( it = hits.begin(); it != hits.end(); ++it )
       
   664 	    {
       
   665 		if ( (*it)->type() >= ID_ROCK_LARGE &&
       
   666 		     (*it)->type() <= ID_ROCK_SMALL && (*it)->collidesWithItem(shield) )
       
   667 		{
       
   668 		    int factor;
       
   669 		    switch ( (*it)->type() )
       
   670 		    {
       
   671 			case ID_ROCK_LARGE:
       
   672 			    factor = 3;
       
   673 			    break;
       
   674 
       
   675 			case ID_ROCK_MEDIUM:
       
   676 			    factor = 2;
       
   677 			    break;
       
   678 
       
   679 			default:
       
   680 			    factor = 1;
       
   681 		    }
       
   682 
       
   683 		    if ( factor > mShieldCount )
       
   684 		    {
       
   685 			// shield not strong enough
       
   686 			shieldOn = FALSE;
       
   687 			break;
       
   688 		    }
       
   689 		    rockHit( static_cast<AnimatedPixmapItem *>(*it) );
       
   690 		    // the more shields we have the less costly
       
   691 		    reducePower( factor * (SHIELD_HIT_COST - mShieldCount*2) );
       
   692 		}
       
   693 	    }
       
   694 	}
       
   695 
       
   696 	if ( !shieldOn )
       
   697 	{
       
   698 	    shield->hide();
       
   699 	    QList<QGraphicsItem *> hits = ship->collidingItems(Qt::IntersectsItemBoundingRect);
       
   700 	    QList<QGraphicsItem *>::Iterator it;
       
   701 	    for ( it = hits.begin(); it != hits.end(); ++it )
       
   702 	    {
       
   703 		if ( (*it)->type() >= ID_ROCK_LARGE &&
       
   704 		     (*it)->type() <= ID_ROCK_SMALL && (*it)->collidesWithItem(ship))
       
   705 		{
       
   706 		    KBit *bit;
       
   707 		    for ( int i = 0; i < 12; i++ )
       
   708 		    {
       
   709                       bit = new KBit( animation[ID_BIT], &field );
       
   710 		      bit->setPos( ship->x() + 5 - randDouble() * 10,
       
   711                                    ship->y() + 5 - randDouble() * 10 );
       
   712                       bit->setFrame( randInt(bit->frameCount()) );
       
   713 		      bit->setVelocity( 1-randDouble()*2,
       
   714 					1-randDouble()*2 );
       
   715 		      bit->setDeath( 60 + randInt(60) );
       
   716 		      bits.append( bit );
       
   717 		    }
       
   718 		    ship->hide();
       
   719 		    shield->hide();
       
   720 		    emit shipKilled();
       
   721 		    break;
       
   722 		}
       
   723 	    }
       
   724 	}
       
   725 
       
   726 
       
   727 	if ( rotateSlow )
       
   728 	    rotateSlow--;
       
   729 
       
   730 	if ( rotateL )
       
   731 	{
       
   732 	    shipAngle -= rotateSlow ? 1 : rotateRate;
       
   733 	    if ( shipAngle < 0 )
       
   734 		shipAngle += SHIP_STEPS;
       
   735 	}
       
   736 
       
   737 	if ( rotateR )
       
   738 	{
       
   739 	    shipAngle += rotateSlow ? 1 : rotateRate;
       
   740 	    if ( shipAngle >= SHIP_STEPS )
       
   741 		shipAngle -= SHIP_STEPS;
       
   742 	}
       
   743 
       
   744 	double angle = shipAngle * PI_X_2 / SHIP_STEPS;
       
   745 	double cosangle = cos( angle );
       
   746 	double sinangle = sin( angle );
       
   747 
       
   748 	if ( brakeShip )
       
   749 	{
       
   750 	    thrustShip = FALSE;
       
   751 	    rotateL = FALSE;
       
   752 	    rotateR = FALSE;
       
   753 	    rotateRate = ROTATE_RATE;
       
   754 	    if ( fabs(shipDx) < 2.5 && fabs(shipDy) < 2.5 )
       
   755 	    {
       
   756 		shipDx = 0.0;
       
   757 		shipDy = 0.0;
       
   758 		ship->setVelocity( shipDx, shipDy );
       
   759 		brakeShip = FALSE;
       
   760 	    }
       
   761 	    else
       
   762 	    {
       
   763 		double motionAngle = atan2( -shipDy, -shipDx );
       
   764 		if ( angle > M_PI )
       
   765 		    angle -= PI_X_2;
       
   766 		double angleDiff = angle - motionAngle;
       
   767 		if ( angleDiff > M_PI )
       
   768 		    angleDiff = PI_X_2 - angleDiff;
       
   769 		else if ( angleDiff < -M_PI )
       
   770 		    angleDiff = PI_X_2 + angleDiff;
       
   771 		double fdiff = fabs( angleDiff );
       
   772 		if ( fdiff > 0.08 )
       
   773 		{
       
   774 		    if ( angleDiff > 0 )
       
   775 			rotateL = TRUE;
       
   776 		    else if ( angleDiff < 0 )
       
   777 			rotateR = TRUE;
       
   778 		    if ( fdiff > 0.6 )
       
   779 			rotateRate = mBrakeCount + 1;
       
   780 		    else if ( fdiff > 0.4 )
       
   781 			rotateRate = 2;
       
   782 		    else
       
   783 			rotateRate = 1;
       
   784 
       
   785 		    if ( rotateRate > 5 )
       
   786 			rotateRate = 5;
       
   787 		}
       
   788 		else if ( fabs(shipDx) > 1 || fabs(shipDy) > 1 )
       
   789 		{
       
   790 		    thrustShip = TRUE;
       
   791 		    // we'll make braking a bit faster
       
   792 		    shipDx += cosangle/6 * (mBrakeCount - 1);
       
   793 		    shipDy += sinangle/6 * (mBrakeCount - 1);
       
   794 		    reducePower( BRAKE_ON_COST );
       
   795 		    addExhaust( ship->x() + 20 - cosangle*22,
       
   796 				ship->y() + 20 - sinangle*22,
       
   797 				shipDx-cosangle, shipDy-sinangle,
       
   798 				mBrakeCount+1 );
       
   799 		}
       
   800 	    }
       
   801 	}
       
   802 
       
   803 	if ( thrustShip )
       
   804 	{
       
   805 	    // The ship has a terminal velocity, but trying to go faster
       
   806 	    // still uses fuel (can go faster diagonally - don't care).
       
   807 	    double thrustx = cosangle/4;
       
   808 	    double thrusty = sinangle/4;
       
   809 	    if ( fabs(shipDx + thrustx) < MAX_SHIP_SPEED )
       
   810 		shipDx += thrustx;
       
   811 	    if ( fabs(shipDy + thrusty) < MAX_SHIP_SPEED )
       
   812 		shipDy += thrusty;
       
   813 	    ship->setVelocity( shipDx, shipDy );
       
   814 	    reducePower( 1 );
       
   815 	    addExhaust( ship->x() + 20 - cosangle*20,
       
   816 			ship->y() + 20 - sinangle*20,
       
   817 			shipDx-cosangle, shipDy-sinangle, 3 );
       
   818 	}
       
   819 
       
   820 	ship->setFrame( shipAngle >> 1 );
       
   821 
       
   822 	if ( shootShip )
       
   823 	{
       
   824 	    if ( !shootDelay && (int)missiles.count() < mShootCount + 2 )
       
   825 	    {
       
   826 	      KMissile *missile = new KMissile( animation[ID_MISSILE], &field );
       
   827 	      missile->setPos( 21+ship->x()+cosangle*21,
       
   828 			     21+ship->y()+sinangle*21 );
       
   829               missile->setFrame( 0 );
       
   830 	      missile->setVelocity( shipDx + cosangle*MISSILE_SPEED,
       
   831 				    shipDy + sinangle*MISSILE_SPEED );
       
   832 	      missiles.append( missile );
       
   833 	      shotsFired++;
       
   834 	      reducePower( 1 );
       
   835 
       
   836 	      shootDelay = 5;
       
   837 	    }
       
   838 
       
   839 	    if ( shootDelay )
       
   840 	      shootDelay--;
       
   841 	}
       
   842 
       
   843 	if ( teleportShip )
       
   844 	{
       
   845 	    int ra = qrand() % 10;
       
   846 	    if( ra == 0 )
       
   847 	    ra += qrand() % 20;
       
   848 	    int xra = ra * 60 + ( (qrand() % 20) * (qrand() % 20) );
       
   849 	    int yra = ra * 50 - ( (qrand() % 20) * (qrand() % 20) );
       
   850 	    ship->setPos( xra, yra );
       
   851 	}
       
   852 
       
   853 	vitalsChanged = TRUE;
       
   854     }
       
   855 }
       
   856 
       
   857 // - - -
       
   858 
       
   859 void KAsteroidsView::processPowerups()
       
   860 {
       
   861     if ( !powerups.isEmpty() )
       
   862     {
       
   863 	// if player gets the powerup remove it from the screen, if option
       
   864 	// "Can destroy powerups" is enabled and a missile hits the powerup
       
   865 	// destroy it
       
   866 
       
   867 	KPowerup *pup;
       
   868 	Q3PtrListIterator<KPowerup> it( powerups );
       
   869 
       
   870 	for( ; it.current(); ++it )
       
   871 	{
       
   872 	    pup = it.current();
       
   873 	    pup->growOlder();
       
   874 
       
   875 	    if( pup->expired() )
       
   876 	    {
       
   877 		powerups.removeRef( pup );
       
   878 		continue;
       
   879 	    }
       
   880 
       
   881 	    wrapSprite( pup );
       
   882 
       
   883 	    QList<QGraphicsItem *> hits = pup->collidingItems();
       
   884 	    QList<QGraphicsItem *>::Iterator it;
       
   885 	    for ( it = hits.begin(); it != hits.end(); ++it )
       
   886 	    {
       
   887 		if ( (*it) == ship )
       
   888 		{
       
   889 		    switch( pup->type() )
       
   890 		    {
       
   891 		      case ID_ENERGY_POWERUP:
       
   892 			shipPower += 150;
       
   893 			if ( shipPower > MAX_POWER_LEVEL )
       
   894 			    shipPower = MAX_POWER_LEVEL;
       
   895 			break;
       
   896 		      case ID_TELEPORT_POWERUP:
       
   897 			mTeleportCount++;
       
   898 			break;
       
   899 		      case ID_BRAKE_POWERUP:
       
   900 			if ( mBrakeCount < MAX_BRAKES )
       
   901 			    mBrakeCount++;
       
   902 			break;
       
   903 		      case ID_SHIELD_POWERUP:
       
   904 			if ( mShieldCount < MAX_SHIELDS )
       
   905 			    mShieldCount++;
       
   906 			break;
       
   907 		      case ID_SHOOT_POWERUP:
       
   908 			if ( mShootCount < MAX_FIREPOWER )
       
   909 			    mShootCount++;
       
   910 			break;
       
   911 		    }
       
   912 
       
   913 		    powerups.removeRef( pup );
       
   914 		    vitalsChanged = TRUE;
       
   915 		}
       
   916 		else if ( (*it) == shield )
       
   917 		{
       
   918 		    powerups.removeRef( pup );
       
   919 		}
       
   920 		else if ( (*it)->type() == ID_MISSILE )
       
   921 		{
       
   922 		    if ( can_destroy_powerups )
       
   923 		    {
       
   924                         powerups.removeRef( pup );
       
   925 		    }
       
   926 		}
       
   927 	    }
       
   928 	}
       
   929     }         // -- if( powerups.isEmpty() )
       
   930 }
       
   931 
       
   932 // - - -
       
   933 
       
   934 void KAsteroidsView::hideShield()
       
   935 {
       
   936     shield->hide();
       
   937     mShieldCount = 0;
       
   938     shieldOn = FALSE;
       
   939 }
       
   940 
       
   941 double KAsteroidsView::randDouble()
       
   942 {
       
   943     int v = qrand();
       
   944     return (double)v / (double)RAND_MAX;
       
   945 }
       
   946 
       
   947 int KAsteroidsView::randInt( int range )
       
   948 {
       
   949     return qrand() % range;
       
   950 }
       
   951 
       
   952 void KAsteroidsView::showEvent( QShowEvent *e )
       
   953 {
       
   954 #if defined( QT_LICENSE_PROFESSIONAL )
       
   955     static bool wasThere = FALSE;
       
   956 
       
   957     if ( !wasThere ) {
       
   958         wasThere = TRUE;
       
   959         QMessageBox::information( this, tr("QGraphicsView demo"),
       
   960                                         tr("This game has been implemented using the QGraphicsView class.\n"
       
   961                                            "The QGraphicsView class is not part of the Light Platform Edition. Please \n"
       
   962                                            "contact Nokia if you want to upgrade to the Full Platform Edition.") );
       
   963     }
       
   964 #endif
       
   965 
       
   966     QWidget::showEvent( e );
       
   967 }