0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

こんにちは!今回は、PowerShellを使ってブロック崩しゲームを実装する方法を紹介します。.NETのWindows Forms を利用して、グラフィカルなゲーム画面を作成し、キー入力操作とスコア機能を追加します。

前回の記事ではコンソールの画面に出力していたのを、今回は.NETのWindows Forms を画面のフレームワークとして採用しました。

目次

  1. 要件
  2. 仕様
  3. 環境設定
  4. ゲームの基本構造
  5. ゲームオブジェクトの実装
  6. キー入力の処理
  7. スコア機能の実装
  8. ゲームロジックの実装
  9. 画面の描画
  10. ゲームループの実装
  11. 完全なソースコード
  12. まとめ

1. 要件

このプロジェクトでは、以下の要件を満たすブロック崩しゲームを作成します:

  1. PowerShellを使用して実装すること
  2. グラフィカルなユーザーインターフェースを持つこと
  3. プレイヤーがパドルを操作してボールを打ち返せること
  4. 複数のブロックを配置し、ボールが当たると消えること
  5. スコア機能を実装すること
  6. ゲームオーバーとクリア条件を設定すること

2. 仕様

image.png

上記の要件を満たすため、以下の仕様で実装を行います:

  1. 使用技術:

    • PowerShell
    • .NET Framework(System.Windows.Forms, System.Drawing)
  2. ゲーム画面:

    • サイズ:400x500ピクセル
    • 背景色:黒
  3. ゲームオブジェクト:

    • パドル:
      • サイズ:幅100ピクセル、高さ10ピクセル
      • 初期位置:画面下部中央
      • 移動速度:5ピクセル/フレーム
    • ボール:
      • サイズ:直径10ピクセル
      • 初期位置:画面中央
      • 初期速度:X方向2ピクセル/フレーム、Y方向-2ピクセル/フレーム
    • ブロック:
      • サイズ:幅50ピクセル、高さ20ピクセル
      • 配置:7列3行(計21個)
  4. 操作方法:

    • 左矢印キー:パドルを左に移動
    • 右矢印キー:パドルを右に移動
  5. スコアシステム:

    • 初期スコア:0点
    • ブロック1個につき10点加算
  6. ゲーム終了条件:

    • ゲームオーバー:ボールが画面下端に到達
    • クリア:すべてのブロックを破壊
  7. その他:

    • フレームレート:約60FPS(タイマー間隔15ミリ秒)
    • 衝突判定:単純な矩形判定を使用

これらの仕様に基づいて、以降のセクションでゲームの実装を進めていきます。

image.png

3. 環境設定

PowerShellとWindows Formsを使用するため、特別な環境設定は必要ありません。Windows 10以降のOSであれば、標準でPowerShellが利用可能です。

4. ゲームの基本構造

まず、ゲームの基本構造を作成します。Windows Formsを使用してゲームウィンドウを作成し、ゲームオブジェクト(パドル、ボール、ブロック)を定義します。

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$form = New-Object System.Windows.Forms.Form
$form.Text = "PowerShell ブロック崩し"
$form.Size = New-Object System.Drawing.Size(400, 500)
$form.StartPosition = "CenterScreen"
$form.BackColor = [System.Drawing.Color]::Black

$graphics = $form.CreateGraphics()

5. ゲームオブジェクトの実装

次に、ゲームオブジェクトを定義します。パドル、ボール、ブロックをそれぞれ構造体として実装します。

$paddle = @{
    X = 150
    Y = 450
    Width = 100
    Height = 10
    Speed = 5
}

$ball = @{
    X = 200
    Y = 250
    Size = 10
    SpeedX = 2
    SpeedY = -2
}

$blocks = @()
$blockWidth = 50
$blockHeight = 20
for ($i = 0; $i -lt 7; $i++) {
    for ($j = 0; $j -lt 3; $j++) {
        $blocks += @{
            X = $i * ($blockWidth + 10) + 25
            Y = $j * ($blockHeight + 10) + 50
            Width = $blockWidth
            Height = $blockHeight
            IsVisible = $true
        }
    }
}

6. キー入力の処理

キー入力の処理方法を改善します。GetAsyncKeyState を使用してキー入力を検出します。

Add-Type @"
using System;
using System.Runtime.InteropServices;

public class KeyboardInput {
    [DllImport("user32.dll")]
    public static extern short GetAsyncKeyState(int vKey);
}
"@

function IsKeyPressed($key) {
    return ([KeyboardInput]::GetAsyncKeyState($key) -band 0x8000) -ne 0
}

7. スコア機能の実装

スコア機能を実装します。ゲーム開始時のスコアを0とし、ブロックを壊すたびにスコアが増加するようにします。

$score = 0

function UpdateScore {
    $script:score += 10
}

