Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Perl Missile Defense with Radar

by zentara (Archbishop)
on Dec 02, 2004 at 20:36 UTC ( #411938=sourcecode: print w/replies, xml ) Need Help??
Category: Fun Stuff
Author/Contact Info zentara
Description: Building upon the successful and profitable Perl Missile Defense Shield , I have added a Mach 1 "fully automated radar fire control", which can be used as a "pause" button. :-)

UPDATE1: Added "sound on/off".

UPDATE2: Fixed "bug" where shells didn't destroy themselves when hitting target.

#!/usr/bin/perl
use warnings;
use strict;
use Tk;

# by zentara of perlmonks  
# Up and Down Arrows  adjust firing power at battery expense.   
# Left and Right keys rotate turret.   
# Spacebar fires.  
# 's' key turns sound on/off 
# If one warhead hits the ground, it's over.   
# Ammo is limited to 500  
# There are 100 incoming missles possible.   
# Batteries are recharged by Solar Panels.  
# Kludged a way to rotate, Tk::Zinc would be better  
#  to do this.  
# this  Mach1 version adds radar-fire-control  
# which can be used for pause  
# fixed bug where shells didn't explode with target 

my $mw = MainWindow->new(-bg=>'black');
$mw->geometry('+100+100');

my $height = 400;
my $width  = 600;

# first create a canvas widget  
my $canvas = $mw->Canvas(
    -height => $height,
    -width  => $width,
    -bg     => 'black',
)->pack();

my $turret = $canvas->createOval(
    $width / 2 - 50, $height - 50, $width / 2 + 50, $height + 50,
    -fill   => 'steelblue',
    -tags => ['turret']
);

my $px0 = $width/2;
my $py0 = $height;
my $px = $width/2;
my $py = $height-65;
my $px_new = $px;
my $py_new = $py;

my $angle = 1.57; # pi divided by 2, 90 degrees in radians  
my $power = 50;
my $status = '  Ready  ';

my %projectile;
my %missle;
my $launcher;
my @ammo = (1..15);   #reusable object array for projectiles  
my $bat_level = 100;
my $ammo_tot = 500;
my $missles_max = 100;
my @missles = (1..20); #reusable object array for missles, max in play
+  
my $hits = 0;
my %radar;  #radar variables  
$radar{'on'} = 0;
$radar{'multifirelock_set'} = 0;
$radar{'angle'} = $angle;
my $sound = 1;  #computer beep on,'s' key controls on/off 

my $cannon = $canvas->createLine(
     $px0,$py0,$px,$py,
    -width      => 10,
    -fill       => 'lightblue',
    -tags => ['cannon'],
);

$canvas->lower('cannon', 'turret');

#1 degree in rads is pi divided by 180 = .01745  
$mw->bind('<Left>',sub{ &rotate(.01745) });
$mw->bind('<Right>',sub{ &rotate(-.01745) });
$mw->bind('<Up>',sub{ &power(10) });
$mw->bind('<Down>',sub{ &power(-10) });
$mw->bind('<space>', sub{ &fire}  );
$mw->bind('<s>',sub{ if($sound == 1){$sound = 0}
                      else{$sound = 1}
                       });

my $frame = $mw->Frame(-background =>'grey45')->pack(-fill=>'x');
my $frame1 = $mw->Frame(-background =>'grey45')->pack(-fill=>'x');

$frame->Label(-text =>'Power ',
                         -bg => 'grey45',
                         -fg => 'green',
                         -borderwidth => 0)->pack(-side=>'left');

$frame->Label(-textvariable => \$power,
                         -bg => 'grey45',
                         -fg => 'green',
                         -width => 3,
                         -borderwidth => 0)->pack(-side=>'left');

$frame->Label(-text => '   ',
               -bg => 'grey45',
             -borderwidth => 0)->pack(-side=>'left');

$frame->Label(-textvariable => \$status,
                         -bg => 'grey45',
                         -fg => 'yellow',
                         -width => 15,
                         -borderwidth => 0)->pack(-side=>'left');
$frame->Label(-text => '   ',
               -bg => 'grey45',
             -borderwidth => 0)->pack(-side=>'left');

$frame->Label(-text =>'Battery Level ',
                         -bg => 'grey45',
                         -fg => 'lightblue',
                         -borderwidth => 0)->pack(-side=>'left');

$frame->Label(-textvariable => \$bat_level,
                         -bg => 'grey45',
                         -fg => 'lightblue',
                         -width =>4,
                         -borderwidth => 0)->pack(-side=>'left');

$frame->Label(-text => '   ',
               -bg => 'grey45',
             -borderwidth => 0)->pack(-side=>'left');


$frame->Label(-text =>'Ammo Supply ',
                         -bg => 'grey45',
                         -fg => 'red',
                         -borderwidth => 0)->pack(-side=>'left');

$frame->Label(-textvariable => \$ammo_tot,
                         -bg => 'grey45',
                         -fg => 'red',
                         -width => 3,
                         -borderwidth => 0)->pack(-side=>'left');

