#!/usr/bin/perl
use Firework;
# add_rocket(initial_x, initial_y, v_x, v_y, start_time, color);
my $display=new Firework;
$display->add_rocket(0,25,18,18);
$display->add_rocket(25,25,18,18,7);
$display->add_wheel(19,22,3);
$display->add_wheel(60,22,8);
$display->start_display;
####
package Firework;
use Firework::Rockets;
use Firework::Catherine;
### used for what the rockets look like:
use constant Point=>".";
#use constant Point=>"*";
use strict;
sub new {
my($self,$point)=@_;
my $display={fireworks=>[],Time=>0,Point=>$point||Point};
bless$display;
return$display;
}
sub add_rocket {
my ($display,@args)=@_;
my $firework=Firework::Rockets->new(@_);
push@{$display->{fireworks}},$firework;
}
sub add_wheel {
my($display,@args)=@_;
my $wheel=Firework::Catherine->new(@_);
push@{$display->{fireworks}},$wheel;
}
sub start_display {
my $display=shift;
my $live_fireworks=1;
$|=1;
while($live_fireworks){
$live_fireworks=0;
print "\ec";
$display->{Time}+=1;
foreach my $firework (@{$display->{fireworks}}){
if(!$firework->{dead}){
$live_fireworks++;
if($firework->{exploded}){
$firework->post_explode;
} else {
if($firework->should_explode ){
$firework->explode;
} else {
if($display->{Time}>$firework->{start}){
$firework->draw;
$firework->{timer}+=.1;
}
}
}
}
}
select undef,undef,undef,0.1
}
}
# and some defaults;
sub draw {
my $firework=shift;
if($firework->y_t > 0 && $firework->y_t < 25 && $firework->x_t > 0 && $firework->x_t < 80){
printf"\e[%d;%dH\e[1;%dm%s\e[m\e[H",$firework->y_t,
$firework->x_t,
$firework->{colour},
$firework->{display}->{Point};
}
}
sub x_t {
my $firework=shift;
return $firework->{i_x}+$firework->{v_x}*$firework->{timer};
}
sub y_t {
my $firework=shift;
# s=ut+1/2*a*t^2
return $firework->{i_y} - $firework->{timer}*
($firework->{v_y}-5*$firework->{timer});
}
sub v_y_t {
my $firework=shift;
return $firework->{v_y}-10*$firework->{timer}
}
sub explode {
my $firework=shift;
$firework->{dead}=1;
}
sub should_explode {
return 0;
}
1;
####
package Firework::Rockets;
use Firework;
our @ISA=qw{ Firework };
sub new {
my($self,$display,$i_x,$i_y,$v_x,$v_y,$start,$colour)=@_;
my $firework={
i_x=>$i_x,
i_y=>$i_y,
v_x=>$v_x,
v_y=>$v_y,
start=>$start,
display=>$display,
colour=>$colour||31+rand(6)
};
bless $firework,$self;
return $firework;
}
sub explode {
my $firework=shift;
$firework->{exploded}=1;
for my $z (1..4){
$firework->{parts}{$z}=bless{
i_x=>$firework->x_t,
i_y=>$firework->y_t,
v_x=>$z%2?5:-5,
v_y=>$z>2?5:-5,
colour=>$firework->{colour},
display=>$firework->{display}
};
}
}
sub should_explode {
my $self=shift;
return ($self->v_y_t < 0);
}
sub post_explode {
my $firework=shift;
foreach my $part_count (keys %{$firework->{parts}}){
my $part=$firework->{parts}{$part_count};
if($part->y_t > 22 || $part->x_t > 75 || $part->x_t < 0){
delete $firework->{parts}{$part_count}
} else {
$part->draw;
$part->{timer}+=.1;
}
}
$firework->{dead}=1 if(!scalar keys %{$firework->{parts}});
}
1;
####
package Firework::Catherine;
use Firework;
our @ISA=qw{ Firework };
sub new {
my($self,$display,$x,$y,$start)=@_;
my $firework={
pos=>[[-1,-1],[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1]],
x=>$x,
y=>$y,
start=>$start,
display=>$display
};
bless $firework,$self;
return $firework;
}
sub draw {
my $wheel=shift;
if($wheel->{x}<40){
push@{$wheel->{pos}},shift@{$wheel->{pos}};
} else {
unshift@{$wheel->{pos}},pop@{$wheel->{pos}};
}
for(0..2){
printf"\e[%d;%dH\e[1;%dm.\e[m\e[H",$wheel->{y}+$wheel->{pos}[$_][0],
$wheel->{x}+$wheel->{pos}[$_][1],31+rand(6);
if($wheel->{pos}[$_][1]==-1 && $wheel->{pos}[$_][0]==1 && $wheel->{timer}%2){
$wheel->{display}->add_rocket(
$wheel->{x},
$wheel->{y},
$wheel->{x}>40?-18:18,15+rand(6)
);
}
}
}
sub should_explode {
my $wheel=shift;
$wheel->{dead}=1 if($wheel->{timer}>6);
return 0;
}
1;