1

現在の振り子シミュレーションに問題があり、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;


         }
4

1 に答える 1

1

HandleCollisionでは、衝突が検出されたときに、速度を変更するだけでなく、振り子が接触するが重ならないように振り子を移動します。

于 2013-10-30T16:37:50.340 に答える