$frame->Label(-text => '   ',
               -bg => 'grey45',
             -borderwidth => 0)->pack(-side=>'left');


$frame->Label(-text =>'Hits ',
                         -bg => 'grey45',
                         -fg => 'orange',
                         -borderwidth => 0)->pack(-side=>'left');

$frame->Label(-textvariable => \$hits,
                         -bg => 'grey45',
                         -fg => 'orange',
                         -width => 3,
                         -borderwidth => 0)->pack(-side=>'left');

$frame1->Button(
    -text    => 'Exit',
    -command => sub{ exit },
    -highlightbackground =>'blue',
)->pack(-side=>'right',-padx => 3);

my $startbut;
$startbut = $frame1->Button(
       -text    => 'New Game',
       -command => sub{
                 $startbut->configure(-state=>'disabled');
                 &launch  },
      -highlightbackground =>'blue',
)->pack(-side=>'right',-padx=>3);

my $radarbut= $frame1->Button(
       -text    => 'Radar-auto-fire',
       -activebackground => 'lightyellow',
       -highlightbackground =>'blue',
       -command => sub{ &radar  },
)->pack(-side=>'left',-padx=>3);


my $solar_panel = Tk::After->new($canvas,1000,'repeat',
        sub {
        $bat_level++;
        $bat_level = sprintf "%.1f", $bat_level;

        if($bat_level > 100){ $bat_level = 100 }
        });