8. ゲームロジックの実装

ゲームロジックを実装します。ボールの移動、衝突判定、スコア管理などを行います。

function MoveBall {
    $ball.X += $ball.SpeedX
    $ball.Y += $ball.SpeedY

    # 壁との衝突判定
    if ($ball.X -le 0 -or $ball.X -ge ($form.Width - $ball.Size)) {
        $ball.SpeedX *= -1
    }
    if ($ball.Y -le 0) {
        $ball.SpeedY *= -1
    }

    # パドルとの衝突判定
    if ($ball.Y -ge $paddle.Y - $ball.Size -and 
        $ball.X -ge $paddle.X -and 
        $ball.X -le $paddle.X + $paddle.Width) {
        $ball.SpeedY *= -1
    }

    # ブロックとの衝突判定
    for ($i = 0; $i -lt $blocks.Count; $i++) {
        if ($blocks[$i].IsVisible -and 
            $ball.X -ge $blocks[$i].X -and 
            $ball.X -le $blocks[$i].X + $blocks[$i].Width -and 
            $ball.Y -ge $blocks[$i].Y -and 
            $ball.Y -le $blocks[$i].Y + $blocks[$i].Height) {
            $blocks[$i].IsVisible = $false
            $ball.SpeedY *= -1
            UpdateScore  # スコアを更新
            break
        }
    }
}

function MovePaddle {
    if (IsKeyPressed([System.Windows.Forms.Keys]::Left)) {
        $paddle.X -= $paddle.Speed
    }
    if (IsKeyPressed([System.Windows.Forms.Keys]::Right)) {
        $paddle.X += $paddle.Speed
    }
    
    $paddle.X = [Math]::Max(0, [Math]::Min($form.Width - $paddle.Width, $paddle.X))
}

9. 画面の描画

ゲームオブジェクトとスコアを描画する関数を実装します。

function DrawGame {
    $graphics.Clear([System.Drawing.Color]::Black)
    
    # パドルの描画
    $graphics.FillRectangle([System.Drawing.Brushes]::White, $paddle.X, $paddle.Y, $paddle.Width, $paddle.Height)
    
    # ボールの描画
    $graphics.FillEllipse([System.Drawing.Brushes]::White, $ball.X, $ball.Y, $ball.Size, $ball.Size)
    
    # ブロックの描画
    foreach ($block in $blocks) {
        if ($block.IsVisible) {
            $graphics.FillRectangle([System.Drawing.Brushes]::Blue, $block.X, $block.Y, $block.Width, $block.Height)
        }
    }

    # スコアの描画
    $font = New-Object System.Drawing.Font("Arial", 12)
    $brush = [System.Drawing.Brushes]::White
    $graphics.DrawString("Score: $score", $font, $brush, 10, 10)
}

10. ゲームループの実装

最後に、ゲームループを実装して、ゲームを動作させます。

$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 15
$timer.Add_Tick({
    MoveBall
    MovePaddle
    DrawGame

    # ゲームオーバー判定
    if ($ball.Y -gt $form.Height) {
        $timer.Stop()
        [System.Windows.Forms.MessageBox]::Show("ゲームオーバー`nスコア: $score", "PowerShell ブロック崩し")
        $form.Close()
    }

    # クリア判定
    if (-not ($blocks | Where-Object { $_.IsVisible })) {
        $timer.Stop()
        [System.Windows.Forms.MessageBox]::Show("クリア!おめでとうございます!`nスコア: $score", "PowerShell ブロック崩し")
        $form.Close()
    }
})

$form.Add_Shown({$timer.Start()})
$form.Add_FormClosing({$timer.Stop()})
$form.ShowDialog()

11. 完全なソースコード

クラス図

シーケンス図

以下は、これまでの実装をまとめた完全なソースコードです。

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

Add-Type @"
using System;
using System.Runtime.InteropServices;

public class KeyboardInput {
    [DllImport("user32.dll")]
    public static extern short GetAsyncKeyState(int vKey);
}
"@

$form = New-Object System.Windows.Forms.Form
$form.Text = "PowerShell ブロック崩し"
$form.Size = New-Object System.Drawing.Size(400, 500)
$form.StartPosition = "CenterScreen"
$form.BackColor = [System.Drawing.Color]::Black

$graphics = $form.CreateGraphics()

$paddle = @{
    X = 150
    Y = 450
    Width = 100
    Height = 10
    Speed = 5
}

$ball = @{
    X = 200
    Y = 250
    Size = 10
    SpeedX = 2
    SpeedY = -2
}

$blocks = @()
$blockWidth = 50
$blockHeight = 20
for ($i = 0; $i -lt 7; $i++) {
    for ($j = 0; $j -lt 3; $j++) {
        $blocks += @{
            X = $i * ($blockWidth + 10) + 25
            Y = $j * ($blockHeight + 10) + 50
            Width = $blockWidth
            Height = $blockHeight
            IsVisible = $true
        }
    }
}

