-3

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.

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
user2296565
  • 243
  • 1
  • 7
  • 18
  • It seems like you ask us to do every little step in your program. Maybe you can solve the problem yourself tomorrow if you sleep well tonight? – Andreas Rejbrand Apr 21 '13 at 17:32
  • 3
    Anyhow: (1) use only a single timer. (2) `shape1.Left:=shape1.left` is trivially a no-op. (3) set the interval of the timer at design-time, or *once*. Not 10 times a second! (4) `shape1.top:=shape1.top` is also a no-op. (5) Animation with Delphi isn't hard at all, if you only think through the logic before you implement it. – Andreas Rejbrand Apr 21 '13 at 17:33
  • the problem is i can't :P. Check timer's 2 program, it is the same as timer's 1, IF SHAPE1.TOP:=SHAPE2.TOP THEN SHAPE1.TOP:=SHAPE1.TOP ...It's like saying: Hey Shape1, if you move on shape2, stop moving, but it doesn't – user2296565 Apr 21 '13 at 17:36
  • No, it is certainly not. I'm sorry, but you really have to learn the very basics of imperative programming. – Andreas Rejbrand Apr 21 '13 at 17:37
  • I know, but i am learning visual basic, c++ and delphi at the same time, believe me it's not easy for me, i've been studing delphi for 2 months, this is why i am asking you – user2296565 Apr 21 '13 at 17:39
  • 1
    Since `SHAPE1.TOP` is the same number as `SHAPE1.TOP` (no kidding!), the line `SHAPE1.TOP:=SHAPE1.TOP` does exactly nothing. Ever. Consequently, `IF SHAPE1.TOP=SHAPE2.TOP THEN SHAPE1.TOP:=SHAPE1.TOP` does nothing if the tops are unequal, and if they are equal, it still does nothing. Hence, the code does nothing in any case! – Andreas Rejbrand Apr 21 '13 at 17:43
  • I will, but you ban my account from asking questions, and i really have to do this project (it's actually a game), else i won't get high mark and my teacher is not helping me at all – user2296565 Apr 21 '13 at 17:43
  • Of course, it does nothing, which means it is not moving either. So if shape1 moves on shape2 then do nothing =(stop moving), what's the wrong? but that's not the problem, something else is – user2296565 Apr 21 '13 at 17:46
  • 1
    If you want to stop the animation, you can ... well disable the timer? – Andreas Rejbrand Apr 21 '13 at 17:47
  • Omg, Of course, it was that easy, but i was so tired programming those things that i didn't even think about it. However, it is important that the timers must be enabled, because they also do other things, so do you suggest me to disable the timers and enable new ones? – user2296565 Apr 21 '13 at 17:52
  • Oh my God. My predictions were right. About a week ago, I felt this question coming. – Jerry Dodge Apr 21 '13 at 20:25
  • Well, if you are not willing to help me, then don't, somebody else will, what's your problem anyway – user2296565 Apr 22 '13 at 12:33

1 Answers1

0

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.

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384