0

我的 Pendulum 模拟目前有问题。
在我的程序中,您选择要通过滑块修改其值的摆锤,然后单击更新按钮将该摆锤更新为用户选择的属性。
还有一个默认和零按钮,两者都修改该摆的值。长度在每个计时器滴答时都会改变,因此它普遍相同。
还有第二个滑块选择屏幕上显示的钟摆数量(1 到 5)。

问题是屏幕上看不到其他钟摆。

这是我的代码...
frmPendulm:

public partial class frmPendulum : Form
{
    private Timer timer;
    private List<Pendulum> pendulums;

    //all public static so they are actually global (can be used between classes and not just global to this class, mock flexibility).
    public static double angle = 0; //pendulums arm angle
    public static double aAcc = 0.00; //Angle acceleration
    public static double aVel = 0.00; //anglular velocity
    public static double damping = 0.000; //friction //friction
    public static double gravity = 0.0; //make gravity a constant

    public frmPendulum()
    {
        InitializeComponent();
        this.Shown += new EventHandler(frmPendulum_Shown);
        this.Paint += new PaintEventHandler(frmPendulum_Paint);
    }

    void frmPendulum_Shown(object sender, EventArgs e)
    {   
        //initialize the range for tbrPend
        tbrPend.Maximum = tbrNoOfPend.Value;

        pendulums = new List<Pendulum>(tbrNoOfPend.Maximum);
        for (int i = 0; i < tbrNoOfPend.Value; i++)
        {
            pendulums.Add(new Pendulum(this.Width + i * 40, this.Height, 0,0,0,0,0));
        }

        timer = new Timer() { Interval = 100 };
        timer.Tick += delegate(object s2, EventArgs e2)
        {
                this.SuspendLayout();
                this.Refresh();
                this.ResumeLayout();
                Pendulum.length = tbrLength.Value; //means length is changed on all pendulums
                updateValueVisuals();
        };
        timer.Start();
    }

    public void updateValueVisuals()
    {
        lblLength.Text= ("Length: " + Pendulum.length);
        lblAngle.Text = ("Angle: " + ((double)tbrAngle.Value) / 100.0);
        lblVel.Text = ("Vel: " + ((double)tbrAVel.Value) / 100.0);
        lblDamp.Text = ("Damping: " + ((double)tbrDamp.Value) / 100.0);
        lblGrav.Text = ("Gravity: " + ((double)tbrGrav.Value) / 100.0);
    }

    void frmPendulum_Paint(object sender, PaintEventArgs e)
    {
        foreach (Pendulum pendulum in pendulums)
        {
            pendulum.DrawPendulum(e.Graphics);
        }
    }


    private void btnDefault_Click(object sender, EventArgs e)
    {
        //sets values to a good calibration by default.
        Pendulum.length = 50;
        angle = Math.PI / 2; 
        aAcc = 0.00;           
        aVel = 0.00; 
        damping = 0.995; 
        gravity = 0.4; 

        UpdateSliders();
        effectSelectedPendulum(aAcc, aVel, damping, angle, gravity);
    }



    private void UpdateSliders()  
    {
        tbrLength.Value = Pendulum.length;
        tbrAngle.Value = (int)(angle * 100.0); 
        //tbrAAcc.Value = (int) Pendulum.aAcc; //Removed acceleration as it is re-calculated anyway.
        tbrAVel.Value = (int)(aVel* 100.0); 
        tbrDamp.Value = (int)(damping * 100.0); 
        tbrGrav.Value = (int)(gravity * 100.0);
    }

    private void btnUpdateValues_Click(object sender, EventArgs e)
    {
        /** The trackbars only use ilnteger values so to increment in decimals certain vaues have to be divided by 100 so they are correct in the simulation.
         * For example is I want the gravity to be 0.4 my track bars value will have to be 40 / 100 = 0.40 
         * Another example will be angle that will go from -3 to 3 incrementing in decimals we go from -300 to 300 /100 = 3 **/

        Pendulum.length = tbrLength.Value; //length is ok as it is an integer
        angle = ((double)tbrAngle.Value) / 100.0; //both numerator and denominator must be of the same type.
        // acceleration is calculated so isn't sent
        aVel = ((double)tbrAVel.Value) / 100.0;
        damping = ((double)tbrDamp.Value) / 100.0;
        gravity = ((double)tbrGrav.Value) / 100.0;

        effectSelectedPendulum(aAcc, aVel, damping, angle, gravity);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        //zero's everything except length.
        Pendulum.length = 10; //can't be 0 must be 10
        angle = 0; 
        aAcc = 0.00; 
        aVel = 0.00; 
        damping = 0; 
        gravity = 0; 

        UpdateSliders();
        effectSelectedPendulum(aAcc, aVel, damping, angle, gravity);
    }


    private void effectSelectedPendulum(double aAcc, double aVel, double damping, double angle, double gravity)
    {
         int index = tbrPend.Value - 1;
         pendulums[index] = new Pendulum(Width + index * 40, ClientRectangle.Height, aAcc, aVel, damping, angle, gravity);
    }

