Make your own free website on Tripod.com

The meat of the problem: Coding

To make the program I used Delphi 5. This is a visual programming language that I have been using for some time now for other projects, but now it suited my needs for the creation of a powerful collision engine. If you want the code, you are going to have to fill out a form requesting to be put on the waiting list...

   Actually I have it right here:

//=============================================================================

// This is the code for an application, which simulates 2d collisions of spheres

//

// Created in 2004 for AP Physics by Max Shokhirev (maxsh@earthlink.net)

//

// Please give me the credit for this code if you use it elsewhere. Thanks.

//=============================================================================

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

  StdCtrls, DXClass, DXDraws, Grids, glLabel, Spin, ExtCtrls, Math, Buttons,

  DXInput, ExtDlgs, FileCtrl, Jpeg;

 

type

   //++++++++++++++++ THE SPHERE IS DEFINED BELOW +++++++++++++++++++++++++++++

 

  TSphere = record

    x : double;    // the x position from the left in meters

    y : double;    // the y position from the top in meters

    vx: double;    // velocity in the x in meters per second

    vy: double;    // velocity in the y in meters per sound

    angle: double;  // the angle of the sphere in radians

    inv: integer;   // internal variable used for blocking polycollision

    r:  double;     // radius of the sphere in meters

    m:  double;     // mass of the sphere in kilograms

    color: integer;  // the color of the sphere used for display

  end;

  TSpheres= array[1..10] of TSphere; // this is the array containing all spheres

  TForm1 = class(TForm)   // this is the form on which all of the components are located

    Timer: TDXTimer;

    Button1: TButton;

    ComboBox1: TComboBox;

    GroupBox1: TGroupBox;

    glLabel1: TglLabel;

    glLabel2: TglLabel;

    glLabel3: TglLabel;

    glLabel7: TglLabel;

    glLabel8: TglLabel;

    glLabel9: TglLabel;

    Xspin: TEdit;

    Yspin: TEdit;

    VxSpin: TEdit;

    VySpin: TEdit;

    MassSpin: TEdit;

    SpinEdit1: TSpinEdit;

    radiusspin: TEdit;

    Draw: TPaintBox;

    Memo1: TMemo;

    Angle: TEdit;

    Anglelbl: TglLabel;

    Walls: TCheckBox;

    glLabel5: TglLabel;

    Bevel1: TBevel;

    FrictionSpin: TEdit;

    randspherebtn: TSpeedButton;

    labels: TCheckBox;

    MV: TEdit;

    KineticE: TEdit;

    glLabel6: TglLabel;

    glLabel10: TglLabel;

    TotalKinetic: TEdit;

    glLabel11: TglLabel;

    MomentumX: TEdit;

    glLabel12: TglLabel;

    MomentumY: TEdit;

    glLabel13: TglLabel;

    Save1: TSaveDialog;

    Open1: TOpenDialog;

    Save2: TSavePictureDialog;

    SaveSpheresBtn: TBitBtn;

    OpenSpheresBtn: TBitBtn;

    BitBtn1: TBitBtn;

    glLabel14: TglLabel;

    DirectoryList: TDirectoryListBox;

    Image1: TImage;

    TimerInterval: TEdit;

    glLabel4: TglLabel;

    glLabel15: TglLabel;

    SpeedButton1: TSpeedButton;

    procedure TimerTimer(Sender: TObject; LagCount: Integer);  //main timer loop procedure

    procedure XSpinChange(Sender: TObject);

    procedure YspinChange(Sender: TObject);

    procedure VxSpinChange(Sender: TObject);

    procedure VySpinChange(Sender: TObject);

    procedure MassSpinChange(Sender: TObject);

    procedure DrawScreen;        // drawing procedure

    procedure Button1Click(Sender: TObject);     //start stop for the timer procedure

    procedure SpinEdit1Change(Sender: TObject);

    procedure RadiusSpinChange(Sender: TObject);

    procedure showfirstsphere;              //debuging only

    procedure ComboBox1Click(Sender: TObject);

    procedure ComboBox1Change(Sender: TObject);

    procedure FormCreate(Sender: TObject);

    procedure FrictionSpinChange(Sender: TObject);

    procedure randspherebtnClick(Sender: TObject);

    procedure SaveSpheresBtnClick(Sender: TObject);

    procedure OpenSpheresBtnClick(Sender: TObject);

    procedure BitBtn1Click(Sender: TObject);

    procedure TimerIntervalChange(Sender: TObject);

    procedure SpeedButton1Click(Sender: TObject);  //generates random spheres

  private

    numcollisions: integer;

    friction: single;          // the coefficeint of friction

    appid : integer;

    interval: double;

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

  Spheres: Tspheres;

