您的位置:首页 > 编程语言 > C#

C#模拟小球碰撞(图形界面)

2013-08-03 09:17 627 查看
有小BUG的。

涉及动量守和定律,和能量守恒定律。

碰撞的时候,有粘连重叠问题。求大神纠正!小弟,找了好久都没找到!



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.Threading;

namespace Cool_Graphics01
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            Thread t = new Thread(new ThreadStart(CrossThreedFlush));
            t.IsBackground = true;
            t.Start();

        }
        private delegate void DelegateGDIMove(Circle[] cs);
        //线程占用主控制权,还没有与主线程发生异步
        private void CrossThreedFlush()
        {
            Color[] color = { Color.Red, Color.Blue, Color.Green, Color.DarkOrange, Color.Black, Color.DeepPink, Color.Purple, Color.Yellow };
            Circle[] cs = new Circle[3];
            /* for (int i = 0; i < 7; i++)
             {
                 cs[i] = new Circle();
                 cs[i].Center = new PointF(50*i+50, 50*i+50);
                 cs[i].Radius = 25;
                 cs[i].MoveSpeed = 3.0f;
                 cs[i].Weight = 15;
                 cs[i].Direct = 1.2 * i + 0.2;
                 cs[i].CircleColor = color[i];
             }
            */
            cs[0] = new Circle();
            cs[0].Center = new PointF(100, 50);
            cs[0].Radius = 20;
            cs[0].MoveSpeed = 3.0f;
            cs[0].Weight = cs[0].Radius*cs[0].Radius*cs[0].Radius;
            cs[0].Direct = 0;
            cs[0].CircleColor = Color.Red;

            cs[1] = new Circle();
            cs[1].Center = new PointF(50, 50);
            cs[1].Radius = 25;
            cs[1].MoveSpeed = 3.0f;
            cs[1].Weight = cs[1].Radius*cs[1].Radius*cs[1].Radius;
            cs[1].Direct = Math.PI * 0.25;
            cs[1].CircleColor = Color.Green;

            cs[2] = new Circle();
            cs[2].Center = new PointF(50, 120);
            cs[2].Radius = 30;
            cs[2].MoveSpeed = 3.0f;
            cs[2].Weight = cs[2].Radius * cs[2].Radius * cs[2].Radius;
            cs[2].Direct = Math.PI*0.5;
            cs[2].CircleColor = Color.Blue;
            /*
            cs[3] = new Circle();
            cs[3].Center = new PointF(200, 150);
            cs[3].Radius = 32;
            cs[3].MoveSpeed = 3.0f;
            cs[3].Weight = 15;
            cs[3].Direct = 5.0;
            cs[3].CircleColor = color[4];

            cs[4] = new Circle();
            cs[4].Center = new PointF(200, 150);
            cs[4].Radius = 40;
            cs[4].MoveSpeed = 3.0f;
            cs[4].Weight = 15;
            cs[4].Direct = 1.8;
            cs[4].CircleColor = color[5];*/

            while (true)
            {
                GDIMove(cs);
                Thread.Sleep(10);
            }
        }

        //异步添加文件方法
        public void GDIMove(Circle[] cs)
        {
            if (pictureBox1.InvokeRequired)
            {
                DelegateGDIMove dgm = new DelegateGDIMove(GDIMove);
                this.Invoke(dgm, new object[] { cs });
            }
            else
            {
                CircleMove(cs);
            }
        }
        public void CircleMove(Circle[] cs)
        {
            //初始化面板
            Bitmap bmp = (Bitmap)pictureBox1.Image;
            Graphics g = Graphics.FromImage(bmp);
            g.Clear(Color.White);
            g.DrawRectangle(Pens.Black, 0, 0, pictureBox1.Width - 1, pictureBox1.Height - 1);

            //画球
            for (int i = 0; i < cs.Length; i++)
            {
                g.FillEllipse(new SolidBrush(cs[i].CircleColor), cs[i].Center.X - cs[i].Radius, cs[i].Center.Y - cs[i].Radius, cs[i].Radius * 2, cs[i].Radius * 2);
            }
            g.Dispose();
            pictureBox1.Refresh();
            GoNextPoint(cs);
        }

        public void GoNextPoint(Circle[] cs)
        {
            PointF[] nextPi = new PointF[cs.Length];
            for (int i = 0; i < cs.Length; i++)
            {
                nextPi[i] = new PointF(cs[i].Center.X + (float)Math.Cos(cs[i].Direct) * cs[i].MoveSpeed, cs[i].Center.Y + (float)Math.Sin(cs[i].Direct) * cs[i].MoveSpeed);
            }

            for (int i = 0; i < cs.Length; i++)
            {
                //碰撞到左右边界
                if (nextPi[i].X + cs[i].Radius > pictureBox1.Width || nextPi[i].X - cs[i].Radius < 0)
                {
                    cs[i].Direct = (3 * Math.PI - cs[i].Direct) % (2 * Math.PI);
                }
                else if (nextPi[i].Y + cs[i].Radius > pictureBox1.Height || nextPi[i].Y - +cs[i].Radius < 0)
                {//碰撞到上下边界
                    cs[i].Direct = (2 * Math.PI - cs[i].Direct) % (2 * Math.PI);
                }

                nextPi[i] = new PointF(cs[i].Center.X + (float)Math.Cos(cs[i].Direct) * cs[i].MoveSpeed, cs[i].Center.Y + (float)Math.Sin(cs[i].Direct) * cs[i].MoveSpeed);
                cs[i].Center = nextPi[i];
            }

            for (int i = 0; i < cs.Length; i++)
            {
                for (int j = i + 1; j < cs.Length; j++)
                {//第i个小球和其后面的cs.Length-i个小球发生碰撞可能
                    double center_distance = Math.Sqrt(Math.Pow(nextPi[i].X - nextPi[j].X, 2) + Math.Pow(nextPi[i].Y - nextPi[j].Y, 2));
                    if (center_distance <= cs[i].Radius + cs[j].Radius)
                    {//碰撞发生
                        //ruuConsole.WriteLine("*******---"+cs[i].CircleColor.ToKnownColor()+"------->"+cs[j].CircleColor.ToKnownColor()+"---******\r\n"+cs[i].ToString() + "----------------------------\r\n" + cs[j].ToString() + "----------------------------\r\n");
                        CalculateDumped2(cs[i], cs[j]);
                    }
                }
            }
        }

        public void CalculateDumped2(Circle c1, Circle c2)
        {
            double m1 = c1.Weight;
            double m2 = c2.Weight;
            double v1 = c1.MoveSpeed;
            double v2 = c2.MoveSpeed;
            double d1 = c1.Direct;
            double d2 = c2.Direct;
            double v1x = v1 * Math.Cos(d1);
            double v1y = v1 * Math.Sin(d1);
            double v2x = v2 * Math.Cos(d2);
            double v2y = v2 * Math.Sin(d2);
            v1x = Math.Round(v1x, 6);
            v2x = Math.Round(v2x, 6);
            v1y = Math.Round(v1y, 6);
            v2y = Math.Round(v2y, 6);
            double v1x_, v1y_, v2x_, v2y_;

            CalculateDumped_Line(m1, m2, v1x, v2x, out v1x_, out v2x_);
            CalculateDumped_Line(m1, m2, v1y, v2y, out v1y_, out v2y_);

            if (Verify(m1, m2, v1x, v2x, v1x_, v2x_) != 0)
            {
                MessageBox.Show("水平方向不守恒");
            }
            if (Verify(m1, m2, v1y, v2y, v1y_, v2y_) != 0)
            {
                MessageBox.Show("垂直方向不守恒");
            }

            c1.MoveSpeed = (float)Math.Sqrt(v1x_ * v1x_ + v1y_ * v1y_);
            c2.MoveSpeed = (float)Math.Sqrt(v2x_ * v2x_ + v2y_ * v2y_);

            c1.Direct = GetDirect(v1x_, v1y_);
            c2.Direct = GetDirect(v2x_, v2y_);
        }

        public double GetDirect(double vx, double vy)
        {
            if (vx == 0)
            {
                return vy < 0 ? Math.PI * 1.5 : Math.PI * 0.5;
            }
            if (vy == 0)
            {
                return vx < 0 ? Math.PI : 0;
            }
            if (vx > 0 && vy > 0)
            {
                return Math.Abs(Math.Atan(vy / vx));
            }
            if (vx < 0 && vy > 0)
            {
                return Math.Abs(Math.Atan(vy / vx)) + Math.PI * 0.5;
            }
            if (vx < 0 && vy < 0)
            {
                return Math.Abs(Math.Atan(vy / vx)) + Math.PI * 1;
            }
            if (vx > 0 && vy < 0)
            {
                return Math.Abs(Math.Atan(vy / vx)) + Math.PI * 1.5;
            }
            return 100;
        }

        public int Verify(double m1, double m2, double v1, double v2, double v1_, double v2_)
        {
            //动能
            float KE_old = (float)(0.5 * m1 * v1 * v1 + 0.5 * m2 * v2 * v2);
            float KE_new = (float)(0.5 * m1 * v1_ * v1_ + 0.5 * m2 * v2_ * v2_);
            //动量
            float momentum_old = (float)(m1 * v1 + m2 * v2);
            float momentum_new = (float)(m1 * v1_ + m2 * v2_);

            int res = 0;
            if (KE_new != KE_old)
                res += 1;
            if (momentum_new != momentum_old)
                res += 2;
            return res;
        }

        public void CalculateDumped_Line(double m1, double m2, double v1, double v2, out double v1_, out double v2_)
        {
            double x = m1 * v1 + m2 * v2;
            double a = 0.5 * m1 + 0.5 * m1 * m1 / m2;
            double b = x * m1 / m2;
            v1_ = (Math.Sqrt(0.5 * m1 * v1 * v1 + 0.5 * m2 * v2 * v2 - x * x / 2 / m2 + b * b / 4 / a) + b / 2 / Math.Sqrt(a)) / Math.Sqrt(a);
            if (Math.Round(v1_, 6) == v1)
            {
                v1_ = (-Math.Sqrt(0.5 * m1 * v1 * v1 + 0.5 * m2 * v2 * v2 - x * x / 2 / m2 + b * b / 4 / a) + b / 2 / Math.Sqrt(a)) / Math.Sqrt(a);
            }
            v2_ = (m1 * v1 + m2 * v2 - m1 * v1_) / m2;

            if (double.IsNaN(v1_))
                v1_ = 0.0;
            if (double.IsNaN(v2_))
                v2_ = 0.0;
        }

        public void CalculateDumped(Circle c1, Circle c2)
        {
            double x = c1.Weight * c1.MoveSpeed * Math.Cos(c1.Direct) + c2.Weight * c2.MoveSpeed * Math.Cos(c2.Direct);
            double a = c2.Weight * c2.Weight / (2.0 * c1.Weight) + c2.Weight / 2.0;
            double b = x * c2.Weight / c1.Weight;
            double c = (0.5 * c1.Weight * c1.MoveSpeed * Math.Cos(c1.Direct) * c1.MoveSpeed * Math.Cos(c1.Direct)) + (1.0 / 2.0 * c2.Weight * c2.MoveSpeed * Math.Cos(c2.Direct) * c2.MoveSpeed * Math.Cos(c2.Direct));
            double v2x = (Math.Sqrt(c + b * b / (4.0 * a) - x * x / 2.0 / c1.Weight) + b / (2.0 * Math.Sqrt(a))) / Math.Sqrt(a);
            double v1x = (c1.Weight * c1.MoveSpeed * Math.Cos(c1.Direct) + c2.Weight * c2.MoveSpeed * Math.Cos(c2.Direct) - c2.Weight * v2x) / c1.Weight;

            x = c1.Weight * c1.MoveSpeed * Math.Sin(c1.Direct) + c2.Weight * c2.MoveSpeed * Math.Sin(c2.Direct);
            a = c2.Weight * c2.Weight / (2.0 * c1.Weight) + c2.Weight / 2.0;
            b = x * c2.Weight / c1.Weight;
            c = 0.5 * c1.Weight * c1.MoveSpeed * Math.Sin(c1.Direct) * c1.MoveSpeed * Math.Sin(c1.Direct) + 1.0 / 2.0 * c2.Weight * c2.MoveSpeed * Math.Sin(c2.Direct) * c2.MoveSpeed * Math.Sin(c2.Direct);
            double v2y = (Math.Sqrt(c + b * b / (4.0 * a) - x * x / 2.0 / c1.Weight) + b / (2.0 * Math.Sqrt(a))) / Math.Sqrt(a);
            double v1y = (c1.Weight * c1.MoveSpeed * Math.Sin(c1.Direct) + c2.Weight * c2.MoveSpeed * Math.Sin(c2.Direct) - c2.Weight * v2y) / c1.Weight;

            //动能
            float KE_old = (float)(0.5 * c1.Weight * c1.MoveSpeed * c1.MoveSpeed + 0.5 * c2.Weight * c2.MoveSpeed * c2.MoveSpeed);
            float KE_new = (float)(0.5 * c1.Weight * (v1x * v1x + v1y * v1y) + 0.5 * c2.Weight * (v2x * v2x + v2y * v2y));
            //动量
            float momentum_old = (float)(Math.Sqrt((c1.Weight * c1.MoveSpeed * Math.Cos(c1.Direct) + c2.Weight * c2.MoveSpeed * Math.Cos(c2.Direct)) * (c1.Weight * c1.MoveSpeed * Math.Cos(c1.Direct) + c2.Weight * c2.MoveSpeed * Math.Cos(c2.Direct)) + (c1.Weight * c1.MoveSpeed * Math.Sin(c1.Direct) + c2.Weight * c2.MoveSpeed * Math.Sin(c2.Direct)) * (c1.Weight * c1.MoveSpeed * Math.Sin(c1.Direct) + c2.Weight * c2.MoveSpeed * Math.Sin(c2.Direct))));
            float momentum_new = (float)(Math.Sqrt((c1.Weight * v1x + c2.Weight * v2x) * (c1.Weight * v1x + c2.Weight * v2x) + (c1.Weight * v1y + c2.Weight * v2y) * (c1.Weight * v1y + c2.Weight * v2y)));

            if (KE_old != KE_new || momentum_old != momentum_new)
            {
                Console.WriteLine("BUG");
            }

            c1.MoveSpeed = (float)Math.Sqrt(v1x * v1x + v1y * v1y);
            c2.MoveSpeed = (float)Math.Sqrt(v2x * v2x + v2y * v2y);

            if (v1x > 0 && v1y > 0)
            {
                c1.Direct = Math.Atan(Math.Abs(v1y) / Math.Abs(v1x));
            }
            else if (v1x < 0 && v1y > 0)
            {
                c1.Direct = Math.Atan(Math.Abs(v1y) / Math.Abs(v1x)) + Math.PI / 2;

            }
            else if (v1x < 0 && v1y < 0)
            {
                c1.Direct = Math.Atan(Math.Abs(v1y) / Math.Abs(v1x)) + Math.PI;

            }
            else if (v1x > 0 && v1y < 0)
            {
                c1.Direct = Math.Atan(Math.Abs(v1y) / Math.Abs(v1x)) + Math.PI * 1.5;

            }

            if (v2x > 0 && v2y > 0)
            {
                c2.Direct = Math.Atan(Math.Abs(v2y) / Math.Abs(v2x));
            }
            else if (v2x < 0 && v2y > 0)
            {
                c2.Direct = Math.Atan(Math.Abs(v2y) / Math.Abs(v2x)) + Math.PI / 2;

            }
            else if (v2x < 0 && v2y < 0)
            {
                c2.Direct = Math.Atan(Math.Abs(v2y) / Math.Abs(v2x)) + Math.PI;

            }
            else if (v2x > 0 && v2y < 0)
            {
                c2.Direct = Math.Atan(Math.Abs(v2y) / Math.Abs(v2x)) + Math.PI * 1.5;
            }

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Environment.Exit(0);
        }
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: