Delphi 完成后如何使图像向下移动
目前我有一个TCard(TGraphic控件),我可以用一小步向上移动x。但是我不知道怎么把它移回去 我从Delphi 完成后如何使图像向下移动,delphi,delphi-xe2,Delphi,Delphi Xe2,目前我有一个TCard(TGraphic控件),我可以用一小步向上移动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 ,
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;
如果我像这样在animateattack中的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-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;
{TCardMover}
函数TCardMover.arrized:boolean;
开始
结果:=(FPosNow.X=FPosDest.X)和(FPosNow.Y=FPosDest.Y);
终止
程序TCardMover.CalculateNextStop;
变量
时间:整数;
开始
当FTickNext=FTickEnd那么//我们到了吗,爸爸?
开始//如果旅程花费的时间足够长,请离开
FTickNext:=FTickEnd;//毫不拖延地赶到我们的目的地,
FPosNow:=FPosDest;//然后保释。
终止
其他的
开始
//如果我们到了这里,我们仍然在途中,所以请计算重新绘制的位置。
已用时间:=GetTickCount-FTickStart;//下一次重画时,旅程需要多少时间?
FPosNow.X:=FPosStart.X+round((经过的/FTickJourney)*FJourney.X);//下次重新抽牌时牌在哪里?
FPosNow.Y:=FPosStart.Y+round((经过的/FTickJourney)*FJourney.Y);
终止
终止
过程TCardMover.Execute;
开始
未终止且未到达时,请执行以下操作:
开始
计算下止点;
韦蒂尔杜;
同步(通知主机);
终止
终止
类过程TCardMover.Slide(aCard:TCard;aDestination:TPoint;aJourneyTime:cardinal;DrawProc:TNotifyEvent);
开始
使用TCardMover.Create(立即启动)do
开始
FTickStart:=GetTickCount;
FTickNext:=FTickStart;
FTickEnd:=FTickStart+aJourneyTime;
FPosStart:=点(aCard.Left,aCard.Top);
FCard:=aCard;
FPosDest:=指定值;
ftickTravely:=每小时一次;
FreeOnTerminate:=真;
FOnMove:=DrawProc;
FJourney.X:=FPosDest.X-FPosStart.X;
FJourney.Y:=FPosDest.Y-FPosStart.Y;
终止
终止
程序TCardMover.NotifyHost;
开始
如果已分配(FOnMove),则
丰莫夫(自我);
终止
程序TCardMover.waitilldue;
变量
蒂克斯诺:红衣主教;
开始
TicksNow:=GetTickCount;
如果单击“下一步”,则
SleepEx(FTickNext TicksNow,不要过早退出);
终止
一种方法是向类方法中添加一个常规参数,并提供一个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类以处理动画列表。首先,我将从一个对象开始,作为一个动画制作者,它可以触发多个动画
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;
您的线程只有一个等待部分和一个同步移动部分。你可以在你的表格上用一个简单的TTimer来处理这个问题。我试过了,但有几个问题。。首先,我更新了我如何攻击。。我称攻击为提供一个插槽和TCard。然后我使用这些值运行AnimateAttack。因此,不确定如何设置TerminateCall过程。主要原因是我不确定如何将数据“插槽”和“卡”发送回此过程而不出错。由于您使用的是TNotifyEvents,因此您可以在事件中访问TCardMover(发送方)。您可以在类过程幻灯片中向线程提供所需的任何信息。这与您在DrawProc中访问PosNow相同。奇怪,在terminatecall中,我在卡和卡上遇到错误。左/右的一个不同之处是我有TGamedata。terminatecall中,与PosNow和DrawProc一样,我使用TCardmover.PosNow。发射型计算机断层扫描仪。。我将尝试将其添加到TCardMover
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;