Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Perl Missile Defense with Radar

by zentara (Archbishop)
on Dec 02, 2004 at 20:36 UTC ( [id://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 (Patriarch) 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 (Parson) 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
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://411938]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (4)
As of 2024-03-29 12:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found