implementation

 

{$R *.DFM}

 

procedure TForm1.TimerTimer(Sender: TObject; LagCount: Integer);  //MAIN PROCEDURE!

var

I,J,Di,Dj: integer;

count: integer;

dist: single;

theta: single;

v1, v2 : single;

w,z,a,b,c,Vone,Vtwo : single;

begin

  if form1.caption='Form1' then form1.caption:='1';        //Here the number of cycles is shown

  count:=StrToint(Form1.caption);

  inc(count);

  Form1.caption:=IntToStr(count);

{  if strtoint(form1.caption) mod 10 = 0 then } application.ProcessMessages;

  w:=0;               //nulling variables that are used in Total Kinetic Energy and Momentum calculations.

  a:=0;

  B:=0;

  for I := 1 to 10 do

  begin

    w:=w+(spheres[i].m*(sqr(spheres[i].vx)+sqr(spheres[i].vy))/2);  // total Kinetic energy found

    a:=a+(spheres[i].m*spheres[i].vx);               //total x momentum found

    b:=b+(spheres[i].m*spheres[i].vy);               //total y momentum found

  end;

  totalkinetic.Text:=floattostr(w)+' J';            // Kinetic energy is displayed

  MomentumX.text:=floattostr(a)+' kg*N/s';          //Momentums are displayed

  MomentumY.text:=floattostr(b)+' kg*N/s';

  //---------------------------------------------

  //here the individual information for the current sphere is shown

  MV.text:=floattostr(spheres[ComboBox1.itemindex+1].m*sqrt(sqr(spheres[ComboBox1.itemindex+1].vx)+sqr(spheres[ComboBox1.itemindex+1].vx)));

  KineticE.text:=floattostr((1/2)*spheres[ComboBox1.itemindex+1].m*(sqr(spheres[ComboBox1.itemindex+1].vx)+sqr(spheres[ComboBox1.itemindex+1].vx)));

  //this major function will move the spheres incorporate friction and check for collisions of all kinds...

  for I := 1 to 10 do

  begin

    if (spheres[i].r > 0) and (spheres[i].m > 0) then

    begin

      begin

        spheres[i].angle:=arctan2(-spheres[i].vy,spheres[i].vx);  //angle of the sphere is found

        // incorporating friction here...

        if spheres[i].vx > 0 then spheres[i].vx:=spheres[i].vx+(friction*9.8*cos(spheres[i].angle+pi)*(1/interval));

        if spheres[i].vx < 0 then spheres[i].vx:=spheres[i].vx-(friction*9.8*cos(spheres[i].angle+pi)*(1/interval));

        if spheres[i].vy > 0 then spheres[i].vy:=spheres[i].vy-(friction*9.8*sin(spheres[i].angle+pi)*(1/interval));

        if spheres[i].vy < 0 then spheres[i].vy:=spheres[i].vy+(friction*9.8*sin(spheres[i].angle+pi)*(1/interval));

        {  -=-=-=-=-= OLD FRICTION FUNCTION

        if spheres[i].vx > 0 then spheres[i].vx:=spheres[i].vx-(friction*9.8*(interval / 1000)*cos(pi/4));

        if spheres[i].vx < 0 then spheres[i].vx:=spheres[i].vx+(friction*9.8*(interval / 1000)*cos(pi/4));

        if spheres[i].vy > 0 then spheres[i].vy:=spheres[i].vy-(friction*9.8*(interval / 1000)*sin(pi/4));

        if spheres[i].vy < 0 then spheres[i].vy:=spheres[i].vy+(friction*9.8*(interval / 1000)*sin(pi/4));

        }

        // end of friction incorporation

        spheres[i].x:=spheres[i].x+(spheres[i].vx / 200);   //new x position is calculated

        spheres[i].y:=spheres[i].y+(spheres[i].vy / 200);   //new y position is calculated

        if walls.Checked then   // if the walls option is turned on

        //check for collisions with walls in the x and y...

        begin

          if ((spheres[i].x+spheres[i].r) >= Draw.clientwidth) or ((spheres[i].x-spheres[i].r) <= 0) then

          begin

            spheres[i].vx:=-spheres[i].vx; // perfect ellastic collision no energy lost! Impulse IS given to sphere.

          end;

          if ((spheres[i].y+spheres[i].r) >= Draw.clientheight) or ((spheres[i].y-spheres[i].r) <= 0) then

          begin

            spheres[i].vy:=-spheres[i].vy; // perfect ellastic collision no energy lost! Impulse IS given to sphere.

          end;

        end;

        for J := 1 to 10 do

        begin

          if (spheres[j].r <> 0) and (spheres[j].m <>  0) then  // make sure we are dealing with real spheres

          begin

            dist:=sqrt(sqr(spheres[i].x-Spheres[j].x)+sqr(spheres[i].y-Spheres[j].y)); // finds the distance between two spheres

            if (dist <= (spheres[i].r+Spheres[j].r)) and (i <> J) then  //collision has occured (checks for collision)

            begin

              Di:=i;                  //this defines dummy variables

              Dj:=j;

              if I > J then           //this makes sure that the first sphere of collision is located before the second sphere

                                      //in the sphere array...

              begin

                Di:=J;

                Dj:=I

              end;

              if Spheres[Di].inv = 0 then  // this has to do with avoiding double collisions

              begin

                Spheres[Di].inv := 1;  // collision has occured (no collisions next cycle even if overlapping to avoid double collisions

                inc(numcollisions);

                theta:=arctan2((Spheres[Dj].y-Spheres[Di].y),(Spheres[Dj].x-Spheres[Di].x));  //find the angle of the collision

                //------------------ DATA IS SHOWN IN THE MEMO ------------------------------------

                memo1.clear;

                memo1.lines.append('Number of collisions: '+IntTOStr(numcollisions));

                memo1.lines.append('-------------------------------------');

                memo1.lines.append('Collision between spheres: '+IntToStr(i)+' and '+IntToStr(j));

                memo1.lines.append('Distance between: '+FloatToStr(dist)+' and total radiuses is'+floatToStr(Spheres[Di].r+Spheres[Dj].r));

                memo1.lines.append('Theta of collision: '+floatToStr(theta));

                //---------------------------------------------------------------------------

                v1:=sqrt(sqr(Spheres[Di].vx)+sqr(Spheres[Di].vy)); // the total velocity of the first sphere is found

                v2:=sqrt(sqr(Spheres[Dj].vx)+sqr(Spheres[Dj].vy)); // the same for the second sphere

                w:=(Spheres[Di].m*v1)-(Spheres[Dj].m*v2);  //the variable w is defined using known values. See main equation.

                z:=(Spheres[Di].m*sqr(v1))+(Spheres[Dj].m*sqr(v2));  //the variable z is defined using known values. See main equation.

                a:=((sqr(Spheres[Di].m)/Spheres[Dj].m)+Spheres[Di].m)/2;  // a is found for use in quadratic equation to find the final speed...

                b:=((-2*w*Spheres[Di].m)/Spheres[Dj].m)/2;   //b is found for quadratic equation

                c:=((sqr(w)/Spheres[Dj].m)-z)/2;             //c is found for quadratic equation

                Vone:=((-b)+sqrt(sqr(b)-(4*a*c)))/(2*a);    //the first possibility from the quadratic equation

                if (Vone >= v1) and (spheres[i].m >= spheres[i].m) then Vone:=((-b)-sqrt(sqr(b)-(4*a*c)))/(2*a); // if the found final velocity

                                                                 // is greater than the initial velocity then use the smaller possible v root

                Vtwo:=(w-(Spheres[Di].m*Vone))/Spheres[Dj].m;  // the final speed of the second object is found using Vone value

                Spheres[Di].vx:=cos(theta)*Vone;  //found the velocity in x for sphere1 using angle of collision and final speed found

                Spheres[Di].vy:=sin(theta)*Vone;  //found the velocity in y for sphere1 using angle of collision and final speed found

                Spheres[Dj].vx:=cos(theta)*Vtwo;  //found the velocity in x for sphere2 using angle of collision and final speed found

                Spheres[Dj].vy:=sin(theta)*Vtwo;  //found the velocity in y for sphere2 using angle of collision and final speed found

