C#-dotnet-GTK-project-template-bound

それじゃあ、画像同士がぶつかったら反射する衝突判定付きアニメーションを追加していきましょう 💥🌀


目次

✅ 追加機能:画像の衝突判定(バウンド+反射)

✨ 更新ポイント:

  • 各画像の 位置 (X, Y)サイズ (Width, Height)矩形衝突 を検出
  • 衝突したら、進行方向(DX, DY)を反転

🧠 ロジック(簡易的なAABB衝突)

bool IsColliding(MovingImage a, MovingImage b)
{
    return !(a.X + image.Width < b.X ||
             a.X > b.X + image.Width ||
             a.Y + image.Height < b.Y ||
             a.Y > b.Y + image.Height);
}

🔁 OnUpdate 内に衝突チェック追加

private void OnUpdate(object sender, ElapsedEventArgs e)
{
    // 移動
    foreach (var img in images)
    {
        img.X += img.DX;
        img.Y += img.DY;

        // 端で反射
        if (img.X < 0 || img.X + image.Width > 600) img.DX = -img.DX;
        if (img.Y < 0 || img.Y + image.Height > 400) img.DY = -img.DY;
    }

    // 衝突判定
    for (int i = 0; i < images.Count; i++)
    {
        for (int j = i + 1; j < images.Count; j++)
        {
            var a = images[i];
            var b = images[j];

            if (IsColliding(a, b))
            {
                // 反射(単純にお互い逆方向に跳ね返る)
                a.DX = -a.DX;
                a.DY = -a.DY;
                b.DX = -b.DX;
                b.DY = -b.DY;
            }
        }
    }

    Application.Invoke((_, __) => drawingArea.QueueDraw());
}

🔍 衝突関数を追加

private bool IsColliding(MovingImage a, MovingImage b)
{
    return !(a.X + image.Width < b.X ||
             a.X > b.X + image.Width ||
             a.Y + image.Height < b.Y ||
             a.Y > b.Y + image.Height);
}

🧪 動作イメージ

  • 🖱 複数クリックして画像を出現させる
  • 🔁 画像が移動しながら、お互いにぶつかると「ピョンッ」と反転
  • 🧲 壁にもバウンド

🔚 全体コード変更まとめ

必要なのは:

  • OnUpdate衝突ループ追加
  • IsColliding(...) を定義

それだけで OK!コード本体はそのまま。


✨ 次にやってみる?

  • 💥 衝突時に色や画像を変える
  • 🔊 サウンドを鳴らす
  • 🎮 主人公キャラだけ操作可能にする(←おすすめ)
  • 🧠 複雑な物理エンジン連携(Farseer など)

やってみたい方向ある?続けて強化できるよ!

もちろん!
以下が「GTK3 + C# で、画像をクリックで追加 & 移動 & 衝突反射」するフルコードです 🎮🌀


🖼 必要な画像ファイル

  • icon.png(プロジェクトディレクトリに置いてください)
    小さめの画像(64×64くらい)がおすすめ。

🧾 Program.cs(フルコード)

using Gtk;
using Cairo;
using Gdk;
using System;
using System.Collections.Generic;
using System.Timers;

public class AnimatedImageWindow : Window
{
    private DrawingArea drawingArea;
    private Pixbuf image;
    private List<MovingImage> images = new List<MovingImage>();
    private Timer timer;

    public AnimatedImageWindow() : base("GTK3 Image Collision Animation")
    {
        SetDefaultSize(600, 400);
        SetPosition(WindowPosition.Center);
        DeleteEvent += (o, args) => Application.Quit();

        drawingArea = new DrawingArea();
        drawingArea.AddEvents((int)EventMask.ButtonPressMask);
        drawingArea.Drawn += OnDraw;
        drawingArea.ButtonPressEvent += OnClick;

        Add(drawingArea);
        ShowAll();

        // 画像読み込み
        image = new Pixbuf("icon.png");

        // タイマーで更新
        timer = new Timer(16); // 約60FPS
        timer.Elapsed += OnUpdate;
        timer.Start();
    }

    private void OnClick(object o, ButtonPressEventArgs args)
    {
        double x = args.Event.X;
        double y = args.Event.Y;

        var rand = new Random();
        double dx = rand.NextDouble() * 4 - 2;
        double dy = rand.NextDouble() * 4 - 2;

        images.Add(new MovingImage(x, y, dx, dy));
    }

    private void OnUpdate(object sender, ElapsedEventArgs e)
    {
        foreach (var img in images)
        {
            img.X += img.DX;
            img.Y += img.DY;

            // 端でバウンド
            if (img.X < 0 || img.X + image.Width > 600) img.DX = -img.DX;
            if (img.Y < 0 || img.Y + image.Height > 400) img.DY = -img.DY;
        }

        // 衝突判定(簡易)
        for (int i = 0; i < images.Count; i++)
        {
            for (int j = i + 1; j < images.Count; j++)
            {
                var a = images[i];
                var b = images[j];

                if (IsColliding(a, b))
                {
                    // お互いに反射
                    double tempDX = a.DX;
                    double tempDY = a.DY;
                    a.DX = b.DX;
                    a.DY = b.DY;
                    b.DX = tempDX;
                    b.DY = tempDY;
                }
            }
        }

        Application.Invoke((_, __) => drawingArea.QueueDraw());
    }

    private bool IsColliding(MovingImage a, MovingImage b)
    {
        return !(a.X + image.Width < b.X ||
                 a.X > b.X + image.Width ||
                 a.Y + image.Height < b.Y ||
                 a.Y > b.Y + image.Height);
    }

    private void OnDraw(object sender, DrawnArgs args)
    {
        Context cr = args.Cr;

        // 背景
        cr.SetSourceRGB(1, 1, 1);
        cr.Paint();

        // 画像を描画
        foreach (var img in images)
        {
            Gdk.CairoHelper.SetSourcePixbuf(cr, image, img.X, img.Y);
            cr.Paint();
        }
    }

    public static void Main()
    {
        Application.Init();
        new AnimatedImageWindow();
        Application.Run();
    }

    private class MovingImage
    {
        public double X, Y, DX, DY;
        public MovingImage(double x, double y, double dx, double dy)
        {
            X = x; Y = y; DX = dx; DY = dy;
        }
    }
}

🛠 ビルド & 実行

GTK3 必要ライブラリ

sudo apt install libgtk-3-dev

コンパイル

mcs -pkg:gtk-sharp-3.0 -out:animated.exe Program.cs

実行

mono animated.exe

✅ 機能まとめ

  • 🖱 クリックで画像を生成
  • 🌀 自動で動き回る
  • 💥 画像同士がぶつかったら反射(速度交換)
  • 🧲 壁で跳ね返る

🔧 拡張したい?

  • 🎮 キーボードで画像操作(プレイヤーキャラ)
  • 💥 衝突時のアニメーション
  • 🎵 サウンド追加
  • 🌈 パーティクルやエフェクト

次のステップ、希望があればすぐ用意しますよ!何を追加したい?

よかったらシェアしてね!
目次