尝试以下代码(分配OnCreate
和OnPaint
形式并将计时器设置为 30 毫秒间隔):
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.
两个球:
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.
使用数组和记录,很容易推广到N
具有自定义属性(颜色、半径等)的球,甚至是随机属性。实现弹跳也很容易。此外,在这里使用真正的矢量类型会很好。