#
# mogura.pl : モグラたたきゲーム
#
# Copyright (C) 2001-2019 Makoto Hiroi
#
use strict;
use warnings;
use Tk;
# 大域変数の宣言
our $level;
our $now_mogu;
our $miss_count;
our $hit_count;
our $score;
our $hi_score;
our @mogu_house;
our $buff0;
our $buff1;
our $top;
our $canvas;
# ラベルの表示
sub print_label {
$buff1 = sprintf("Level %d : Score %d : Miss %d", $level, $score, $miss_count);
}
# HI SCORE 表示
sub print_hi_score {
$buff0 = sprintf("HiScore %d", $hi_score);
}
# 大域変数の初期化
sub init_global {
$level = 1;
$now_mogu = 0;
$miss_count = 0;
$hit_count = 0;
$score = 0;
my ($x, $y);
for ($x = 0; $x < 5; $x++) {
for ($y = 0; $y < 5; $y++) {
my $mogura = $mogu_house[$x][$y];
$mogura->{'state'} = 0;
}
}
&print_label();
}
# 穴にモグラが一匹ずついて顔を出すというイメージ
sub init_mogura {
my ($x, $y) = @_;
my $x1 = $x * 60 + 5;
my $y1 = $y * 40 + 5;
my $hole = $canvas->create('rectangle', $x1, $y1, $x1 + 59, $y1 + 39,
-outline => 'white', -fill => 'darkgreen');
my $mogu = $canvas->create('oval', $x1, $y1, $x1 + 59, $y1 + 39,
-outline => 'darkgreen', -fill => 'blue',
-tags => 'mogura');
my $miss = $canvas->create('text', $x1 + 30, $y1 + 20,
-text => '**MISS**', -fill => 'red',
-tags => 'mogura');
my $hit = $canvas->create('text', $x1 + 30, $y1 + 20,
-text => '!!HIT!!', -fill => 'yellow',
-tags => 'mogura');
$canvas->bind($mogu, "<Button-1>" => [\&attack, $x, $y]);
$canvas->lower($mogu);
$canvas->lower($miss);
$canvas->lower($hit);
# 無名のハッシュにまとめる
my $mogura = {
state => 0, mogutime => 0, mogu => $mogu, miss => $miss, hit => $hit,
};
$mogura;
}
# 命中
sub attack {
my ($id, $x, $y) = @_;
my $mogura = $mogu_house[$x][$y];
++$hit_count;
if ($hit_count and ($hit_count % 10 == 0)) {
$level++;
}
$score += $level;
$now_mogu--;
$mogura->{'state'} = 2;
$mogura->{'mogutime'} = 2;
$canvas->lower($mogura->{'mogu'});
$canvas->raise($mogura->{'hit'});
&print_label();
}
# モグラの状態を変更する
sub change_mogura {
my $mogura = shift;
my $state = $mogura->{'state'};
if( $state == 1 ){
# ミス
$canvas->lower($mogura->{'mogu'});
$canvas->raise($mogura->{'miss'});
$mogura->{'state'} = 3;
$mogura->{'mogutime'} = 4;
$miss_count++;
$now_mogu--;
if ($miss_count >= 10) {
return 1;
}
&print_label();
} elsif ($state == 2) {
# HIT を引っ込める
$canvas->lower($mogura->{'hit'});
$mogura->{'state'} = 4;
$mogura->{'mogutime'} = 4;
} elsif ($state == 3) {
# MISS を引っ込める
$canvas->lower($mogura->{'miss'});
$mogura->{'state'} = 4;
$mogura->{'mogutime'} = 4;
} elsif ($state == 4) {
# アイドル時間終了
$mogura->{'state'} = 0;
}
return 0;
}
# モグラの生成
sub gen_mogura {
my $mogura = shift;
if ($now_mogu < $level){
# モグラを出すか
if (rand() < 0.1) {
$now_mogu++;
$mogura->{'state'} = 1;
$mogura->{'mogutime'} = 6;
$canvas->raise($mogura->{'mogu'});
}
}
}
# ゲームの実行 500 msec 毎に起動する
sub game {
my ($x, $y);
for ($x = 0; $x < 5; $x++) {
for ($y = 0; $y < 5; $y++) {
my $mogura = $mogu_house[$x][$y];
if ($mogura->{'state'} != 0) {
if (--$mogura->{'mogutime'} == 0) {
if(&change_mogura($mogura)) {
&game_over();
return;
}
}
} else {
&gen_mogura($mogura);
}
}
}
$top->update;
$top->after(500, \&game);
}
# ゲーム終了
sub game_over {
&print_label();
if ($hi_score < $score) {
$hi_score = $score;
&print_hi_score();
}
# 全て引っ込める
$canvas->lower('mogura');
}
# ゲームの開始
sub start_game {
&init_global();
&game();
}
# 画面の設定
$top = MainWindow->new();
# メニューの設定
my $m = $top->Menu(-type => 'menubar');
$top->configure(-menu => $m);
$m->command(-label => 'Start', -under => 0, -command => \&start_game);
# ラベル
my $l0 = $top->Label(-textvariable => \$buff0)->pack();
my $l1 = $top->Label(-textvariable => \$buff1)->pack();
# キャンバス
$canvas = $top->Canvas(-width => 310, -height => 210, -bg => 'darkgreen');
$canvas->pack();
# モグラ
@mogu_house = ();
for (my $x = 0; $x < 5; $x++) {
$mogu_house[$x] = [];
for (my $y = 0; $y < 5; $y++) {
$mogu_house[$x][$y] = &init_mogura($x, $y);
}
}
$buff1 = "Click Start Menu !!";
$hi_score = 0;
MainLoop();
戻る