source: trunk/examples/graphicsview/portedasteroids/view.cpp@ 857

Last change on this file since 857 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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