MainLoop();
##################################################################### 
+ 
sub launch{
  if($radar{'on'}){ $mw->bind('<space>', sub{ } )
   }else{ $mw->bind('<space>', sub{ &fire}  ) }

 $status = 'Ready';

 $launcher = Tk::After->new($canvas,1000,'repeat',
      sub {
          my $rand = int(rand(100));
          if( $rand > 70 ){ #launch  

              $missles_max--;

              if($missles_max == 0){
                 print chr(07) if $sound;
                 $status = 'You Win';
                 &restart;
               }
               
             my $misl = shift @missles;
             my $mx = int(rand $width);
             my $my = -20;

             $missle{$misl}{'warhead'} =
                    $canvas->createOval($mx-8,$my-8,$mx+8,$my+8,
                     -fill => 'yellow',
                     -tags =>['warhead'],
                     );

            my ($dx,$dy);
              $dx =  0;
              $dy = .8;

     $missle{$misl}{'repeater'} = Tk::After->new($canvas,10,'repeat',
        sub {
        $canvas->move($missle{$misl}{'warhead'}, $dx,$dy);
        my ($x,$y,$x1,$y1) = $canvas->bbox($missle{$misl}{'warhead'});
         my @overlap = $canvas->find( 'overlapping', $x,$y,$x1,$y1 );

            if(scalar @overlap > 1){
                my $des_angle = $radar{'angle'};

                if($des_angle < 1){$des_angle -= .05}  #leading fire  
                if($des_angle > 2){$des_angle += .05}

                my @tags = map{$canvas->gettags($_)} @overlap;
                    if( grep /shell/, @tags)
                       {
                        $missle{$misl}{'repeater'}->cancel;
                        $canvas->delete($missle{$misl}{'warhead'});
                        $missle{$misl} = ();
                        push @missles, $misl;
                        $hits++;
                         #cleanup shells          
                           my (@shells) = grep /\d+/, @tags;
                            foreach my $num(@shells)
                            {
                             $projectile{$num}{'repeater'}->cancel;
                             $canvas->delete($projectile{$num}{'shell'
+});
                             $projectile{$num} = ();
                             push @ammo, $num;
                            }
                     }
                     else{
                         #radar contact  
                        print chr(07) if $sound;
                        &rotate($des_angle);
                        &fire;
                        }
                        
             }          
             
           if($y > $height + 10) {
             $missle{$misl}{'repeater'}->cancel;
             $canvas->delete($missle{$misl}{'warhead'});
             $missle{$misl} = ();
             push @missles, $misl;
             print chr(07) if $sound;
                 $status = 'Uh Oh Boom';
                 &restart;
           };
      });

            }

        });

}#################################################################### 
+ 
sub fire{

return if( $radar{'multifirelock_set'} == 1); #splatter fire preventio
+n  

if((scalar @ammo == 0)||
    ($ammo_tot < 0)||
     ($bat_level < 0)) {
        print chr(07) if $sound;
        $status = 'Gun Jambed';
        return
   }

my $num = shift @ammo;

$projectile{$num}{'shell'} =
         $canvas->createOval($px_new-4,$py_new-4,$px_new+4,$py_new+4,
              -fill => 'pink',
              -tags=> ['shell', $num],
              );

$bat_level -= 1.5;
$bat_level = sprintf "%.1f",$bat_level;
$ammo_tot--;

my ($dx,$dy);
if($px_new == $px0){ $dy = -$power/10 ; $dx = 0}
   else{  $dx = cos($angle) * $power/10;
          $dy = -sin($angle)* $power/10;
 }

$projectile{$num}{'repeater'} = Tk::After->new($canvas,10,'repeat',
        sub {$canvas->move($projectile{$num}{'shell'}, $dx,$dy);
              my ($x,$y) = $canvas->bbox($projectile{$num}{'shell'});

           if($y > $height + 10 || $y < -10 || $x < -10 || $x > $width
+ +10) {
             $projectile{$num}{'repeater'}->cancel;
             $canvas->delete($projectile{$num}{'shell'});
             $projectile{$num} = ();
             push @ammo, $num;
             $status = 'Ready';
           };
      });

if( $radar{'on'}){      #prevent excessive splatter firing  
  $radar{'multifirelock_set'} = 1;
  $canvas->after(40,
       sub{
        $radar{'multifirelock_set'} = 0;
        });
  }

}
######################################################################
+###  
sub power{
my $pow = shift;
$power += $pow;
if($power < 10){$power = 10}
if($power > 100){$power = 100}
}
######################################################################
+####  
sub rotate{
 my $change = shift;

 $angle += 5*$change;  #more action for manual key control  

 if( $radar{'on'} ){ $angle = $change}

 if( $angle > 3.1 ){$angle = 3.1;return}
 if( $angle < .1 ){$angle = .1;return}
 $angle = sprintf "%.4f",$angle;
#  print "$angle\t";  

$py_new = $height - sin($angle)*65;
$px_new = ($width/2) + ( cos($angle)*65);

$canvas->delete($cannon);
$cannon = ();
$cannon = $canvas->createLine(
     $px0,$py0,$px_new,$py_new,
    -width      => 10,
    -fill       => 'lightblue',
    -tags => ['cannon'],
);

$canvas->lower('cannon', 'turret');
}
######################################################################
+###  
sub radar{

   if($radar{'on'} == 0){
        $radarbut->configure(-bg => 'lightyellow');
        $radar{'on'} = 1;
   }else{
        $radarbut->configure(-bg => 'lightgrey',);
        $radar{'on'} = 0;
    }

#----------------  
if($radar{'on'} == 1){
  $power = 100;
  $mw->bind('<space>', sub{ }  );
  $radar{'angle'} = 1.571; #90 degrees   
  $radar{'line'} =  $canvas->createLine(
                 $px0,$py0,$width/2,0,
                 -width      => 1,
                 -fill       => 'lightgrey',
                 -dash   =>  [2,4],
                 -tags => ['radar'],
);

$canvas->lower('radar', 'cannon');

$radar{'multifirelock_set'} = 0;

$radar{'repeater'} = Tk::After->new($canvas,10,'repeat',
          sub {
           $canvas->delete($radar{'line'});
           $radar{'line'} = ();
           $radar{'angle'} += .01745;
           if($radar{'angle'} > 3.1415){ $radar{'angle'} = 0 }
           $radar{'line'} = $canvas->createLine(
                $px0, $py0,
                $width/2 + $height*cos($radar{'angle'}),
                $height - $height*sin($radar{'angle'}),
               -width      => 1,
               -fill       => 'lightgrey',
               -dash   =>  [2,4],
               -tags => ['radar'],
                 );
            $canvas->lower('radar', 'cannon');
            });
}

#----------------  
if($radar{'on'} == 0){
     $mw->bind('<space>', sub{ &fire }  );
     $radar{'repeater'}->cancel;
     $canvas->delete($radar{'line'});
     $radar{'multifirelock_set'} = 0;
     $radar{'line'} = ();

  }

}
######################################################################
+#####  
sub restart{

$launcher->cancel;
$mw->bind('<space>', sub{ }  );

my $wait;
$wait = Tk::After->new($canvas,10,'repeat',
        sub {
          if(scalar @missles == 20){
            $wait->cancel;
            $bat_level = 100;
            $ammo_tot = 500;
            $missles_max = 100;
            $hits = 0;
            $startbut->configure(-state =>'normal');
          }else{return}
    });
}
######################################################################
+###  


Replies are listed 'Best First'.
Re: Perl Missile Defense with Radar
by BrowserUk (Pope) on Dec 02, 2004 at 21:25 UTC

    For those, like me, with strident bells and other householders who sleep regular hours, comment out lines 194, 236, 248 & 266!


    Examine what is said, not who speaks.
    "But you should never overestimate the ingenuity of the sceptics to come up with a counter-argument." -Myles Allen
    "Think for yourself!" - Abigail        "Time is a poor substitute for thought"--theorbtwo         "Efficiency is intelligent laziness." -David Dunham
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: Perl Missile Defense with Radar
by parv (Priest) on Dec 02, 2004 at 20:55 UTC
    Nice work. Now that "we" have the radar, we drink coffee easliy w/o a worry ... which may not last longer if our projectiles stop after a hit w/ enemies' drops.
      Got to keep something back....for inclusion in the "pay" version. ha ha :-)

      I'm not really a human, but I play one on earth. flash japh
Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: sourcecode [id://411938]
help
Chatterbox?
and monks are getting baked in the sun...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2018-05-26 10:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?