2013-10-26 69 views
0

目前我的擺錘模擬有問題。
在我的程序中,您可以選擇要通過滑塊修改值的擺錘,然後在單擊更新按鈕時將該擺錘更新爲用戶選擇的屬性。
還有一個默認和零按鈕,都修改該擺的值。長度在每個計時器滴答聲上發生變化,因此它的通用性也相同。
還有第二個滑塊可以選擇屏幕上顯示的擺數(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! 
    } 
} 

回答

0

不要建立在一開始所有的鐘擺。創建的擺的數量和tbrPend滑塊的最大值應該受tbrNoOfPend滑塊的實際值的影響。

我會建議使用List<Pendulum>並擺脫變量p1p5

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滑塊,並創建或刪除分別在pendulumns:

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)); 
     } 
    } 
} 
+0

我已經看了這個解決方案再跟其他人關於這個之後,我認爲你是對的,也不會接受,直到我儘管已經嘗試過了。 –

+0

我已經通過我的程序運行此代碼,但由於某種原因,現在我沒有看到多個鐘擺。我會用我的新代碼更新我的答案,因爲我似乎無法看到什麼是錯的......所有的邏輯對我來說似乎都是正確的。 –

+0

@CoreyFord我複製你的更新代碼後經歷了同樣的情況。 'tbrLength.Value'最初設置爲0,然後將'Pendulum.length'更新爲0.因此擺的計算永遠拋出異常。 – pescolino