package KAsteroidsView; =begin * KAsteroids - Copyright (c) Martin R-> Jones 1997 * * Part of the KDE project =cut use strict; use warnings; use QtCore4; use QtGui4; use QtCore4::isa qw( Qt::Widget ); use QtCore4::signals shipKilled => [], rockHit => ['int'], rocksRemoved => [], updateVitals => []; use QtCore4::slots hideShield => []; use Qt::GlobalSpace qw(qrand); use POSIX qw( RAND_MAX ); use List::MoreUtils qw(first_index); use constant { MAX_POWER_LEVEL => 1000, IMG_BACKGROUND => ':/trolltech/examples/graphicsview/portedasteroids/bg.png' }; use AnimatedPixmapItem; use Sprites; use KMissile; use KBit; use KExhaust; use KPowerup; use KRock; use KShield; sub setRockSpeed() { my ($rs) = @_; this->{rockSpeed} = $rs; } sub rotateLeft() { my ($r) = @_; this->{rotateL} = $r; this->{rotateSlow} = 5; } sub rotateRight() { my ($r) = @_; this->{rotateR} = $r; this->{rotateSlow} = 5; } sub thrust() { my ($t) = @_; this->{thrustShip} = $t && this->{shipPower} > 0; } sub shoot() { my ($s) = @_; this->{shootShip} = $s; this->{shootDelay} = 0; } sub teleport() { my ($te) = @_; this->{teleportShip} = $te && this->{mTeleportCount}; } sub shots() { return this->{shotsFired}; } sub hits() { return this->{shotsHit}; } sub power() { return this->{shipPower}; } sub teleportCount() { return this->{mTeleportCount}; } sub brakeCount() { return this->{mBrakeCount}; } sub shieldCount() { return this->{mShieldCount}; } sub shootCount() { return this->{mShootCount}; } sub refreshRate() { return this->{refreshRate}; } sub field() { return this->{field}; } sub view() { return this->{view}; } sub animation() { return this->{animation}; } sub rocks() { return this->{rocks}; } sub missiles() { return this->{missiles}; } sub bits() { return this->{bits}; } sub exhaust() { return this->{exhaust}; } sub powerups() { return this->{powerups}; } sub shield() { return this->{shield}; } sub ship() { return this->{ship}; } sub textSprite() { return this->{textSprite}; } sub rotateL() { return this->{rotateL}; } sub rotateR() { return this->{rotateR}; } sub thrustShip() { return this->{thrustShip}; } sub shootShip() { return this->{shootShip}; } sub teleportShip() { return this->{teleportShip}; } sub brakeShip() { return this->{brakeShip}; } sub pauseShip() { return this->{pauseShip}; } sub shieldOn() { return this->{shieldOn}; } sub vitalsChanged() { return this->{vitalsChanged}; } sub shipAngle() { return this->{shipAngle}; } sub rotateSlow() { return this->{rotateSlow}; } sub rotateRate() { return this->{rotateRate}; } sub shipPower() { return this->{shipPower}; } sub shotsFired() { return this->{shotsFired}; } sub shotsHit() { return this->{shotsHit}; } sub shootDelay() { return this->{shootDelay}; } sub mBrakeCount() { return this->{mBrakeCount}; } sub mShieldCount() { return this->{mShieldCount}; } sub mTeleportCount() { return this->{mTeleportCount}; } sub mShootCount() { return this->{mShootCount}; } sub shipDx() { return this->{shipDx}; } sub shipDy() { return this->{shipDy}; } sub textDy() { return this->{textDy}; } sub mFrameNum() { return this->{mFrameNum}; } sub mPaused() { return this->{mPaused}; } sub mTimerId() { return this->{mTimerId}; } sub rockSpeed() { return this->{rockSpeed}; } sub powerupSpeed() { return this->{powerupSpeed}; } sub can_destroy_powerups() { return this->{can_destroy_powerups}; } sub shieldTimer() { return this->{shieldTimer}; } sub initialized() { return this->{initialized}; } use constant { REFRESH_DELAY => 33, SHIP_SPEED => 0.3, MISSILE_SPEED => 10.0, SHIP_STEPS => 64, ROTATE_RATE => 2, SHIELD_ON_COST => 1, SHIELD_HIT_COST => 30, BRAKE_ON_COST => 4, MAX_ROCK_SPEED => 2.5, MAX_POWERUP_SPEED => 1.5, MAX_SHIP_SPEED => 12, MAX_BRAKES => 5, MAX_SHIELDS => 5, MAX_FIREPOWER => 5, TEXT_SPEED => 4, PI_X_2 => 6.283185307, M_PI => 3.141592654, }; my @kas_animations = ( { id => Sprites::ID_ROCK_LARGE, path => 'rock1/rock1%1.png', frames => 32 }, { id => Sprites::ID_ROCK_MEDIUM, path => 'rock2/rock2%1.png', frames => 32 }, { id => Sprites::ID_ROCK_SMALL, path => 'rock3/rock3%1.png', frames => 32 }, { id => Sprites::ID_SHIP, path => 'ship/ship%1.png', frames => 32 }, { id => Sprites::ID_MISSILE, path => 'missile/missile.png', frames => 1 }, { id => Sprites::ID_BIT, path => 'bits/bits%1.png', frames => 16 }, { id => Sprites::ID_EXHAUST, path => 'exhaust/exhaust.png', frames => 1 }, { id => Sprites::ID_ENERGY_POWERUP, path => 'powerups/energy.png', frames => 1 }, # { id => Sprites::ID_TELEPORT_POWERUP, path => 'powerups/teleport%1.png', frames => 12 }, { id => Sprites::ID_BRAKE_POWERUP, path => 'powerups/brake.png', frames => 1 }, { id => Sprites::ID_SHIELD_POWERUP, path => 'powerups/shield.png', frames => 1 }, { id => Sprites::ID_SHOOT_POWERUP, path => 'powerups/shoot.png', frames => 1 }, { id => Sprites::ID_SHIELD, path => 'shield/shield%1.png', frames => 6 }, { id => 0, path => 0, frames => 0 } ); sub NEW { my ($class, $parent, $name) = @_; if ( $name ) { $class->SUPER::NEW($parent, $name); } else { $class->SUPER::NEW($parent); } this->{mFrameNum} = 0; this->{mBrakeCount} = 0; this->{mShieldCount} = 0; this->{mShootCount} = 0; this->{field} = Qt::GraphicsScene( 0, 0, 640, 440 ); this->{view} = Qt::GraphicsView(field, this); view->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff() ); view->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff() ); view->setCacheMode(Qt::GraphicsView::CacheBackground()); view->setViewportUpdateMode(Qt::GraphicsView::BoundingRectViewportUpdate()); view->setOptimizationFlags(Qt::GraphicsView::DontClipPainter() | Qt::GraphicsView::DontSavePainterState() | Qt::GraphicsView::DontAdjustForAntialiasing()); view->viewport()->setFocusProxy( this ); this->{rocks} = []; this->{missiles} = []; this->{bits} = []; this->{powerups} = []; this->{exhaust} = []; this->{animation} = []; my $pm = Qt::Pixmap( IMG_BACKGROUND ); field->setBackgroundBrush( Qt::Brush( $pm ) ); this->{textSprite} = Qt::GraphicsTextItem( undef, field ); my $font = Qt::Font( 'helvetica', 18 ); textSprite()->setFont( $font ); textSprite()->setCacheMode(Qt::GraphicsItem::DeviceCoordinateCache()); this->{shield} = 0; this->{shieldOn} = 0; this->{refreshRate} = REFRESH_DELAY; this->{initialized} = readSprites(); this->{shieldTimer} = Qt::Timer( this ); this->connect( shieldTimer, SIGNAL 'timeout()', this, SLOT 'hideShield()' ); this->{mTimerId} = -1; this->{shipPower} = MAX_POWER_LEVEL; this->{vitalsChanged} = 1; this->{can_destroy_powerups} = 0; this->{mPaused} = 1; if ( !initialized ) { textSprite()->setHtml( this->tr('Error: Cannot read sprite images') ); textSprite()->setPos( (field->width()-textSprite()->boundingRect()->width()) / 2, (field->height()-textSprite()->boundingRect()->height()) / 2 ); } } # - - - sub reset { if ( !initialized ) { return; } map { $_->scene->removeItem($_) } grep { defined } @{rocks()}, @{missiles()}, @{bits()}, @{powerups()}, @{exhaust()}; @{rocks()} = (); @{missiles()} = (); @{bits()} = (); @{powerups()} = (); @{exhaust()} = (); this->{shotsFired} = 0; this->{shotsHit} = 0; this->{rockSpeed} = 1.0; this->{powerupSpeed} = 1.0; this->{mFrameNum} = 0; this->{mPaused} = 0; ship->hide(); shield->hide(); #if ( mTimerId >= 0 ) { #killTimer( mTimerId ); #mTimerId = -1; #} } # - -- sub newGame { if ( !initialized ) { return; } if ( shieldOn ) { shield->hide(); this->{shieldOn} = 0; } this->reset(); if ( this->{mTimerId} < 0 ) { this->{mTimerId} = startTimer( REFRESH_DELAY ); } emit updateVitals(); } # - - - sub endGame { } sub pause { my ( $p ) = @_; if ( !initialized ) { return; } if ( !mPaused && $p ) { if ( mTimerId >= 0 ) { killTimer( mTimerId ); this->{mTimerId} = -1; } } elsif ( mPaused && !$p ) { this->{mTimerId} = startTimer( REFRESH_DELAY ); } this->{mPaused} = $p; } # - - - sub newShip { if ( !initialized ) { return; } ship->setPos( width()/2, height()/2 ); ship->setFrame( 0 ); shield->setPos( width()/2, height()/2 ); shield->setFrame( 0 ); ship->setVelocity( 0.0, 0.0 ); this->{shipDx} = 0; this->{shipDy} = 0; this->{shipAngle} = 0; this->{rotateL} = 0; this->{rotateR} = 0; this->{thrustShip} = 0; this->{shootShip} = 0; this->{brakeShip} = 0; this->{teleportShip} = 0; this->{shieldOn} = 1; this->{shootDelay} = 0; this->{shipPower} = MAX_POWER_LEVEL; this->{rotateRate} = ROTATE_RATE; this->{rotateSlow} = 0; this->{mBrakeCount} = 0; this->{mTeleportCount} = 0; this->{mShootCount} = 0; ship->show(); shield->show(); this->{mShieldCount} = 1; # just in case the ship appears on a rock. shieldTimer->start( 1000, 1 ); } sub setShield { my ( $s ) = @_; if ( !initialized ) { return; } if ( shieldTimer->isActive() && !$s ) { shieldTimer->stop(); hideShield(); } else { this->{shieldOn} = $s && mShieldCount; } } sub brake { my ( $b ) = @_; if ( !initialized ) { return; } if ( mBrakeCount ) { if ( brakeShip && !$b ) { this->{rotateL} = 0; this->{rotateR} = 0; this->{thrustShip} = 0; this->{rotateRate} = ROTATE_RATE; } this->{brakeShip} = $b; } } # - - - sub readSprites { my $sprites_prefix = ':/trolltech/examples/graphicsview/portedasteroids/sprites/'; my $i = 0; while ( $kas_animations[$i]->{id} ) { my @anim; my $wildcard = $sprites_prefix . $kas_animations[$i]->{path}; $wildcard =~ s/%1/*/g; my $fi = Qt::FileInfo($wildcard); foreach my $entry (@{Qt::Dir($fi->path(), $fi->fileName())->entryList()}) { push @anim, Qt::Pixmap($fi->path() . '/' . $entry); } animation->[$kas_animations[$i]->{id}] = \@anim; $i++; } this->{ship} = AnimatedPixmapItem( animation->[Sprites::ID_SHIP], field ); ship->hide(); this->{shield} = KShield( animation->[Sprites::ID_SHIELD], field ); shield->hide(); return (!ship->image(0)->isNull() && !shield->image(0)->isNull()); } # - - - sub addRocks { my ( $num ) = @_; if ( !initialized ) { return; } for ( my $i = 0; $i < $num; $i++ ) { my $rock = KRock( animation->[Sprites::ID_ROCK_LARGE], field, Sprites::ID_ROCK_LARGE, randInt(2), randInt(2) ? -1 : 1 ); my $dx = (2.0 - randDouble()*4.0) * rockSpeed; my $dy = (2.0 - randDouble()*4.0) * rockSpeed; $rock->setVelocity( $dx, $dy ); $rock->setFrame( randInt( $rock->frameCount() ) ); if ( $dx > 0 ) { if ( $dy > 0 ) { $rock->setPos( 5, 5 ); } else { $rock->setPos( 5, field->height() - 25 ); $rock->setFrame( 0 ); } } else { if ( $dy > 0 ) { $rock->setPos( field->width() - 25, 5 ); } else { $rock->setPos( field->width() - 25, field->height() - 25 ); $rock->setFrame( 0 ); } } $rock->show(); push @{rocks()}, $rock; } } # - - - sub showText { my ( $text, $color, $scroll ) = @_; if ( !defined $scroll ) { $scroll = 1; } if ( !initialized ) { return; } textSprite()->setHtml( sprintf '%s', $color->red(), $color->green(), $color->blue(), $text ); # ### Porting: no such thing textSprite()->setColor( color ); if ( $scroll ) { textSprite()->setPos( (field->width() - textSprite()->boundingRect()->width()) / 2, -textSprite()->boundingRect()->height() ); this->{textDy} = TEXT_SPEED; } else { textSprite()->setPos( (field->width() - textSprite()->boundingRect()->width()) / 2, (field->height() - textSprite()->boundingRect()->height()) / 2 ); this->{textDy} = 0; } textSprite()->show(); } # - - - sub hideText { this->{textDy} = -TEXT_SPEED(); } # - - - sub resizeEvent { my ($event) = @_; Qt::Widget::resizeEvent($event); field->setSceneRect(0, 0, width()-4, height()-4); view->resize(width(),height()); } # - - - sub timerEvent { # XXX why is this necessary? field->update(); field->advance(); # move rocks forward foreach my $rock ( @{rocks()} ) { $rock->nextFrame(); wrapSprite( $rock ); } wrapSprite( ship ); # check for missile collision with rocks. processMissiles(); # these are generated when a ship explodes for( my $it = 0; $it < @{bits()}; ) { my $bit = bits()->[$it]; if ( $bit->expired() ) { $bit->scene()->removeItem($bit); splice @{bits()}, $it, 1; } else { $bit->growOlder(); $bit->setFrame( ( $bit->frame()+1 ) % $bit->frameCount() ); ++$it; } } foreach my $it ( 0..$#{exhaust()} ) { my $e = exhaust()->[$it]; $e->scene()->removeItem($e); } @{exhaust()} = (); # move / rotate ship. # check for collision with a rock. processShip(); # move powerups and check for collision with player and missiles processPowerups(); if ( textSprite()->isVisible() ) { if ( textDy < 0 && textSprite()->boundingRect()->y() <= -textSprite()->boundingRect()->height() ) { textSprite()->hide(); } else { textSprite()->moveBy( 0, textDy ); } if ( textSprite()->sceneBoundingRect()->y() > (field->height()-textSprite()->boundingRect()->height())/2 ) { this->{textDy} = 0; } } if ( vitalsChanged && !(mFrameNum % 10) ) { emit updateVitals(); this->{vitalsChanged} = 0; } this->{mFrameNum}++; } sub wrapSprite { my ( $s ) = @_; my $x = sprintf '%d', ($s->x() + $s->boundingRect()->width() / 2); my $y = sprintf '%d', ($s->y() + $s->boundingRect()->height() / 2); if ( $x > field->width() ) { $s->setPos( $s->x() - field->width(), $s->y() ); } elsif ( $x < 0 ) { $s->setPos( field->width() + $s->x(), $s->y() ); } if ( $y > field->height() ) { $s->setPos( $s->x(), $s->y() - field->height() ); } elsif ( $y < 0 ) { $s->setPos( $s->x(), field->height() + $s->y() ); } } # - - - sub processRockHit { my ( $hit ) = @_; my $nPup = undef; my $rnd = sprintf '%d', (randDouble()*30.0) % 30; if ($rnd == 4 || $rnd == 5) { $nPup = KPowerup( animation->[Sprites::ID_ENERGY_POWERUP], field, Sprites::ID_ENERGY_POWERUP ); } elsif ($rnd == 10) { # Commented out in C++ # $nPup = KPowerup( animation->[Sprites::ID_TELEPORT_POWERUP], &field, # Sprites::ID_TELEPORT_POWERUP ); } elsif ($rnd == 15) { $nPup = KPowerup( animation->[Sprites::ID_BRAKE_POWERUP], field, Sprites::ID_BRAKE_POWERUP ); } elsif ($rnd == 20) { $nPup = KPowerup( animation->[Sprites::ID_SHIELD_POWERUP], field, Sprites::ID_SHIELD_POWERUP ); } elsif ($rnd == 24 || $rnd == 25) { $nPup = KPowerup( animation->[Sprites::ID_SHOOT_POWERUP], field, Sprites::ID_SHOOT_POWERUP ); } if ( $nPup ) { my $r = 0.5 - randDouble(); $nPup->setPos( $hit->x(), $hit->y() ); $nPup->setFrame( 0 ); $nPup->setVelocity( $hit->xVelocity() + $r, $hit->yVelocity() + $r ); push @{this->{powerups}}, $nPup; } if ( $hit->type() == Sprites::ID_ROCK_LARGE || $hit->type() == Sprites::ID_ROCK_MEDIUM ) { # break into smaller rocks my @addx = ( 1.0, 1.0, -1.0, -1.0 ); my @addy = ( -1.0, 1.0, -1.0, 1.0 ); my $dx = $hit->xVelocity(); my $dy = $hit->yVelocity(); my $maxRockSpeed = MAX_ROCK_SPEED * rockSpeed(); if ( $dx > $maxRockSpeed ) { $dx = $maxRockSpeed; } elsif ( $dx < -$maxRockSpeed ) { $dx = -$maxRockSpeed; } if ( $dy > $maxRockSpeed ) { $dy = $maxRockSpeed; } elsif ( $dy < -$maxRockSpeed ) { $dy = -$maxRockSpeed; } my $nrock; for ( my $i = 0; $i < 4; $i++ ) { my $r = rockSpeed()/2 - randDouble()*rockSpeed(); if ( $hit->type() == Sprites::ID_ROCK_LARGE ) { $nrock = KRock( animation->[Sprites::ID_ROCK_MEDIUM], field, Sprites::ID_ROCK_MEDIUM, randInt(2), randInt(2) ? -1 : 1 ); emit rockHit( 0 ); } else { $nrock = KRock( animation->[Sprites::ID_ROCK_SMALL], field, Sprites::ID_ROCK_SMALL, randInt(2), randInt(2) ? -1 : 1 ); emit rockHit( 1 ); } $nrock->setPos( $hit->x(), $hit->y() ); $nrock->setFrame( 0 ); $nrock->setVelocity( $dx+$addx[$i]*rockSpeed()+$r, $dy+$addy[$i]*rockSpeed()+$r ); $nrock->setFrame( randInt( $nrock->frameCount() ) ); push @{rocks()}, $nrock; } } elsif ( $hit->type() == Sprites::ID_ROCK_SMALL ) { emit rockHit( 2 ); } $hit->scene()->removeItem($hit); splice @{rocks()}, (first_index{$hit==$_} @{rocks()}), 1; if ( scalar @{rocks()} == 0 ) { emit rocksRemoved(); } } sub reducePower { my ( $val ) = @_; this->{shipPower} -= $val; if ( shipPower <= 0 ) { this->{shipPower} = 0; this->{thrustShip} = 0; if ( shieldOn ) { this->{shieldOn} = 0; shield->hide(); } } this->{vitalsChanged} = 1; } sub addExhaust { my ( $x, $y, $dx, $dy, $count ) = @_; for ( my $i = 0; $i < $count; $i++ ) { my $e = KExhaust( animation->[Sprites::ID_EXHAUST], field ); $e->setPos( $x + 2 - randDouble()*4, $y + 2 - randDouble()*4 ); $e->setVelocity( $dx, $dy ); push @{exhaust()}, $e; } } sub processMissiles { my $missile; # if a missile has hit a rock, remove missile and break rock into smaller # rocks or remove completely. for( my $it = 0; $it < @{missiles()}; ) { $missile = missiles()->[$it]; $missile->growOlder(); if ( $missile->expired() ) { $missile->scene()->removeItem($missile); splice @{missiles()}, $it, 1; next; } wrapSprite( $missile ); my $hits = $missile->collidingItems(Qt::IntersectsItemBoundingRect()); foreach my $hit ( @{$hits} ) { if ( $hit->type() >= Sprites::ID_ROCK_LARGE && $hit->type() <= Sprites::ID_ROCK_SMALL && $hit->collidesWithItem($missile) ) { this->{shotsHit}++; processRockHit( $hit ); splice @{missiles()}, $it, 1; last; } } ++$it; } } # - - - my $sf = 0; sub processShip { if ( ship->isVisible() ) { if ( shieldOn ) { shield->show(); reducePower( SHIELD_ON_COST ); $sf++; if ( $sf % 2 ) { shield->setFrame( (shield->frame()+1) % shield->frameCount() ); } shield->setPos( ship->x() - 9, ship->y() - 9 ); my $hits = shield->collidingItems(Qt::IntersectsItemBoundingRect()); #Qt::List::Iterator it; #for ( it = hits->begin(); it != hits->end(); ++it ) foreach my $it ( @{$hits} ) { if ( $it->type() >= Sprites::ID_ROCK_LARGE && $it->type() <= Sprites::ID_ROCK_SMALL && $it->collidesWithItem(shield) ) { my $factor; if ( $it->type() == Sprites::ID_ROCK_LARGE ) { $factor = 3; } elsif ( $it->type() == Sprites::ID_ROCK_MEDIUM ) { $factor = 2; } else { $factor = 1; } if ( $factor > mShieldCount ) { # shield not strong enough this->{shieldOn} = 0; last; } processRockHit( $it ); # the more shields we have the less costly reducePower( $factor * (SHIELD_HIT_COST - mShieldCount*2) ); } } } if ( !shieldOn ) { shield->hide(); my $hits = ship->collidingItems(Qt::IntersectsItemBoundingRect()); #Qt::List::Iterator it; #for ( it = hits->begin(); it != hits->end(); ++it ) foreach my $it ( @{$hits} ) { if ( $it->type() >= Sprites::ID_ROCK_LARGE && $it->type() <= Sprites::ID_ROCK_SMALL && $it->collidesWithItem(ship) ) { my $bit; for ( my $i = 0; $i < 12; $i++ ) { $bit = KBit( animation->[Sprites::ID_BIT], field ); $bit->setPos( ship->x() + 5 - randDouble() * 10, ship->y() + 5 - randDouble() * 10 ); $bit->setFrame( randInt($bit->frameCount()) ); $bit->setVelocity( 1-randDouble()*2, 1-randDouble()*2 ); $bit->setDeath( 60 + randInt(60) ); push @{bits()}, $bit; } ship->hide(); shield->hide(); emit shipKilled(); last; } } } if ( rotateSlow ) { this->{rotateSlow}--; } if ( rotateL ) { this->{shipAngle} -= rotateSlow ? 1 : rotateRate; if ( shipAngle < 0 ) { this->{shipAngle} += SHIP_STEPS; } } if ( rotateR ) { this->{shipAngle} += rotateSlow ? 1 : rotateRate; if ( shipAngle >= SHIP_STEPS ) { this->{shipAngle} -= SHIP_STEPS; } } my $angle = shipAngle * PI_X_2 / SHIP_STEPS; my $cosangle = cos( $angle ); my $sinangle = sin( $angle ); if ( brakeShip ) { this->{thrustShip} = 0; this->{rotateL} = 0; this->{rotateR} = 0; this->{rotateRate} = ROTATE_RATE; if ( abs(shipDx) < 2.5 && abs(shipDy) < 2.5 ) { this->{shipDx} = 0.0; this->{shipDy} = 0.0; ship->setVelocity( shipDx, shipDy ); this->{brakeShip} = 0; } else { my $motionAngle = atan2( -shipDy(), -shipDx() ); if ( $angle > M_PI ) { $angle -= PI_X_2; } my $angleDiff = $angle - $motionAngle; if ( $angleDiff > M_PI ) { $angleDiff = PI_X_2 - $angleDiff; } elsif ( $angleDiff < -M_PI() ) { $angleDiff = PI_X_2 + $angleDiff; } my $fdiff = abs( $angleDiff ); if ( $fdiff > 0.08 ) { if ( $angleDiff > 0 ) { this->{rotateL} = 1; } elsif ( $angleDiff < 0 ) { this->{rotateR} = 1; } if ( $fdiff > 0.6 ) { this->{rotateRate} = mBrakeCount + 1; } elsif ( $fdiff > 0.4 ) { this->{rotateRate} = 2; } else { this->{rotateRate} = 1; } if ( rotateRate > 5 ) { this->{rotateRate} = 5; } } elsif ( abs(shipDx) > 1 || abs(shipDy) > 1 ) { this->{thrustShip} = 1; # we'll make braking a bit faster this->{shipDx} += $cosangle/6 * (mBrakeCount - 1); this->{shipDy} += $sinangle/6 * (mBrakeCount - 1); reducePower( BRAKE_ON_COST ); addExhaust( ship->x() + 20 - $cosangle*22, ship->y() + 20 - $sinangle*22, shipDx-$cosangle, shipDy-$sinangle, mBrakeCount+1 ); } } } if ( thrustShip ) { # The ship has a terminal velocity, but trying to go faster # still uses fuel (can go faster diagonally - don't care). my $thrustx = $cosangle/4; my $thrusty = $sinangle/4; if ( abs(shipDx + $thrustx) < MAX_SHIP_SPEED ) { this->{shipDx} += $thrustx; } if ( abs(shipDy + $thrusty) < MAX_SHIP_SPEED ) { this->{shipDy} += $thrusty; } ship->setVelocity( shipDx, shipDy ); reducePower( 1 ); addExhaust( ship->x() + 20 - $cosangle*20, ship->y() + 20 - $sinangle*20, shipDx-$cosangle, shipDy-$sinangle, 3 ); } ship->setFrame( shipAngle >> 1 ); if ( shootShip ) { if ( !shootDelay && scalar @{missiles()} < mShootCount + 2 ) { my $missile = KMissile( animation->[Sprites::ID_MISSILE], field ); $missile->setPos( 21+ship->x()+$cosangle*21, 21+ship->y()+$sinangle*21 ); $missile->setFrame( 0 ); $missile->setVelocity( shipDx + $cosangle*MISSILE_SPEED, shipDy + $sinangle*MISSILE_SPEED ); push @{missiles()}, $missile; this->{shotsFired}++; reducePower( 1 ); this->{shootDelay} = 5; } if ( shootDelay ) { this->{shootDelay}--; } } if ( teleportShip ) { my $ra = qrand() % 10; if( $ra == 0 ) { $ra += qrand() % 20; } my $xra = $ra * 60 + ( (qrand() % 20) * (qrand() % 20) ); my $yra = $ra * 50 - ( (qrand() % 20) * (qrand() % 20) ); ship->setPos( $xra, $yra ); } this->{vitalsChanged} = 1; } } # - - - sub processPowerups { if ( scalar @{powerups()} ) { # if player gets the powerup remove it from the screen, if option # 'Can destroy powerups' is enabled and a missile hits the powerup # destroy it my $pup; for( my $it = 0; $it < @{powerups()}; ) { $pup = powerups()->[$it]; $pup->growOlder(); if( $pup->expired() ) { $pup->scene()->removeItem($pup); splice @{powerups()}, $it, 1; next; } wrapSprite( $pup ); my $hits = $pup->collidingItems(); #Qt::List::Iterator it; #for ( $it2 = hits->begin(); $it2 != hits->end(); ++$it2 ) foreach my $it2 ( @{$hits} ) { if ( $it2 == ship() ) { if ( $pup->type() == Sprites::ID_ENERGY_POWERUP ) { this->{shipPower} += 150; if ( shipPower > MAX_POWER_LEVEL ) { this->{shipPower} = MAX_POWER_LEVEL; } } elsif ( $pup->type() == Sprites::ID_TELEPORT_POWERUP ) { this->{mTeleportCount}++; } elsif ( $pup->type() == Sprites::ID_BRAKE_POWERUP ) { if ( mBrakeCount < MAX_BRAKES ) { this->{mBrakeCount}++; } } elsif ( $pup->type() == Sprites::ID_SHIELD_POWERUP ) { if ( mShieldCount < MAX_SHIELDS ) { this->{mShieldCount}++; } } elsif ( $pup->type() == Sprites::ID_SHOOT_POWERUP ) { if ( mShootCount < MAX_FIREPOWER ) { this->{mShootCount}++; } } $pup->scene()->removeItem($pup); splice @{powerups()}, $it, 1; this->{vitalsChanged} = 1; next; } elsif ( $it2 == shield ) { $pup->scene()->removeItem($pup); splice @{powerups()}, $it, 1; next; } elsif ( $it2->type() == Sprites::ID_MISSILE ) { if ( can_destroy_powerups ) { $pup->scene()->removeItem($pup); splice @{powerups()}, $it, 1; next; } } } ++$it; } } # -- if( powerups->isEmpty() ) } # - - - sub hideShield { shield->hide(); this->{mShieldCount} = 0; this->{shieldOn} = 0; } sub randDouble { my $v = qrand(); return $v / RAND_MAX; } sub randInt { my ( $range ) = @_; return qrand() % $range; } #void KAsteroidsView::showEvent( Qt::ShowEvent *e ) #{ #if defined( Qt::T_LICENSE_PROFESSIONAL ) #static bool wasThere = 0; #if ( !wasThere ) { #wasThere = 1; #Qt::MessageBox::information( this, this->tr('Qt::GraphicsView demo'), #this->tr('This game has been implemented using the Qt::GraphicsView class.\n' #'The Qt::GraphicsView class is not part of the Light Platform Edition. Please \n' #'contact Nokia if you want to upgrade to the Full Platform Edition.') ); #} #endif #Qt::Widget::showEvent( e ); #} 1;