現在の振り子シミュレーションに問題があり、2 つの振り子が衝突し、それぞれの振り子の中で動かなくなることがあります。
これは、1 回の繰り返しで描画されるときに、それぞれがあまりにも速くヒットした場合に発生します。
Form1 のコードは次のとおりです::
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private bool running = false;
private int updateInterval = 15;
private List<Pendulum> pendulums;
private Graphics graphics;
private int userID;
public Form1(int UserID)
{
userID = UserID;
InitializeComponent();
graphics = this.CreateGraphics();
//Pendulum setup
Pendulum.Gravity = 9.81;
Pendulum.SimSpeed = 0.005;
tbrNoOfPendulums.Value = 5;
pendulums = new List<Pendulum>(tbrNoOfPendulums.Maximum);
for (int i = 0; i < tbrNoOfPendulums.Maximum; i++)
{
pendulums.Add(new Pendulum(this.Width + i * 40 - 80, (int)nudLength.Value));
}
Task t = new Task(new Action(UpdatePendulums));
t.Start();
}
private void btnRun_Click(object sender, EventArgs e)
{
running = !running;
if (running)
{
btnRun.Text = "Running";
tbrNoOfPendulums.Enabled = false;
}
else
{
btnRun.Text = "Paused";
tbrNoOfPendulums.Enabled = true;
}
}
private void UpdatePendulums()
{
while (true)
{
System.Threading.Thread.Sleep(updateInterval);
if (!running) continue;
//Update pendulums
foreach (Pendulum p in pendulums)
{
p.Update();
}
//Detect Collision
for (int i = 0; i < pendulums.Count-1; i++)
{
pendulums[i].HandleCollision(pendulums[i+1]);
}
foreach (Pendulum p in pendulums)
{
p.Angle += p.Velocity * Pendulum.SimSpeed;
}
//Draw pendulums
try
{
graphics.Clear(this.BackColor);
}
catch { }
foreach (Pendulum p in pendulums)
{
p.Draw(graphics);
}
}
}
private void btnSet_Click(object sender, EventArgs e)
{
int index;
//which pendulum side
if (rdbLeft.Checked)
{
index = 0;
}
else
{
index = tbrNoOfPendulums.Value - 1;
}
//update angle
double angle = (double)nudAngle.Value;
//Convert from degrees to rads
angle /= 180;
angle *= Math.PI;
pendulums[index].Angle = angle;
//update velocity
pendulums[index].Velocity = (double)nudVelocity.Value;
//update damping
pendulums[index].damping = (double)nudDamping.Value;
//update gravity
Pendulum.Gravity = (double)nudGravity.Value;
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
//stops simulation running before closing to avoid "A generic error occurred in GDI+."
running = !running;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void rdbLeft_CheckedChanged(object sender, EventArgs e)
{
nudAngle.Minimum = -179;
nudAngle.Maximum = 0;
}
private void rdbRight_CheckedChanged(object sender, EventArgs e)
{
nudAngle.Minimum = 0;
nudAngle.Maximum = 179;
}
private void tbrNoOfPendulums_Scroll(object sender, EventArgs e)
{
if (tbrNoOfPendulums.Value < pendulums.Count)
{
pendulums.RemoveRange(tbrNoOfPendulums.Value, pendulums.Count - tbrNoOfPendulums.Value);
return;
}
if (tbrNoOfPendulums.Value > pendulums.Count)
{
for (int i = pendulums.Count; i < tbrNoOfPendulums.Value; i++)
{
pendulums.Add(new Pendulum(this.Width + i * 40 - 80, (int)nudLength.Value));
}
}
}
}
振り子クラス:
class Pendulum
{
public int bobX;
public int bobY;
/* -- Statics -- */
//Attributes
public static double Gravity { get; set; }
public static double SimSpeed { get; set; }
/* -- Non statics -- */
//Attributes
public int Length { get; set; }
public int Mass { get; set; }
public double Angle { get; set; }
public double Velocity { get; set; }
public int frmWidth { get; set; }
//Fields for attributes
public double damping;
//Other fields
public int originX;
public int originY = 0;
public Pendulum(int frmwidth, int length)
{
frmWidth = frmwidth;
Mass = 20;
Length = length;
Angle = 0;
}
public void Update()
{
if (Angle != 0 || Velocity != 0)
{
double aAcc = -Gravity * Math.Sin(Angle) / Length;
Velocity += aAcc;
}
}
public void Draw(Graphics g)
{
originX = frmWidth / 2;
originY = 0;
bobX = originX + (int)(Math.Sin(Angle) * Length);
bobY = originY + (int)(Math.Cos(Angle) * Length);
try
{
g.DrawLine(Pens.Red, originX, originY, bobX, bobY);
g.FillEllipse(Brushes.Black, bobX - 8, bobY, 20, 20);
}
catch { }
}
internal void HandleCollision(Pendulum other)
{
originX = frmWidth / 2;
originY = 0;
bobX = originX + (int)(Math.Sin(Angle) * Length);
bobY = originY + (int)(Math.Cos(Angle) * Length);
if (other.bobX-bobX < 20)
{
double temp = Velocity;
Velocity = other.Velocity;
other.Velocity = temp;
}
}
}
更新 - 編集: 衝突方法は次のとおりです。
if (Math.Abs(other.bobX-bobX ) < 20) //Detects if pendulums intersect
{
do //attempt at separating
{
other.bobX += 1;
bobX -= 1;
}
while (!(Math.Abs(other.bobX - bobX) > 20));
double temp = Velocity;
Velocity = other.Velocity;
other.Velocity = temp;
}