    private void tbrNoOfPend_ValueChanged(object sender, EventArgs e)
    {
        tbrPend.Maximum = tbrNoOfPend.Value;

        if (tbrNoOfPend.Value < pendulums.Count)
        {
            pendulums.RemoveRange(tbrNoOfPend.Value, pendulums.Count - tbrNoOfPend.Value);
            return;
        }

        if (tbrNoOfPend.Value > pendulums.Count)
        {
            for (int i = pendulums.Count; i < tbrNoOfPend.Value; i++)
            {
                pendulums.Add(new Pendulum(this.Width + i * 40, this.ClientRectangle.Height, 0, 0, 0, 0, 0));
            }
        }
    }

}

摆锤类:

class Pendulum
{
    public static int length = 10;//length of arm /** can't be less than 0 or will break.

    int originX = 0;
    int originY = 0; //allways 0
    int bobX; // = frmWidth / 2;
    int bobY; // = (int)length; Drawn in pendulm as don't really need to be global. Are currently for flexibilty.
    //public static int returnvalue;

    Timer timer; //global for flexibility

    public Pendulum(int frmWidth, int frmHeight, double aAcc, double aVel, double damping, double angle, double gravity)  
    {
        timer = new Timer() { Interval = 30 };

        originX = frmWidth / 2;

        timer.Tick += delegate(object sender, EventArgs e)
        {
            //-----------------drawing variables------------------------------//
            originY = 0;
            //to be relative to origin we go:
            bobX = originX + (int)(Math.Sin(angle) * length);
            bobY = originY + (int)(Math.Cos(angle) * length);

            //gravity
            aAcc = (-1 * gravity / length) * Math.Sin(angle); //calculate acceleration
            aVel += aAcc;//increment velcocity
            angle += aVel;//incrment angle

            aVel *= damping;//friction action, pendulum eventually 0's



        };
        //returnvalue = string.Format("{0}Length:" + length + ",{0} Angle: " + angle + ",{0}Vel: " + aVel + ",{0}Damping: " + damping + ",{0}Gravity: " + gravity, Environment.NewLine);
        timer.Start();
    }

    public void DrawPendulum(Graphics g) 
    {
        g.DrawLine(Pens.Red, originX, originY, bobX, bobY);
            g.FillEllipse(Brushes.Black, bobX - 8 , bobY, 20, 20); //-8 to make it look more central!
    }
}
4

1 回答 1

0

不要在一开始就创建所有的钟摆。创建的摆数和滑块的最大值tbrPend应受滑块实际值的影响tbrNoOfPend

我建议使用 aList<Pendulum>并摆脱变量p1to p5

private List<Pendulum> pendulums;

void frmPendulum_Shown(object sender, EventArgs e)
{
    // initialize the range for tbrPend
    tbrPend.Maximum = tbrNoOfPend.Value;

    pendulums = new List<Pendulum>(tbrNoOfPend.Maximum);
    for (int i = 0; i < tbrNoOfPend.Value; i++)
    {
        pendulums.Add(new Pendulum(this.Width + i * 40, this.ClientRectangle.Height, 0, 0, 0, 0, 0));
    }

    timer = new Timer()
    {
        Interval = 100
    };
    timer.Tick += delegate(object s2, EventArgs e2)
    {
        this.SuspendLayout();
        this.Refresh();
        this.ResumeLayout();
        Pendulum.length = tbrLength.Value; //means length is changed on all pendulums
        updateValueVisuals();
    };
    timer.Start();
}

现在Paint事件处理程序和effectSelectedPendulum方法变得更好:

void frmPendulum_Paint(object sender, PaintEventArgs e)
{
    foreach (Pendulum pendulum in pendulums)
    {
        pendulum.DrawPendulum(e.Graphics);
    }
}

private void effectSelectedPendulum(double aAcc, double aVel, double damping, double angle, double gravity)
{
    int index = tbrPend.Value - 1;

    pendulums[index] = new Pendulum(Width + index * 40, ClientRectangle.Height, aAcc, aVel, damping, angle, gravity);
}

您唯一需要添加的是滑块ValueChanged事件的处理程序。tbrNoOfPend您可以在此处更新滑块的最大值tbrPend并分别创建或删除钟摆:

private void tbrNoOfPend_ValueChanged(object sender, EventArgs e)
{
    tbrPend.Maximum = tbrNoOfPend.Value;

    if (tbrNoOfPend.Value < pendulums.Count)
    {
        pendulums.RemoveRange(tbrNoOfPend.Value, pendulums.Count - tbrNoOfPend.Value);
        return;
    }

    if (tbrNoOfPend.Value > pendulums.Count)
    {
        for (int i = pendulums.Count; i < tbrNoOfPend.Value; i++)
        {
            pendulums.Add(new Pendulum(this.Width + i * 40, this.ClientRectangle.Height, 0, 0, 0, 0, 0));
        }
    }
}
于 2013-10-26T13:57:07.663 回答