@manluan8

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

至急、解決策を求めます。

解決したいこと

加速度センサを用いて端末上でバーを操作しブロック崩しのゲームを作成することです。また、3回ボールを落とすとバーの色が赤に変わり5回目になるとゲームオーバーとなります。
ブロックをボールがすり抜けたり、まったく別のあたっていないブロックが消えたり、ボールとバーが反射していないことが発覚しました。
画像ではスタートすると勝手にブロックが消されております
解決方法を教えて下さい。

発生している問題・エラー

出ているエラーメッセージを入力
```なし
```![スクリーンショット 2025-07-25 151845.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4149141/ac025ef7-0293-4c37-bdf0-a9e2a67c3461.png)
![スクリーンショット 2025-07-26 224516.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4149141/8465d01e-15ff-44ad-9fe3-17203e92b1e3.png)
![スクリーンショット 2025-07-26 224712.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4149141/b589d41c-b870-46bf-8b03-5ba4c1743a5d.png)


### 該当するソースコード
```言語名 C# visualstudio2022
ソースコードを入力
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ProgressBar;
using System.Net.Sockets;

namespace adbClient2
{
    public partial class Form1 : Form
    {
        MyTcpClient client = new MyTcpClient("127.0.0.1", 7654);
        readonly System.Windows.Forms.Timer timer;

        Rectangle ballPos;

        Vector ballSpeed;
        const int ballRadius = 10;
        Rectangle paddlePos;
        int ballSpeedX = 5, ballSpeedY = 5;

        int ballWidth = 20;
        int ballHeight = 20;
        int paddleWidth = 100;
        int paddleHeight = 20;
        int paddleX = 150;
        int paddleY;

        int count = 0;
        Brush paddleColor = Brushes.Blue;
        Rectangle paddle;
        Rectangle ball;
        List<Rectangle> blocks = new List<Rectangle>();
        private static readonly Brush blue = Brushes.Blue;
        Brush blockColor = Brushes.Green;

        TcpListener tcpListener;
        Thread tcpThread;
        float accelX = 0f; // 加速度センサ値

        List<Rectangle> blockPos;


        public Form1()
        {
            InitializeComponent();

            client.Connected += new EventHandler(client_Connected);
            client.Disconnected += new EventHandler(client_Disconnected);
            client.DataRead += new EventHandler<DataReadEventArgs>(client_DataRead);

            pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(Draw);

            this.DoubleBuffered = true;
            this.Width = 600;
            this.Height = 600;

            paddle = new Rectangle(this.ClientSize.Width / 2 - paddleWidth / 2, this.ClientSize.Height - 50, paddleWidth, paddleHeight);
            ball = new Rectangle(this.ClientSize.Width / 2, this.ClientSize.Height / 2, ballWidth, ballHeight);



            this.ballPos = new Rectangle(200, 200, ballRadius * 2, ballRadius * 2);
            this.paddlePos = new Rectangle(100, this.Height - 50, 100, 5);
            this.blockPos = new List<Rectangle>();
            for (int x = 0; x <= this.Height; x += 100)
            {
                for (int y = 0; y <= 150; y += 40)
                {
                    this.blockPos.Add(new Rectangle(25 + x, y, 80, 25));
                }
            }

            timer = new System.Windows.Forms.Timer();
            timer.Interval = 33;
            timer.Tick += new EventHandler(Update);
            timer.Start();

            ballPos = new Rectangle(pictureBox1.Width / 2 - ballRadius, pictureBox1.Height / 2 - ballRadius, ballRadius * 2, ballRadius * 2);
            ballSpeed = new Vector(1, 1);
            this.paddlePos = new Rectangle(100, this.Height - 50, 100, 5);
            paddlePos = new Rectangle(pictureBox1.Width / 2 - 50, pictureBox1.Height - 30, 100, 10);
        }

        // 接続したときの処理
        void client_Connected(object sender, EventArgs e)
        {
            ;
            // 別のスレッドから呼び出されるのでDelegate(委譲)を経由してSetTextを実行する
            this.Invoke((MethodInvoker)delegate
            {
                SetText("Connected to Android Device\r\n");
            });
        }

        // 切断した時の処理
        void client_Disconnected(object sender, EventArgs e)
        {
            // 別のスレッドから呼び出されるのでDelegate(委譲)を経由してSetTextを実行する
            this.Invoke((MethodInvoker)delegate
            {
                SetText("Disconnected\r\n");
            });
        }

        // データを受信したときの処理
        void client_DataRead(object sender, DataReadEventArgs e)
        {
            string str;
            short accX, accY, accZ;

            accX = (short)((e.Data[0] << 8) | e.Data[1]);
            accY = (short)((e.Data[2] << 8) | e.Data[3]);
            accZ = (short)((e.Data[4] << 8) | e.Data[5]);


            str = "加速度センサの値\r\n";
            str += "x成分:" + ((float)accX / 100.0).ToString();
            str += "\r\n";
            str += "Y成分:" + ((float)accY / 100.0).ToString();
            str += "\r\n";
            str += "Z成分:" + ((float)accZ / 100.0).ToString();


            this.Invoke((MethodInvoker)delegate
            {
                SetText(str);
            });

            byte[] sendData = new byte[3];
            sendData[1] = 100;
            sendData[2] = 255;

            try
            {
                client.Write(sendData);
            }
            catch (Exception ex)
            {
                SetText(ex.Message);
            }

            if (accX > 100)
            {
                paddlePos.Offset(5, 0);
            }
            else if (accX < -100)
            {
                paddlePos.Offset(-5, 0);
            }

            if (paddlePos.Left < 0)
            {
                paddlePos.X = 0;
            }
            else if (paddlePos.Right > pictureBox1.Width)
            {
                paddlePos.X = pictureBox1.Width - paddlePos.Width;
            }
            pictureBox1.Invalidate();
        }

        private void CreateBlocks()
        {
            int blockWidth = 60;
            int blockHeight = 20;
            for (int y = 0; y < 3; y++)
            {
                for (int x = 0; x < 8; x++)
                {
                    blocks.Add(new Rectangle(10 + x * (blockWidth + 10), 50 + y * (blockHeight + 10), blockWidth, blockHeight));
                }
            }
        }

        private void Draw(object sender, PaintEventArgs e)
        {
            using (var grayBrush = new SolidBrush(Color.DimGray))
            using (var pinkBrush = new SolidBrush(Color.HotPink))
            using (var blueBrush = new SolidBrush(Color.LightBlue))
            {
                float px = (float)this.ballPos.X - ballRadius;
                float py = (float)this.ballPos.Y - ballRadius;

                e.Graphics.FillEllipse(pinkBrush, px, py, ballRadius * 2, ballRadius * 2);
                e.Graphics.FillRectangle(grayBrush, paddlePos);

                for (int i = 0; i < this.blockPos.Count; i++)
                {
                    int collision = BlockVsCircle(blockPos[i], new Vector(ballPos.X / 2 - ballRadius, ballPos.Y / 2 - ballRadius));
                    e.Graphics.FillRectangle(blueBrush, blockPos[i]);
                }
            }

            ballPos.Offset((int)ballSpeed.X, (int)ballSpeed.Y);


        }

        double DotProduct(Vector a, Vector b)
        {
            return a.X * b.X + a.Y * b.Y; // 内積計算
        }

        bool LineVsCircle(Vector p1, Vector p2, Vector center, float radius)
        {
            Vector lineDir = (p2 - p1);                   // パドルの方向ベクトル
            Vector n = new Vector(lineDir.Y, -lineDir.X); // パドルの法線
            n.Normalize();

            Vector dir1 = center - p1;
            Vector dir2 = center - p2;

            double dist = Math.Abs(DotProduct(dir1, n));
            double a1 = DotProduct(dir1, lineDir);
            double a2 = DotProduct(dir2, lineDir);

            return (a1 * a2 < 0 && dist < radius) ? true : false;
        }

        int BlockVsCircle(Rectangle block, Vector ball)
        {
            if (LineVsCircle(new Vector(block.Left, block.Top),
                new Vector(block.Right, block.Top), ball, ballRadius))
                return 1;

            if (LineVsCircle(new Vector(block.Left, block.Bottom),
                new Vector(block.Right, block.Bottom), ball, ballRadius))
                return 2;

            if (LineVsCircle(new Vector(block.Right, block.Top),
                new Vector(block.Right, block.Bottom), ball, ballRadius))
                return 3;

            if (LineVsCircle(new Vector(block.Left, block.Top),
                new Vector(block.Left, block.Bottom), ball, ballRadius))
                return 4;

            return -1;
        }

        private void Update(object sender, EventArgs e)
        {
            ballPos.Offset((int)ballSpeed.X, (int)ballSpeed.Y);
            // ボールの移動;

            // 壁バウンド処理
            if (ballPos.Left <= 0 || ballPos.Right >= pictureBox1.Width)
            {
                ballSpeed.X *= -1;
            }
            if (ballPos.Top <= 0)
            {
                ballSpeed.Y *= -1;
            }
            if (ballPos.Bottom >= pictureBox1.Height)
            {
                // ボールが下に落ちた
                ballPos.Y = pictureBox1.Height / 2;
                ballPos.X = pictureBox1.Width / 2;
                ballSpeed.Y *= -1;
            }

            // パドルとの衝突
            if (ballPos.IntersectsWith(paddlePos))
            {
                ballSpeed.Y *= -1;
                ballPos.Y = paddlePos.Top - ballRadius * 2;
            }


            // 左右の壁でのバウンド
            if (ballPos.X + ballRadius > this.Bounds.Width || ballPos.X - ballRadius < 0)
            {
                ballSpeed.X *= -1;
            }

            // 上の壁でバウンド
            if (ballPos.Y - ballRadius < 0)
            {
                ballSpeed.Y *= -1;
            }
            //パドルの当たり判定
            if (LineVsCircle(new Vector(this.paddlePos.Left, this.paddlePos.Top),
                             new Vector(this.paddlePos.Right, this.paddlePos.Top),
                             new Vector(ballPos.X / 2 - ballRadius, ballPos.Y / 2 - ballRadius),
                             ballRadius))
            {
                ballSpeed.Y *= -1;
            }

            for (int i = 0; i < this.blockPos.Count; i++)
            {
                int collision = BlockVsCircle(blockPos[i], new Vector(ballPos.X / 2 - ballRadius, ballPos.Y / 2 - ballRadius));
                if (collision == 1 || collision == 2)
                {
                    ballSpeed.Y *= -1;
                    this.blockPos.Remove(blockPos[i]);  // 追加
                }
                else if (collision == 3 || collision == 4)
                {
                    ballSpeed.X *= -1;
                    this.blockPos.Remove(blockPos[i]); // 追加
                }
            }
        }

        // テキストボックス内の文字列を設定
        public void SetText(string s)
        {
            pictureBox1.Text = s;
        }

        // フォームが出現した時の処理
        private void Form1_Load(object sender, EventArgs e)
        {
            // 接続ボタンを有効にする
            btnStart.Enabled = true;
        }

        // フォームを閉じるときの処理
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // 通信を開始していたら通信用オブジェクトを破棄する
            if (client != null)
            {
                client = null;
            }
        }

        // 接続ボタンを押したときの処理
        private void btnStart_Click(object sender, EventArgs e)
        {
            Process proc;                                       // 別アプリとの連携処理オブジェクト(窓口)を生成
            ProcessStartInfo psi = new ProcessStartInfo
            {
                FileName = System.AppDomain.CurrentDomain.BaseDirectory + "\\adb.exe",  // 起動するアプリ名(同じフォルダにある)
                Arguments = "forward tcp:7654 tcp:4567",                                // 引数
                CreateNoWindow = true,                                                  // ウィンドウは開かない
                UseShellExecute = false                                                // シェル機能は使わない
            };      // 別アプリを起動する時の設定用の変数

            proc = Process.Start(psi);                                                  // 別アプリ(adb.exe)の実行を開始
            proc.WaitForExit();                                                         // 終了するまで待つ 
            proc.Close();                                                               // 連携機能を終了
            proc.Dispose();                                                             // 連携機能の窓口を破棄
                                                                                        // コマンドプロンプト上で adb forward tcp:7654 tcp:4567 と実行したのと同じ
                                                                                        // PC上の7654番ポートとAndroid端末の4567番ポートを接続

            try
            {
                client.Connect();       // Android端末との通信を開始
            }
            catch (Exception ex)
            {
                SetText(ex.Message);    // エラー(例外)が発生した場合はエラーメッセージを表示
            }
            btnStart.Enabled = false;   // 接続ボタンを無効にする
        }

        // 色データ送信ボタンを押したときの処理
        private void button1_Click(object sender, EventArgs e)
        {
            // 色データ(RGB)を格納するための配列(3バイト分)を用意
            byte[] colorData = new byte[3];
            colorData[0] = Convert.ToByte(textBoxRed.Text);     // 第1要素(赤色のデータ)にtextBoxRed.Text(文字列)をバイトに変換してから格納
            colorData[1] = Convert.ToByte(textBoxGreen.Text);   // 第2要素(緑色のデータ)にtextBoxGreen.Text(文字列)をバイトに変換してから格納
            colorData[2] = Convert.ToByte(textBoxBlue.Text);    // 第3要素(青色のデータ)にtextBoxBlue.Text(文字列)をバイトに変換してから格納
            try
            {
                client.Write(colorData);    // Android端末へ色データを送信
            }
            catch (Exception ex)
            {
                SetText(ex.Message);        // エラー(例外)が発生した場合はエラーメッセージを表示
            }
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            // パドル移動(加速度に応じて)
            paddle.X += (int)(accelX * 10);
            if (paddle.X < 0) paddle.X = 0;
            if (paddle.X + paddleWidth > this.ClientSize.Width) paddle.X = this.ClientSize.Width - paddleWidth;

            // ボール移動
            ball.X += ballSpeedX;
            ball.Y += ballSpeedY;

            // 壁との衝突
            if (ball.Left < 0 || ball.Right > this.ClientSize.Width)
                ballSpeedX = -ballSpeedX;

            if (ball.Top < 0)
                ballSpeedY = -ballSpeedY;

            // 落下処理
            if (ball.Bottom > pictureBox1.Height)
            {
                count++; // ミス回数を増やす
                ball.X = pictureBox1.Width / 2;
                ball.Y = pictureBox1.Height / 2;
                ballSpeedY = -ballSpeedY; // ボールを上に戻す
            }

            // パドルの色をミス回数に応じて変更
            if (count >= 3)
                paddleColor = Brushes.Red;
            else
                paddleColor = Brushes.Gray;

            // パドル衝突
            if (ball.IntersectsWith(paddle))
            {
                ballSpeedY = -ballSpeedY;
                ball.Y = paddle.Top - ballHeight;
            }

            // ブロック衝突
            for (int i = 0; i < blocks.Count; i++)
            {
                if (ball.IntersectsWith(blocks[i]))
                {
                    blocks.RemoveAt(i);
                    ballSpeedY = -ballSpeedY;
                    break;
                }
            }
            paddleColor = count > 2 ? Brushes.Red : Brushes.Blue;

            // 終了条件
            if (count >= 5)
            {
                MessageBox.Show("Game Over");
                Application.Exit();
            }
            this.Invalidate();
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            // パドルを paddleColor で描画
            g.FillRectangle(paddleColor, paddle);

            // ボールを黒で描画
            g.FillEllipse(Brushes.Black, ball);

            // ブロック(必要であれば)もここで描画
            foreach (Rectangle b in blocks)
            {
                g.FillRectangle(Brushes.Green, b);
            }
        }

    }
}
0 likes

1Answer

            for (int i = 0; i < this.blockPos.Count; i++)
            {
                int collision = BlockVsCircle(blockPos[i], new Vector(ballPos.X / 2 - ballRadius, ballPos.Y / 2 - ballRadius));
                if (collision == 1 || collision == 2)
                {
                    ballSpeed.Y *= -1;
                    this.blockPos.Remove(blockPos[i]);  // 追加
                }
                else if (collision == 3 || collision == 4)
                {
                    ballSpeed.X *= -1;
                    this.blockPos.Remove(blockPos[i]); // 追加
                }
            }

forでリストをループしてる最中に要素を消そうとしないでください
消した次の要素がスキップされます

https://atmarkit.itmedia.co.jp/ait/articles/0812/04/news140.html
せめて逆順で列挙してください

for (int i = this.blockPos.Count - 1; i >= 0; i--) {
 // 省略
}
0Like

Comments

  1. @manluan8

    Questioner

    ありがとうございます

Your answer might help someone💌