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

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

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

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

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

14-4. ステージの作成

次に壁崩しのブロック(以降のコードではbrick(≒レンガ)と呼んでいる)をステージに配置しよう. このための方法はいくつか考えられる.ブロックを手作業で一つずつ配置する方法もありえるが 今回は単純かつ規則的に配置するので手続き的に生成することにする.MainWindowクラスに _に示す2つのメソッドGetRectangles()SetupLevel()を追記しよう. 前者はcanvas1に配置されたRectangle部品を取り出すメソッドである. 後者が実際にブロックを配置するメソッドである.

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// canvas1 に配置された Rectangle を取り出すメソッド
private IEnumerable<Rectangle> GetRectangles() 
{
    var children = new List<FrameworkElement>();

    foreach (FrameworkElement c in canvas1.Children)
        children.Add(c);

    var rects = from c in children
                where c is Rectangle
                select (Rectangle)c;

    return rects;
}

// ブロックの配置
private void SetupLevel() 
{
    const double BricksTop = 60;  // ブロックの配置を始める高さ
    const int BricksRows = 5;     // ブロックの行数
    const int BricksColumns = 10; // ブロックの列数

    const double BrickWidth = 60;    // 1つのブロックの幅
    const double BrickHeight = 30;   // 1つのブロックの高さ

    Brush[] brickFillBrushes = new[]  // ブロックの色(行ごとに変化させる)
    {
        Brushes.Red,
        Brushes.Yellow,
        Brushes.LightBlue,
        Brushes.Magenta,
        Brushes.LightGreen,
    };

    // canvas1をクリアする.つまり, Rectangleのうちブロックとなっているもの
    //(.Tagプロパティに"Bricks"が設定されているもの)をあらかじめすべて削除する.
    var bricks = from r in GetRectangles()
                 where (string)r.Tag == "Bricks"
                 select r;
                    
    foreach (var b in bricks)
        canvas1.Children.Remove(b);

    // ブロックを手続的に生成して配置する.
    for (int i = 0; i < BricksRows; ++i) 
    {
        for (int k = 0; k < BricksColumns; ++k) 
        {
            // ブロック役の Rectangle を生成する.以降の処理のため 
            // .Tag プロパティに "Bricks"という文字列を設定しておく.
            Rectangle brick = new Rectangle()
            {
                Width = BrickWidth,
                Height = BrickHeight,
                Stroke = Brushes.Black,
                Fill = brickFillBrushes[i],
                Tag = "Bricks" // タグ(部品を識別するための任意データ)
            };

            // ブロックの位置決めをして canvas1 に追加する.
            Canvas.SetLeft(brick, k * BrickWidth);           
            Canvas.SetTop(brick, BricksTop + i * BrickHeight);

            canvas1.Children.Add(brick); // 追加
        }// for
    }// for
}

このSetupLevel()メソッドをResetGame()メソッドから呼び出そう. ResetGame()メソッドに_に示す内容を追記する.

MainWindow.xaml.csの追記内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
private void ResetGame()
{
    Canvas.SetLeft(ball, 295);
    Canvas.SetTop(ball, 685);

    speedX = -5.0 + 10.0 * rand.NextDouble();
    speedY = -(8.0 + 16.0 * rand.NextDouble());
    
    SetupLevel(); // ブロックを配置する.

    timer.Start();
}

ここまで書けたら起動してみよう._に示すようにブロックが配置されていることが分かるはずである. いまのところボールがぶつかったときの処理を実装していないため,ボールはブロックやプレイヤーの横棒を無視して 動き回るだけである.次節ではこのための処理─衝突判定衝突応答を実装してみよう.

作業結果
Last updated on 2024-01-09
Published on 2024-01-09

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