现在在我的程序中已经到了这样的地步,我有 5 个摆动的钟摆,它们都被滑块值一次修改。这些值被绘制到 from 并通过类摆。要更改值,请运行更新按钮,它们是使用有效设置的默认选项。这些值也通过一些简单的标签显示在屏幕上。零按钮将所有值(长度除外)设置为零。
现在我的下一个任务是让钟摆“真实地”碰撞并重新创建牛顿摇篮式效果。我研究了粒子的弹性碰撞解决方案,例如这里是一个很好的例子:Ball to Ball Collision - Detection and Handling
我也在这里查看了它背后的原始物理,但我的大脑无法掌握事物的原始物理方面。
所以我想知道是否有人可以帮助我弄清楚碰撞的理论。
我目前的想法是当坐标遇到速度时,将简单地改变极性,例如在相反的钟摆中 +10 到 -10。我在这里正确吗?
这是我的钟摆课程:
class Pendulum
{
//all public static so they are actually global (can be used between classes and not just global to this class).
public static int length = 10;//length of arm /** can't be less than 0 or will break.
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
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.
Timer timer; //global for flexibility
public Pendulum(int frmWidth, int frmHeight)
{
timer = new Timer() { Interval = 30 };
timer.Tick += delegate(object sender, EventArgs e)
{
//-----------------drawing variables------------------------------//
originX = frmWidth / 2;
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
};
timer.Start();
}
public void DrawPendulum(Graphics g)
{
g.DrawLine(Pens.Black, originX, originY, bobX, bobY);
g.FillEllipse(Brushes.Red, bobX - 8, bobY, 20, 20); //-8 to make it look more central!
}
}
这是表单代码:
public partial class frmPendulum : Form
{
private Timer timer;
private Pendulum p1 = null;
private Pendulum p2 = null;
private Pendulum p3 = null;
private Pendulum p4 = null;
private Pendulum p5 = null;
public frmPendulum()
{
InitializeComponent();
this.Shown += new EventHandler(frmPendulum_Shown);
this.Paint += new PaintEventHandler(frmPendulum_Paint);
}
void frmPendulum_Shown(object sender, EventArgs e)
{
p1 = new Pendulum(this.ClientRectangle.Width, this.ClientRectangle.Height);
p2 = new Pendulum(this.ClientRectangle.Width + 40, this.ClientRectangle.Height);
p3 = new Pendulum(this.ClientRectangle.Width - 40, this.ClientRectangle.Height);
p4 = new Pendulum(this.ClientRectangle.Width - 80, this.ClientRectangle.Height);
p5 = new Pendulum(this.ClientRectangle.Width + 80, this.ClientRectangle.Height);
timer = new Timer() { Interval = 100 };
timer.Tick += delegate(object s2, EventArgs e2)
{
this.Refresh();
Value.Text = string.Format("Length: " + Pendulum.length + "{0}Angle: " + Pendulum.angle + "{0}Acc: " + Pendulum.aAcc + "{0}Vel: " + Pendulum.aVel + "{0}Damping: " + Pendulum.damping + "{0}Gravity: " + Pendulum.gravity, Environment.NewLine);
value2.Text = string.Format("Length: " + tbrLength.Value + "{0}Angle: " + ((double)tbrAngle.Value) / 100.0 + "{0}Vel: " + ((double)tbrAVel.Value) / 100.0 + "{0}Damping: " + ((double)tbrDamp.Value) / 100.0 + "{0}Gravity: " + ((double)tbrGrav.Value) / 100.0, Environment.NewLine);
};
timer.Start();
}
void frmPendulum_Paint(object sender, PaintEventArgs e)
{
switch (tbrNoOfPend.Value)
{
case 1:
if (p1 != null) //if used because the Paint() event could occur BEFORE "p1"etc. has been instantiated.
{
p1.DrawPendulum(e.Graphics);
}
break;
case 2:
if (p2 != null)
{
p2.DrawPendulum(e.Graphics);
}
goto case 1;
case 3:
if (p3 != null)
{
p3.DrawPendulum(e.Graphics);
}
goto case 2;
case 4:
if (p4 != null)
{
p4.DrawPendulum(e.Graphics);
}
goto case 3;
case 5:
if (p5 != null)
{
p5.DrawPendulum(e.Graphics);
}
goto case 4;
default:
break;
}
}
private void btnDefault_Click(object sender, EventArgs e)
{
//sets values to a good calibration by default.
Pendulum.length = 50;
Pendulum.angle = Math.PI / 2; //pendulums arm angle
Pendulum.aAcc = 0.00; //Angle acceleration
Pendulum.aVel = 0.00; //anglular velocity
Pendulum.damping = 0.995; //friction //friction
Pendulum.gravity = 0.4; //make gravity a constant
UpdateSliders();
}
private void UpdateValues()
{
/** The trackbars only use integer values so to increment in decimals certain values 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
Pendulum.angle = ((double)tbrAngle.Value) / 100.0; //both numerator and denominator must be of the same type.
// acceleration is calculated so isn't sent
Pendulum.aVel = ((double)tbrAVel.Value) / 100.0;
Pendulum.damping = ((double)tbrDamp.Value) / 100.0;
Pendulum.gravity = ((double)tbrGrav.Value) / 100.0;
}
private void UpdateSliders()
{
tbrLength.Value = Pendulum.length;
tbrAngle.Value = (int)(Pendulum.angle * 100.0); //pendulums arm angle
//tbrAAcc.Value = (int) Pendulum.aAcc; //Removed acceleration as it is re-calculated anyway.
tbrAVel.Value = (int)(Pendulum.aVel* 100.0); //anglular velocity
tbrDamp.Value = (int)(Pendulum.damping * 100.0); //friction //friction
tbrGrav.Value = (int)(Pendulum.gravity * 100.0); //make gravity a constant
}
private void btnUpdateValues_Click(object sender, EventArgs e)
{
UpdateValues();
//this.Shown += new EventHandler(frmPendulum_Shown);
//this.Paint += new PaintEventHandler(frmPendulum_Paint);
}
private void button1_Click(object sender, EventArgs e)
{
//zero's everything except length.
Pendulum.angle = 0; //pendulums arm angle
Pendulum.aAcc = 0.00; //Angle acceleration
Pendulum.aVel = 0.00; //anglular velocity
Pendulum.damping = 0; //friction //friction
Pendulum.gravity = 0; //make gravity a constant
UpdateSliders();
}
}