完成后如何让Image向后移动

时间:2013-11-24 06:27:36

标签: delphi delphi-xe2

目前我有一个TCard(TGraphicControl),我将x向上移动一小步。但是我无法弄清楚如何将它移回去。

我用

开始
           TCardMover.Slide(card,point(card.Left,card.Top -10),CARD_SLIDE_TIME,Animation);

在里面 {这将给予攻击动画}

procedure TGameData.AnimateAttack(slot: Integer;card: TCard);  //add value as integer ,
var
i : integer;
begin
i:=0;
   if slot = 1 then
        begin
           //TCardMover.Slide(card,point(card.Left,card.Top -10),CARD_SLIDE_TIME,Animation,nil);
           TCardMover.Slide(Card,point(Card.Left,Card.Top -10),CARD_SLIDE_TIME,Animation,TerminateCall);
        end;
   if slot = 2 then
        begin
          TCardMover.Slide(card,point(card.Left,card.Top -10),CARD_SLIDE_TIME,Animation,TerminateCall);  // DMc Just to test card movement
        end;
   if slot = 3  then
        begin
          TCardMover.Slide(card,point(card.Left,card.Top -10),CARD_SLIDE_TIME,Animation,TerminateCall);  // DMc Just to test card movement
        end;
end;

然后我称之为

procedure TGameData.attack;
begin
    animateAttack(1,fgame.Slot1);
end;

如果我像这样在自己的动画攻击中运行tCardMover.slide。

   TCardMover.Slide(card,point(card.Left,card.Top -10),CARD_SLIDE_TIME,Animation);
   TCardMover.Slide(card,point(card.Left,card.Top +10),CARD_SLIDE_TIME,Animation);

它尝试两者兼顾,我假设由于移动是一个单独的线程?我怎么能解决这个问题所以我可以移出-10然后在卡完成移动后移动+10?

这是TCardMover。

{ TCardMover }

function TCardMover.Arrived: boolean;
begin
  Result := (FPosNow.X = FPosDest.X) and (FPosNow.Y = FPosDest.Y);
end;

procedure TCardMover.CalculateNextStop;
var
  Elapsed : integer;
begin
  while FTickNext < GetTickCount do                 // When is next re-draw due?
    FTicknext := FTickNext + CARD_MOVE_INTERVAL;


  if FTickNext >= FTickEnd then   // Are we there yet Dad?
  begin                           // If the journey has taken long enough, move
    FTickNext := FTickEnd;        // to our destination without further delay,
    FPosNow   := FPosDest;        // then bail.
  end
  else
  begin
    // If we get here we are still en route so calculate where to re-draw.
    Elapsed := GetTickCount - FTickStart;                // How much time will journey have taken at next re-draw?
    FPosNow.X := FPosStart.X + round((Elapsed/FTickJourney)*FJourney.X);  // Where will card be at next re-draw?
    FPosNow.Y := FPosStart.Y + round((Elapsed/FTickJourney)*FJourney.Y);
  end;
end;

procedure TCardMover.Execute;
begin
  while not terminated and not Arrived do
  begin
    CalculateNextStop;
    WaitTillDue;
    Synchronize(NotifyHost);
  end;
end;

class procedure TCardMover.Slide(aCard: TCard; aDestination: TPoint; aJourneyTime: cardinal; DrawProc : TNotifyEvent);
begin
  with TCardMover.Create(START_IMMEDIATELY) do
  begin
    FTickStart      := GetTickCount;
    FTickNext       := FTickStart;
    FTickEnd        := FTickStart + aJourneyTime;
    FPosStart       := Point(aCard.Left,aCard.Top);
    FCard           := aCard;
    FPosDest        := aDestination;
    FTickJourney    := aJourneyTime;
    FreeOnTerminate := TRUE;
    FOnMove         := DrawProc;
    FJourney.X      := FPosDest.X - FPosStart.X;
    FJourney.Y      := FPosDest.Y - FPosStart.Y;
  end;
end;

procedure TCardMover.NotifyHost;
begin
  if assigned(FOnMove) then
    FOnMove(Self);
end;

procedure TCardMover.WaitTillDue;
var
  TicksNow : cardinal;