$score = 0

function IsKeyPressed($key) {
    return ([KeyboardInput]::GetAsyncKeyState($key) -band 0x8000) -ne 0
}

function UpdateScore {
    $script:score += 10
}

function MoveBall {
    $ball.X += $ball.SpeedX
    $ball.Y += $ball.SpeedY

    if ($ball.X -le 0 -or $ball.X -ge ($form.Width - $ball.Size)) {
        $ball.SpeedX *= -1
    }
    if ($ball.Y -le 0) {
        $ball.SpeedY *= -1
    }

    if ($ball.Y -ge $paddle.Y - $ball.Size -and 
        $ball.X -ge $paddle.X -and 
        $ball.X -le $paddle.X + $paddle.Width) {
        $ball.SpeedY *= -1
    }

    for ($i = 0; $i -lt $blocks.Count; $i++) {
        if ($blocks[$i].IsVisible -and 
            $ball.X -ge $blocks[$i].X -and 
            $ball.X -le $blocks[$i].X + $blocks[$i].Width -and 
            $ball.Y -ge $blocks[$i].Y -and 
            $ball.Y -le $blocks[$i].Y + $blocks[$i].Height) {
            $blocks[$i].IsVisible = $false
            $ball.SpeedY *= -1
            UpdateScore
            break
        }
    }
}

function MovePaddle {
    if (IsKeyPressed([System.Windows.Forms.Keys]::Left)) {
        $paddle.X -= $paddle.Speed
    }
    if (IsKeyPressed([System.Windows.Forms.Keys]::Right)) {
        $paddle.X += $paddle.Speed
    }
    
    $paddle.X = [Math]::Max(0, [Math]::Min($form.Width - $paddle.Width, $paddle.X))
}

function DrawGame {
    $graphics.Clear([System.Drawing.Color]::Black)
    $graphics.FillRectangle([System.Drawing.Brushes]::White, $paddle.X, $paddle.Y, $paddle.Width, $paddle.Height)
    $graphics.FillEllipse([System.Drawing.Brushes]::White, $ball.X, $ball.Y, $ball.Size, $ball.Size)
    
    foreach ($block in $blocks) {
        if ($block.IsVisible) {
            $graphics.FillRectangle([System.Drawing.Brushes]::Blue, $block.X, $block.Y, $block.Width, $block.Height)
        }
    }

    $font = New-Object System.Drawing.Font("Arial", 12)
    $brush = [System.Drawing.Brushes]::White
    $graphics.DrawString("Score: $score", $font, $brush, 10, 10)
}

$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 15
$timer.Add_Tick({
    MoveBall
    MovePaddle
    DrawGame

    if ($ball.Y -gt $form.Height) {
        $timer.Stop()
        [System.Windows.Forms.MessageBox]::Show("ゲームオーバー`nスコア: $score", "PowerShell ブロック崩し")
        $form.Close()
    }

    if (-not ($blocks | Where-Object { $_.IsVisible })) {
        $timer.Stop()
        [System.Windows.Forms.MessageBox]::Show("クリア!おめでとうございます!`nスコア: $score", "PowerShell ブロック崩し")
        $form.Close()
    }
})

$form.Add_Shown({$timer.Start()})
$form.Add_FormClosing({$timer.Stop()})
$form.ShowDialog()

12. まとめ

以上で、PowerShellを使用したブロック崩しゲームの実装が完了しました。このコードを実行すると、シンプルながらも楽しいブロック崩しゲームをプレイすることができます。

主な特徴:

  1. Windows Formsを使用したグラフィカルなインターフェース
  2. 改善されたキー入力処理(GetAsyncKeyStateの使用)
  3. スコア機能の実装(ブロックを壊すとスコアが増加)
  4. ゲームオーバーとクリア時のスコア表示

PowerShellは通常、システム管理やスクリプト作成に使用されますが、このように創造的な用途にも適用できることがわかります。さらに改良を加えて、以下のような機能を実装してみるのも面白いでしょう:

  • レベルデザイン(複数のステージ)
  • サウンドエフェクト
  • パワーアップアイテム
  • 難易度設定
  • ハイスコア機能

このプロジェクトを通じて、PowerShellの柔軟性と.NET Frameworkとの連携の可能性を探ることができました。システム管理者やIT専門家だけでなく、プログラミング初心者にとっても、PowerShellの可能性を広げる良い例となるでしょう。

ゲーム開発の楽しさを体験しながら、プログラミングスキルを向上させることができます。ぜひ、このコードをベースに自分なりのアイデアを追加して、オリジナルのゲームを作成してみてください。

Happy coding!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?