M.Hiroi's Home Page

Perl/Tk memo

お気楽 Perl/Tk プログラミング入門

モグラたたき:ソースファイル

[ Home | Perl/Tk ]
#
# 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();

戻る


Copyright (C) 2001-2019 Makoto Hiroi
All rights reserved.

[ Home | Perl/Tk memo ]