begin
  TicksNow := GetTickCount;
  if TicksNow < FTickNext then
    SleepEx(FTickNext-TicksNow,DO_NOT_QUIT_EARLY);
end;

2 个答案:

答案 0 :(得分:1)

一种方法是向类方法添加aditional Parameter并提供OnTerminate事件。因此第二个线程将在第一个终止后被调用:

class procedure TCardMover.Slide(aCard: TShape; aDestination: TPoint; 
           aJourneyTime:cardinal ; DrawProc : TNotifyEvent; CallOnTerminate: TNotifyEvent);
begin
  with TCardMover.Create(false) do
  begin
    FTickStart      := GetTickCount;
    // .....
    OnTerminate := CallOnTerminate;
  end;
end;


procedure TAForm.TerminateCall(Sender: TObject);
begin
 TCardMover.Slide(Card ,point(Card.Left,Card.Top +100),50,Animation,nil);
end;

// Call the method and provide a procedure which will be called if the thread terminates
begin
 TCardMover.Slide(Card,point(Card.Left,Card.Top -100),50,Animation,TerminateCall);
end;

另一种方法是更改​​TCardMover类以处理动画列表。

答案 1 :(得分:1)

首先,我将从一个对象开始,作为一个触发多个动画的动画

type
  IAnimation = interface
   {GUID}
   function IsFinished : Boolean;
   procedure Step;
 end;

 TAnimator = class
 private
   FAnimations : TList<IAnimation>;
   FTimer : TTimer;
   procedure TimerEvent( Sender : TObject );
 public
   constructor Create;
   destructor Destroy; override;
   procedure Add( AAnimation : IAnimation );
 end;

constructor TAnimator.Create;
begin
  inherited;
  FAnimations := TList<IAnimation>.Create;

  FTimer := TTimer.Create( nil );
  FTimer.Interval := 25; // whatever you like
  FTimer.OnTimer := TimerEvent;
  FTimer.Enabled := True;
end;

destructor Destroy;
begin
  FTimer.Free;
  FAnimations.Free;
  inherited;
end;

procedure TAnimator.Add( AAnimation : IAnimation );
begin
  FAnimations.Add( AAnimation );
end;

procedure TAnimator.TimerEvent( Sender : TObject );
var
  LIdx : Integer;
  LAnimation : IAnimation;
begin
  LIdx := 0;
  while LIdx < FAnimations.Count do
  begin
    LAnimation := FAnimations[LIdx];
    LAnimation.Step;
    if LAnimation.IsFinished then
      FAnimations.Remove( LAnimation )
    else
      Inc( LIdx );
  end;
end;

这就是你需要的所有你想要的动画......

e.g。让我们构建一个动画序列

type
  TAnimationSequence = class( TInterfacedObject, IAnimation )
  private
    FAnimations : TQueue<IAnimation>;
    function IsFinished : Boolean;
    procedure Step;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Add( AAnimation : IAnimation );
  end;

constructor TAnimationSequence.Create;
begin
  inherited;
  FAnimations := TQueue<IAnimation>.Create;
end;

destructor TAnimationSequence.Destroy;
begin
  FAnimations.Free;
  inherited;
end;

function TAnimationSequence.IsFinished : Boolean;
begin
  Result := FQueue.Count = 0;
end;

procedure Step;
var
  LAnimation : IAnimation;
begin
  LAnimation := FAnimations.Peek;
  LAnimation.Step;
  if LAnimation.IsFinished then
    LAnimation := FAnimations.Dequeue;
end;

现在你应该能够构建自己的动画并将它们组合成一个序列

var
  LSequence : TAnimationSequence;
begin
  LSequence := TAnimationSequence.Create;

  LSequence.Add( TControlMoveUpAnimation.Create( MyCard, 10 ) );
  LSequence.Add( TControlMoveDownAnimation.Create( MyCard, 10 ) );
  LSequence.Add( TControlMoveUpAnimation.Create( MyCard, 8 ) );
  LSequence.Add( TControlMoveDownAnimation.Create( MyCard, 8 ) );
  LSequence.Add( TControlMoveUpAnimation.Create( MyCard, 4 ) );
  LSequence.Add( TControlMoveDownAnimation.Create( MyCard, 4 ) );

  MyAnimator.Add( LSequence );
end;