1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
| #!/usr/bin/env perl
use v5.36;
use Time::HiRes qw(sleep);
package BulletType {
use Moo;
has char => (is => 'ro', required => 1);
has color => (is => 'ro', default => 'white');
# 外部状態(位置)を受け取って描画
sub render($self, $x, $y, $screen) {
my $ix = int($x);
my $iy = int($y);
# 画面外チェック
return if $iy < 0 || $iy >= @$screen;
return if $ix < 0 || $ix >= length($screen->[$iy]);
# 画面バッファに描画
substr($screen->[$iy], $ix, 1) = $self->char;
}
}
package BulletFactory {
use Moo;
has _cache => (is => 'ro', default => sub { {} });
has _definitions => (
is => 'ro',
default => sub {
{
circle => { char => '●', color => 'red' },
star => { char => '★', color => 'blue' },
dot => { char => '・', color => 'green' },
arrow => { char => '→', color => 'yellow' },
}
},
);
sub get($self, $key) {
my $cache = $self->_cache;
my $defs = $self->_definitions;
$cache->{$key} //= do {
my $def = $defs->{$key} or die "Unknown: $key";
BulletType->new(%$def);
};
}
sub count($self) { scalar keys %{$self->_cache} }
}
# メイン処理
my $WIDTH = 50;
my $HEIGHT = 20;
my $factory = BulletFactory->new;
# 弾を生成
my @bullets;
my $cx = $WIDTH / 2;
my $cy = $HEIGHT / 2;
for my $wave (0 .. 2) {
for my $i (0 .. 11) {
my $angle = ($i * 30 + $wave * 10) * 3.14159 / 180;
my $type = qw(circle star dot)[$wave];
push @bullets, {
type => $factory->get($type),
x => $cx,
y => $cy,
vx => cos($angle) * (1.5 - $wave * 0.2),
vy => sin($angle) * 0.7,
born => $wave * 2,
};
}
}
say "弾の総数: " . scalar(@bullets);
say "BulletTypeオブジェクト数: " . $factory->count;
say "";
# アニメーション
print "\e[2J";
for my $frame (0 .. 12) {
my @screen = map { " " x $WIDTH } (1 .. $HEIGHT);
for my $b (@bullets) {
next if $frame < $b->{born};
$b->{type}->render($b->{x}, $b->{y}, \@screen);
$b->{x} += $b->{vx};
$b->{y} += $b->{vy};
}
print "\e[H";
say $_ for @screen;
say "Frame $frame - 外部状態を渡して描画中...";
sleep(0.2);
}
say "\n完了!";
|