//--------------------- THIS IS OLD CODE THAT HANDLED THE COLLISION ---------------------

//--------------------- HOWEVER THE KINETIC ENERGY WAS NOT CONSERVED AND SO IT IS INCORRECT---------

 

{                Spheres[i].vx:=(cos(theta+Pi)*v2*spheres[j].m)/spheres[i].m; // new velocities (see equation for collision)

                spheres[i].vy:=(sin(theta+Pi)*v2*spheres[j].m)/spheres[i].m;

                spheres[j].vx:=(cos(theta)*v1*spheres[i].m)/spheres[j].m;

                spheres[j].vy:=(sin(theta)*v1*spheres[i].m)/spheres[j].m;

                MV.text:=floattostr(Spheres[i].m*(sqrt(sqr(Spheres[i].vx)+sqr(Spheres[i].vy))));

                KineticE.text:=floattostr((1/2)*Spheres[i].m*sqr(sqrt(sqr(Spheres[i].vx)+sqr(Spheres[i].vy))));

}                exit;  // make sure that we are done with these two spheres

              end;

            end;

          end;

        end;

      end;

      if spheres[i].inv > 0 then dec(spheres[i].inv);  // blocks polycollisions

    end;

  end;

  Drawscreen;      // draw the new fram using the new velocities for the spheres

