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); } } }
相关文章推荐
- .NET GDI 模拟小球弹性碰撞(质点,动能守恒)
- js小球碰撞模拟小球落下
- C# Winform利用POST传值方式模拟表单提交数据(Winform与网页交互)
- 排序网络(C#模拟)
- C#模拟web请求,使用post提交带有文件的数据表单
- C#利用Label标签控件模拟窗体标题的移动及窗体颜色不断变换效果
- C# 模拟上传图片
- 控制台应用程序模拟银行取款(C#)
- (转)C#模拟键盘鼠标事件
- 网络编程(自定义图形界面浏览器-Tomcat服务端). 模拟IE 的请求
- c#第一篇 在WPF的window窗体中使用httpwebrequest实现模拟登陆网页,并在webbroser控件中显示
- C# 中使用System.Net.Http.HttpClient 模拟登录博客园 (GET/POST)
- C# 模拟 鼠标 键盘操作
- C# 利用 HttpWebRequest 和 HttpWebResponse 模拟登录有验证码的网站
- 用 c# 使用HttpWebRequest模拟登陆(带验证码)
- C# 模拟单击网页链接
- C#模拟Post和Get方式发送数据
- C#用WebBrowser与WIN API辅助模拟获取网站完整Cookie
- c#模拟登录,cookie问题
- C#模拟登录总结