プログラミング演習Ⅲ(2023)

【WPF練習14】壁崩し(9/9)

プロジェクトタイプC# WPFアプリケーション※
プロジェクト名T10b
ソリューション名PET10
ターゲットフレームワーク.NET 6.0 (長期的なサポート)

※ 「WPFアプリ(.NET Framework)」ではないので注意せよ!

注意
  • 本ページの作業内容は 前のページまでの続き になっていることに注意せよ.
    • 先に前のページまでをすべて読み,指示されている作業を済ませてから本ページを読むこと.
    • プロジェクトの作成作業については準備を参照せよ.

14-9. ゲームとしての「味付け」

さてここまでで壁崩しとしてはおおむね完成と言いたいところだが,実は一つ問題がある. 現在のボールの挙動は,壁やブロック,プレイヤーに衝突するたびに正確に正反射方向に跳ね返るだけなので, 最初のボールの速度ベクトルの方向(リスト14-3-4の28~29行目)によっては,_に示すように 千日手のような状態に陥って永遠にすべてのブロックを破壊できない場合がある.

作業結果

そこでボールが壁やブロック,プレイヤーなどに接触した場合に,一定の確率でボールの速度ベクトルにノイズを加えてみることにしよう. Timer_Tick()メソッドに_に示す内容を追記する.

MainWindow.xaml.csの追記内容
 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
private void Timer_Tick(object sender, EventArgs e)
{
    const double EPSILON = 1 / 256.0;

    double ballX = Canvas.GetLeft(ball) + ball.Width / 2;
    double ballY = Canvas.GetTop(ball) + ball.Height / 2;

    // (..中略: チートコマンドの処理..)

    // (..中略: ゲームの終了処理..)

    bool hit = false; // 接触があったかどうかを示すフラグ

    if (nextBallX < 0 || canvas1.Width <= nextBallX) 
    {
        speedX *= -1;
        ballX = Math.Clamp(nextBallX, 0, canvas1.Width) + EPSILON * speedX;
        nextBallX = ballX + speedX;
        hit = true;
    }// if

    if (nextBallY < 0 || canvas1.Height <= nextBallY) 
    {
        speedY *= -1;
        ballY = Math.Clamp(nextBallY, 0, canvas1.Height) + EPSILON * speedY;
        nextBallY = ballY + speedX;
        hit = true;
    }// if

    var query = (new Vector(ballX, ballY), new Vector(nextBallX, nextBallY));

    var result = QueryBySegment(query);
    if (result.HasValue) 
    {
        // (..中略..)

        if ((string)rect.Tag == "Bricks")
            canvas1.Children.Remove(rect);

        hit = true;
    }// if

    // ボールに接触があり,かつ約三分の一の確率で以下の処理を行う.
    if (hit && rand.Next(100) <= 33) 
    {
        speedX += -5.0 + 10.0 * rand.NextDouble(); // ボールの速度ベクトルに
        speedY += -5.0 + 10.0 * rand.NextDouble(); // ノイズを加える.
    }// if

    Canvas.SetLeft(ball, nextBallX - ball.Width / 2);
    Canvas.SetTop(ball, nextBallY - ball.Height / 2);
}

ここまで書けたら起動してゲームを遊んでみよう._に示すように, 時折ボールが理不尽な方向に進んでいくはずである.

作業結果

このほかにも壁崩しの機能拡張はいろいろ考えられる.たとえば,プレイヤーにボールが接触した場合に, その瞬間のプレイヤーの運動を反射方向に加味して,ある程度ボールの反射方向を制御できるようにするのも面白いだろう. 実際の壁崩しゲームでは技術介入要素を増やすためにそのような挙動を実装しているものも多い.

システム面では,残機制の導入や複数のステージを攻略するいわゆるキャンペーンモードの実装, ボールを増やしたり一定時間プレイヤーの横幅を増やしたり,ショットを打てるようにするといった特殊効果を付与するアイテムの実装, もしくは既存の壁崩しゲームの ように,画面上を動き回る敵キャラを実装するといったことも考えられるだろう.

ゲームプログラミングは難解な処理を多数含んでいるが自由製作で挑戦してみるのもよいだろう.

ここまでを確認できたら本チュートリアルは完了である.

Last updated on 2024-01-09
Published on 2024-01-09

Powered by Hugo. Theme by TechDoc. Designed by Thingsym.