end;

 

// THESE PROCEDURES DEAL WITH THE GENERAL PROGRAM INTERFACE (NO PHYSICS HERE)

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-

procedure TForm1.XSpinChange(Sender: TObject);

begin

  if (xspin.text <> '') and (xspin.text <> '-') then Spheres[ComboBox1.ItemIndex+1].x:=StrToFloat(Xspin.text);

end;

 

procedure TForm1.YspinChange(Sender: TObject);

begin

  if (yspin.text <> '') and (yspin.text <> '-') then   Spheres[ComboBox1.ItemIndex+1].y:=StrToFloat(yspin.text);

end;

 

procedure TForm1.VxSpinChange(Sender: TObject);

begin

  if (vxspin.text <> '') and (vxspin.text <> '-') then Spheres[ComboBox1.ItemIndex+1].vx:=StrToFloat(Vxspin.text);

end;

 

procedure TForm1.VySpinChange(Sender: TObject);

begin

  if (vyspin.text <> '') and (vyspin.text <> '-') then Spheres[ComboBox1.ItemIndex+1].vy:=StrToFloat(Vyspin.text);

end;

 

procedure TForm1.MassSpinChange(Sender: TObject);

begin

  if (massspin.text <> '') and (massspin.text <> '-') then Spheres[ComboBox1.ItemIndex+1].m:=StrToFloat(Massspin.text);

end;

 

procedure TForm1.DrawScreen; // THIS PROCEDURE DRAWS THE SPHERES ON THE SCREEN

var

I : integer;

Hidden : Tbitmap;

S,D : Trect;

begin

  Hidden:= Tbitmap.create;

  Hidden.Height:=draw.clientheight;

  Hidden.width:=draw.clientwidth;

  Hidden.canvas.Brush.color:=clwhite;

  Hidden.canvas.Pen.color:=clwhite;

  Hidden.canvas.Rectangle(0,0,Draw.clientwidth,Draw.clientheight);

  s.Left:=0;

  s.top:=0;

  s.Right:=hidden.Width;

  s.Bottom:=hidden.height;

  d.Left:=0;

  d.top:=0;

  d.Right:=draw.clientWidth;

  d.Bottom:=draw.clientheight;

  for I := 1 to 10 do

  begin

    if (spheres[i].x> 0) and (spheres[i].x < Draw.clientwidth) then

    begin

      if (spheres[i].y> 0) and (spheres[i].y < Draw.clientheight) then

      begin

        if spheres[i].m >  0 then

        begin

          Hidden.canvas.brush.Color:=Spheres[i].color;

          Hidden.canvas.pen.Color:=Spheres[i].color;

          Hidden.canvas.Ellipse(Trunc(Spheres[i].x-Spheres[i].r),Trunc(Spheres[i].y-Spheres[i].r),Trunc(Spheres[i].x+Spheres[i].r),Trunc(SPheres[i].y+Spheres[i].r));

          if labels.Checked then  // drawing the labels on the spheres

          begin

            Hidden.canvas.Font.color:=Spheres[i].color+20000;

            Hidden.canvas.font.size:=6;

            Hidden.canvas.font.height:=-11;

            Hidden.canvas.font.name:='Arial';

            Hidden.canvas.TextOut(Trunc(Spheres[i].x-Spheres[i].r/2),Trunc(Spheres[i].y-Spheres[i].r/2),IntToStr(i));

          end;

        end;

      end;

    end;

  end;

  draw.Canvas.CopyRect(D,hidden.canvas,S);

  hidden.Free;

  Combobox1change(form1);

end;

 

procedure TForm1.Button1Click(Sender: TObject);  // RUN/STOP BUTTON

begin

  if Timer.enabled=true then

  begin

    timer.enabled:=false;

    GroupBox1.enabled:=true;

    exit;

  end;

  If Timer.enabled=false then

  begin

    timer.enabled:=true;

    GroupBox1.enabled:=false;

  end;

end;

 

//-=-=-=-=--=-= MORE INTERFACE PROCEDURES -=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-

 

procedure TForm1.SpinEdit1Change(Sender: TObject);

begin

  if (spinedit1.text <> '') and (spinedit1.text <> '-') then

  begin

    randomize;

    Spheres[ComboBox1.ItemIndex+1].color:=SpinEdit1.value*10000+random(10000);

    spinedit1.color:=Spheres[ComboBox1.ItemIndex+1].color;

    spinedit1.font.color:=Spheres[ComboBox1.ItemIndex+1].color+20000;

  end;

end;

 

procedure TForm1.RadiusSpinChange(Sender: TObject);

begin

  if (radiusspin.text <> '') and (radiusspin.text <> '-') then

    Spheres[ComboBox1.ItemIndex+1].r:=StrToFloat(Radiusspin.text);

end;

 

procedure TForm1.showfirstsphere;

begin

  // used for debuging only...

  memo1.clear;

  memo1.lines.append(FloatToStr(spheres[1].x)+'/'+floattostr(spheres[1].y));

  memo1.lines.append(FloatToStr(spheres[1].vx)+'/'+floattostr(spheres[1].vy));

  memo1.lines.append(FloatToStr(spheres[1].r)+'/'+floattostr(spheres[1].m));

end;

 

procedure TForm1.ComboBox1Click(Sender: TObject);

begin

  //interface stuff

  Xspinchange(form1);

  yspinchange(form1);

  vXspinchange(form1);

  vyspinchange(form1);

  radiusspinchange(form1);

  massspinchange(form1);

  spinedit1change(form1);

end;

 

procedure TForm1.ComboBox1Change(Sender: TObject);

begin

  //interface stuff

  Xspin.Text:=Floattostr(spheres[combobox1.itemindex+1].x);

  yspin.Text:=Floattostr(spheres[combobox1.itemindex+1].y);

  vxspin.Text:=Floattostr(spheres[combobox1.itemindex+1].vx);

  vyspin.Text:=Floattostr(spheres[combobox1.itemindex+1].vy);

  radiusspin.Text:=Floattostr(spheres[combobox1.itemindex+1].r);

  massspin.Text:=Floattostr(spheres[combobox1.itemindex+1].m);

  spinedit1.Value:=Trunc(spheres[combobox1.itemindex+1].color / 10000);

  Angle.text:=floattostr((spheres[combobox1.itemindex+1].angle*360)/(2*Pi));

