I am trying to make a shape move towards onother using 2 shapes and 2 timer, but i really can't seem. I was thinking:
At the beggining, I will make shape 1 calculate the distance of shape 2 and then move towards it, this is what i have done, i have also added comments to help you understand the code, because it is a little bit confusing:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
timer1.Interval:=100; //set interval=200
//begin
if shape1.Left=shape2.Left then
begin
shape1.Left:=shape1.left //If shape's 1 coordinates = shape's 2 then
end else //shape1.left:=stop moving else do
begin //find if shape 2 is right or left from shape 1
if shape1.left>shape2.Left then
begin
shape1.Left:=shape1.Left-5;
end else shape1.Left:=shape1.Left+5;
//Moving to shape2.left until shape1.left:=shape2.left
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
begin
timer2.Interval:=100; //the same method as timer1
if shape1.top=shape2.top then
begin
shape1.top:=shape1.top
end else
begin
if shape1.top>shape2.top then
begin
shape1.top:=shape1.top-5;
end else shape1.top:=shape1.top+5;
end;
end;
end.
What shape1 does now is to move toward shape 2, but it doesn't stop moving, i mean it sticks to shape 2, but it is still moving upside-down, but not left-right from shape 2. I checked timer's 2 code and there is nothing wrong.
Try the following code (assign OnCreate
and OnPaint
of the form and set the timer to 30 millisecond intervals):
unit Unit5;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TVector = record
X, Y: real;
end;
TForm5 = class(TForm)
Timer1: TTimer;
procedure FormPaint(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
FPosA, FPosB: TVector;
v: TVector;
public
{ Public declarations }
end;
var
Form5: TForm5;
implementation
uses Math;
{$R *.dfm}
const RADIUS = 16;
function RealPoint(X, Y: real): TVector;
begin
result.X := X;
result.Y := Y;
end;
function RoundPoint(P: TVector): TPoint;
begin
result.X := round(P.X);
result.Y := round(P.Y);
end;
procedure TForm5.FormCreate(Sender: TObject);
var
DX, DY: real;
begin
FPosA := RealPoint(32, 32);
FPosB := RealPoint(500, 200);
DX := FPosB.X - FPosA.X;
DY := FPosB.Y - FPosA.Y;
v.X := DX / 100;
v.Y := DY / 100;
end;
function EllipseRectFromPoint(P: TVector): TRect;
var
ScreenPoint: TPoint;
begin
ScreenPoint := RoundPoint(P);
result.Left := ScreenPoint.X - RADIUS;
result.Right := ScreenPoint.X + RADIUS;
result.Top := ScreenPoint.Y - RADIUS;
result.Bottom := ScreenPoint.Y + RADIUS;
end;
procedure TForm5.FormPaint(Sender: TObject);
begin
// Draw ball A
Canvas.Brush.Color := clSkyBlue;
Canvas.Ellipse(EllipseRectFromPoint(FPosA));
// Draw ball B
Canvas.Brush.Color := clMoneyGreen;
Canvas.Ellipse(EllipseRectFromPoint(FPosB));
end;
procedure TForm5.Timer1Timer(Sender: TObject);
begin
FPosA.X := FPosA.X + V.X;
FPosA.Y := FPosA.Y + V.Y;
Invalidate;
if Hypot(FPosA.X - FPosB.X, FPosA.Y - FPosB.Y) < 0.1 then
begin
Timer1.Enabled := false;
ShowMessage('We''re there!');
end;
end;
end.
Two balls:
unit Unit5;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TVector = record
X, Y: real;
end;
TForm5 = class(TForm)
Timer1: TTimer;
procedure FormPaint(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
AreWeThereYetA, AreWeThereYetB: boolean;
FPosA, FPosB, FPosC: TVector;
vA, vB: TVector;
public
{ Public declarations }
end;
var
Form5: TForm5;
implementation
uses Math;
{$R *.dfm}
const RADIUS = 16;
function RealPoint(X, Y: real): TVector;
begin
result.X := X;
result.Y := Y;
end;
function RoundPoint(P: TVector): TPoint;
begin
result.X := round(P.X);
result.Y := round(P.Y);
end;
procedure TForm5.FormCreate(Sender: TObject);
var
DX, DY: real;
begin
FPosA := RealPoint(32, 32);
FPosB := RealPoint(132, 32);
FPosC := RealPoint(500, 200);
DX := FPosC.X - FPosA.X;
DY := FPosC.Y - FPosA.Y;
vA.X := DX / 100;
vA.Y := DY / 100;
DX := FPosC.X - FPosB.X;
DY := FPosC.Y - FPosB.Y;
vB.X := DX / 200;
vB.Y := DY / 200;
end;
function EllipseRectFromPoint(P: TVector): TRect;
var
ScreenPoint: TPoint;
begin
ScreenPoint := RoundPoint(P);
result.Left := ScreenPoint.X - RADIUS;
result.Right := ScreenPoint.X + RADIUS;
result.Top := ScreenPoint.Y - RADIUS;
result.Bottom := ScreenPoint.Y + RADIUS;
end;
procedure TForm5.FormPaint(Sender: TObject);
begin
// Draw ball A
Canvas.Brush.Color := clSkyBlue;
Canvas.Ellipse(EllipseRectFromPoint(FPosA));
// Draw ball B
Canvas.Brush.Color := clMoneyGreen;
Canvas.Ellipse(EllipseRectFromPoint(FPosB));
// Draw ball C
Canvas.Brush.Color := clRed;
Canvas.Ellipse(EllipseRectFromPoint(FPosC));
end;
procedure TForm5.Timer1Timer(Sender: TObject);
begin
if not AreWeThereYetA then
begin
FPosA.X := FPosA.X + VA.X;
FPosA.Y := FPosA.Y + VA.Y;
end;
if not AreWeThereYetB then
begin
FPosB.X := FPosB.X + VB.X;
FPosB.Y := FPosB.Y + VB.Y;
end;
Invalidate;
if Hypot(FPosA.X - FPosC.X, FPosA.Y - FPosC.Y) < 0.1 then
AreWeThereYetA := true;
if Hypot(FPosB.X - FPosC.X, FPosB.Y - FPosC.Y) < 0.1 then
AreWeThereYetB := true;
if AreWeThereYetA and AreWeThereYetB then
begin
Timer1.Enabled := false;
ShowMessage('We are there!');
end;
end;
end.
Using arrays and records, it would be easily to generalise to N
balls with custom properties (colours, radii, etc.), even random ones. It would also be very easy to implement bouncing. In addition, a real vector type would be good here.