2013-11-24 1 views
-1

현재 x를 작은 단계로 위로 움직이는 TCard (TGraphicControl)가 있습니다. 그러나 나는 그것을 뒤로 움직이는 방법을 이해할 수 없다.완료되면 이미지를 다시 가져 오는 방법

내가이 내부

  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; 

을 {이 공격 amimation을 줄 것이다} 내가 tCardMover을 실행하면 다음 내가

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

과 같이 호출 animateattack에서 이와 같이 바로 뒤에서 .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

스레드는 대기 부분과 sychronized 이동 부분이있다. 당신은 양식에 간단한 TTimer로 이것을 처리 할 수 ​​있습니다. –

답변

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; 

그게 당신이 원하는 모든 종류의 애니메이션을하는 데 필요한 모든 ...

예를 들어, 의 지금 당신이 당신의 자신의 애니메이션을 구축하고 시퀀스에 또한 그들을 결합 할 수 있어야 애니메이션 시퀀스

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; 
1

한 가지 방법은 클래스 메서드에 additional 매개 변수를 추가하고 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 클래스를 변경할 수 있습니다.

+0

알았습니다.하지만 몇 가지 문제를 시도했습니다. 우선 공격 방법을 업데이트했습니다. 나는 슬롯과 TCard를 제공하는 공격을합니다. 그런 다음 해당 값을 사용하여 AnimateAttack을 실행합니다. 따라서 TerminateCall 프로 시저를 설정하는 방법을 모릅니다. –

+0

은 대부분 데이터를 "슬롯"및 "카드"를 오류없이이 절차로 되돌려 보내는 방법을 잘 모릅니다. –

+0

TNotifyEvents를 사용하고 있으므로 이벤트 내에서 TCardMover (Sender)에 액세스 할 수 있습니다. 스레드 프로 시저 슬라이드와 함께 필요한 모든 정보를 스레드에 제공 할 수 있습니다. 그것은 당신이 DrawProc의 PosNow에 접근하는 것과 같습니다. – bummi