end;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  ComboBox1.itemindex:=0;

  randomize;

  appid:=random(999999);

  BitBtn1.caption:='Snap Shot '+IntTOStr(appid);

  interval:=5;

end;

 

// =-=-=-=-=-=-=-=-=-=-=-- INTERFACE STUFF AGAIN -=-=-=-=-=-=-=-=-=-==-=-=-=-=

procedure TForm1.FrictionSpinChange(Sender: TObject);

begin

  if (frictionspin.text<>'') and (frictionspin.text<>'-') then friction:=strtofloat(frictionspin.text);

  if friction <0 then friction:=0;

end;

 

procedure TForm1.randspherebtnClick(Sender: TObject);

begin

  // this generates a random sphere using the Gaussian curve (BELL CURVE)

  randomize;

  spheres[combobox1.itemindex+1].r:=randg(10,3);

  spheres[combobox1.itemindex+1].x:=randg(400,100-spheres[combobox1.itemindex+1].r);

  spheres[combobox1.itemindex+1].y:=randg(400,100-spheres[combobox1.itemindex+1].r);

  spheres[combobox1.itemindex+1].vx:=randg(50,20);

  spheres[combobox1.itemindex+1].vy:=randg(50,20);

  spheres[combobox1.itemindex+1].m:=randg(20,20);

  spheres[combobox1.itemindex+1].color:=random(999999);

  combobox1change(form1);

end;

 

procedure TForm1.SaveSpheresBtnClick(Sender: TObject);       // procedure for saving all spheres to file

var

f: textfile;

fname: string;

i: integer;

begin

  if MessageDLg('Are you sure you want to save?',MTCONFIRMATION,[Mbyes,Mbno],0)= mryes then

  begin

    if Save1.execute then

    begin

      fname:=save1.filename;

      assignfile(f,fname);

      rewrite(f);

      writeln(f,Form1.caption);

      writeln(f,numcollisions);

      writeln(f,friction);

      writeln(f,walls.checked);

      writeln(f,labels.checked);

      for I := 1 to 10 do

      begin

        writeln(f,spheres[i].x);

        writeln(f,spheres[i].y);

        writeln(f,spheres[i].vx);

        writeln(f,spheres[i].vy);

        writeln(f,spheres[i].angle);

        writeln(f,spheres[i].inv);

        writeln(f,spheres[i].r);

        writeln(f,spheres[i].m);

        writeln(f,spheres[i].color);

      end;

      closefile(f);

    end;

  end;

end;

 

procedure TForm1.OpenSpheresBtnClick(Sender: TObject);  //procedure for loading spheres from a file

var

f: textfile;

fname: string;

i: integer;

str: string;

begin

  if MessageDLg('Are you sure you want to load?',MTCONFIRMATION,[Mbyes,Mbno],0)= mryes then

  begin

    if Open1.execute then

    begin

      fname:=open1.filename;

      assignfile(f,fname);

      reset(f);

      readln(f,str);

      Form1.caption:=str;

      readln(f,numcollisions);

      readln(f,friction);

      readln(f,str);

      if str='TRUE' then walls.checked:=true;

      if str='FALSE' then walls.checked:=false;

      readln(f,str);

      if str='TRUE' then labels.checked:=true;

      if str='FALSE' then labels.checked:=false;

      for I := 1 to 10 do

      begin

        readln(f,spheres[i].x);

        readln(f,spheres[i].y);

        readln(f,spheres[i].vx);

        readln(f,spheres[i].vy);

        readln(f,spheres[i].angle);

        readln(f,spheres[i].inv);

        readln(f,spheres[i].r);

        readln(f,spheres[i].m);

        readln(f,spheres[i].color);

      end;

      closefile(f);

    end;

  end;

