Apr 26, 2011

SDL Perl をいじってみた (2)

懲りずにまだまだ SDL Perl をいじっています。今回はアイテムと、アイテムと自キャラの衝突判定、スコア表示を追加してみました。少しはゲームに近づいたのではないでしょうか?

SDL に加えて png画像の読み込みに SDL_imagetruetypeフォントの読み込みに SDL_ttf を利用しています。

ゲームっぽい何かのテスト画面 2

ご覧のように、魔法少女まどか☆マギカのまどかが漆黒に染まったソウルジェムを拾うゲーム(まだゲームとは言えない出来ですけども)になってしまったのは、まどかマギカの第11話・第12話を観たばっかりだったのと、前回投稿した動画、SDL Perl でゲームっぽい何かを書いてみたのコメントのキャラをまどかのドット絵にしたら?という書き込みに乗っかってみたからです。そんでもってまたもや動画を投稿してみました。

SDL Perl でゲームっぽい何かを書いてみた 2

madoka.png と soul_gem.png

ドット絵まどか画像ドット絵黒ソウルジェム画像

コードを追加するよりドット絵を手打ちする方に遥かに多くの時間が掛かってしまいました。さらりと描ける方々が本当に羨ましいです。

#!/usr/local/bin/perl

use strict;
use warnings;
use SDL;
use SDL::Events;
use SDLx::App;
use SDLx::Rect;
use SDLx::Sprite;
use SDLx::Text;

# ウィンドウ全体の準備
my $app = SDLx::App->new(
                         width        => 512,
                         height       => 384,
                         title        => 'Catch the Soul Gem!',
                         dt           => 0.02,
                         exit_on_quit => 1,
                        );

# 自キャラの準備
my $player = { 
          rect  => SDLx::Rect->new( $app->w / 2 - 16, $app->h / 5 * 4, 32, 32 ),
          v_x   => 0,
          score => 0,
         };

# 自キャラ画像を入れる
my $player_character = SDLx::Sprite->new(
                     image => 'madoka.png', # 画像置き場へのパス
                     rect  => $player->{rect},
                    );

# アイテムの準備
my $item = { 
            rect => SDLx::Rect->new( int( rand( $app->w ) ) - 16, 0, 32, 32 ),
            v_y  => 4,
           };

# アイテム画像を入れる
my $item_character = SDLx::Sprite->new(
                       image => 'soul_gem.png', # 画像置き場のパス
                       rect  => $item->{rect},
                      );

# スコアの準備
my $score = SDLx::Text->new(
               font => 'VL-Gothic-Regular.ttf', # truetypeフォント置き場へのパス
               h_align => 'right',
              );

# 表示
$app->add_show_handler(
    sub {
        $app->draw_rect( [ 0, 0, $app->w, $app->h - 45 ], 0x007bbbff ); # 空
        $app->draw_rect( [ 0, $app->h - 45, $app->w, 45 ], 0xc3d825ff ); # 地面
        $player_character->draw( $app ); # 自キャラ
        $item_character->draw( $app ); # アイテム
        $score->write_to( $app, 'SCORE:' . $player->{score} ); # スコア
 
        # CPU使用率が 100% に振り切れるようならディレイを挟んでも良いかも?
        #$app->delay( 10 );

        $app->update;
    }
);

# 自キャラの動き
$app->add_move_handler(
    sub {
        my ( $step, $app ) = @_;
        my $v_x = $player->{v_x};
        $player->{rect}->x( $player->{rect}->x + ( $v_x * $step ) );

        # 左の移動限度
        if ( $player->{rect}->left <= 0 ) {
            $player->{rect}->left( 0 );
        }

        # 右の移動限度
        elsif ( $player->{rect}->right >= $app->w ) {
            $player->{rect}->right( $app->w );
        }
    }
);

# アイテムの動き
$app->add_move_handler(
    sub {
        my ( $step, $app ) = @_;
        my $v_y = $item->{v_y};
        $item->{rect}->y( $item->{rect}->y + ( $v_y * $step ) );

        # 衝突した?
        if ( &check_collision( $item->{rect}, $player->{rect} ) ) {
            $player->{score}++;
            &reset_item;
        }

        # 下端まで行き着いた?
        elsif ( $item->{rect}->top >= $app->h ) {
            &reset_item;
        }
    }
);

# 自キャラの操作
$app->add_event_handler(
    sub {
        my ( $event, $app ) = @_;

        # キーを押し込んだ場合
        if ( $event->type == SDL_KEYDOWN ) {

            # ←キーを押し込んで左へ
            if ( $event->key_sym == SDLK_LEFT ) {
                $player->{v_x} = -2;
            }
            # →キーを押し込んで右へ
            elsif ( $event->key_sym == SDLK_RIGHT ) {
                $player->{v_x} = 2;
            }
            # qキーまたは ESCキーを押して終了
            elsif ( 
                       $event->key_sym == SDLK_q 
                    or $event->key_sym == SDLK_ESCAPE
            ) {
                $app->stop();
            }
        }
        # キーを離した場合
        elsif ( $event->type == SDL_KEYUP ) {

            # ←キーや→キーを離したら自キャラが止まる
            if (
                    $event->key_sym == SDLK_LEFT
                 or $event->key_sym == SDLK_RIGHT
            ) {
                $player->{v_x} = 0;
            }
        }
    }
);

# ループ開始
$app->run;

# 衝突判定
sub check_collision {
    my ($A, $B) = @_;

    return if ( $A->bottom < $B->top + 16 ); # 自キャラ上半分の衝突判定を削る
    return if ( $A->right  < $B->left     );
    return if ( $A->left   > $B->right    );

    # 衝突
    return 1;
}

# アイテムをリセット
sub reset_item {
    $item->{rect}->y( 0 );                          # 上端の
    $item->{rect}->x( int( rand( $app->w) ) - 16 ); # ランダムな水平位置
    $item->{v_y} = int( rand( 3 ) ) + 3;            # ランダムな速度で再出現
}
Posted at 12:32 in perl | Comments/Trackbacks ()
Comments/Trackbacks
TrackBack ping me at
http://pochi.usamimi.info/blog/perl/SDL_Perl_game03.
Post a comment

writeback message: