目前我有一个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;
答案 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;