end;

 

procedure TForm1.BitBtn1Click(Sender: TObject);

//-=-=-=-=-=-=-=- TAKING A SNAP SHOT OF THE ACTION! -=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=

var

Hidden: TBitmap;

s,d: Trect;

jp: TJpegImage;

f: textfile;

fname: string;

I : integer;

begin

  fname:=Directorylist.directory+'\'+IntTOStr(appid)+' '+form1.caption+'.txt';

  assignfile(f,fname);

  rewrite(f);

  writeln(f,DateToStr(date));

  writeln(f,TimeToStr(time));

  writeln(f,form1.caption+' = number of cylcles');

  writeln(f,IntToStr(numcollisions)+' = number of collisions');

  writeln(f,'--------------------------');

  writeln(f,'Walls enabled?');

  writeln(f,walls.checked);

  writeln(f,'Labels enabled?');

  writeln(f,labels.checked);

  writeln(f,'--------------------------');

  writeln(f,Totalkinetic.text+' = Total kinetic energy.');

  writeln(f,momentumx.text+' = Total momentum in the x.');

  writeln(f,momentumy.text+' = Total momentum in the y.');

  writeln(f,'-------SPHERES:--------------');

  for I := 1 to 10 do

  begin

    if (spheres[i].m> 0) and (spheres[i].r > 0) then

    begin

      writeln(f,' SPHERE # ' +IntTOStr(I));

      writeln(f,'--------------------------');

      writeln(f,'X: '+FloatToStr(spheres[i].x));

      writeln(f,'Y: '+FloatToStr(spheres[i].y));

      writeln(f,'VX: '+FloatToStr(spheres[i].vx));

      writeln(f,'VY: '+FloatToStr(spheres[i].vy));

      writeln(f,'MASS: '+FloatToStr(spheres[i].m));

      writeln(f,'Radius: '+FloatToStr(spheres[i].r));

      writeln(f,'Angle: '+FloatToStr(spheres[i].angle));

      writeln(f,'Color: '+IntTOStr(spheres[i].color));

      writeln(f,'~~~~~~~~~~~~~');

      writeln(f,'MV: '+FloatToStr(Spheres[i].m*sqrt(sqr(spheres[i].vx)+sqr(spheres[i].vy))));

      writeln(f,'Kinetic Energy: '+FloatToStr((1/2)*spheres[i].m*(sqr(spheres[i].vx)+sqr(spheres[i].vy)))+' Joules');

      writeln(f,'--------------------------');

    end;

  end;

  closefile(f);

  Hidden:= Tbitmap.create;

  Hidden.Height:=draw.clientheight;

  Hidden.width:=draw.clientwidth;

  Hidden.canvas.Brush.color:=clwhite;

  Hidden.canvas.Pen.color:=clwhite;

  Hidden.canvas.Rectangle(0,0,Draw.clientwidth,Draw.clientheight);

  s.Left:=0;

  s.top:=0;

  s.Right:=hidden.Width;

  s.Bottom:=hidden.height;

  d.Left:=0;

  d.top:=0;

  d.Right:=draw.clientWidth;

  d.Bottom:=draw.clientheight;

  hidden.Canvas.CopyRect(d,draw.canvas,s);

  jp:= TJpegImage.Create;

  try

    with jp do

    begin

      assign(Hidden);

      SaveToFile(Directorylist.directory+'\'+IntTOStr(appid)+' '+form1.caption+'.jpg');

    end;

  finally

  hidden.free;

  jp.free;

  end;

end;

 

procedure TForm1.TimerIntervalChange(Sender: TObject);

begin

  //changing the timer interval in run-time

  if timerInterval.text<> '' then

  begin

    interval := StrTofloat(TimerInterval.text);

    Timer.Interval:=trunc(abs(interval));

  end;

end;

 

procedure TForm1.SpeedButton1Click(Sender: TObject);

begin

  //interface stuff

  appid:=random(999999);

  BitBtn1.caption:='Snap Shot '+IntToStr(appid);

end;

 

end.  // end of code thank you.

.