Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Smooth movement on screen

Status
Not open for further replies.

bobbie100

Programmer
Aug 29, 2003
64
GB
I'm currently teaching myself Delphi and am implementing a card game (BrainJam) as my learning project. I have got the thing working well except for the smooth sliding of cards between piles and at the end of the game where I bounce cards around the form. The individual cards are implemented as components extended from TGraphicControl. Having experimented and read these and other forums (or is it fora?) I chose to transfer the card image to a window based on a TCustomControl while sliding from one position to the next as it seemed that sliding a window object around is likely to require less redrawing and therefore less flicker. Despite all my efforts the sliding process is still not very smooth. At the moment I run a continuous loop for updating the window position during the slide. I have considered using a timer to provide updates at regular intervals (say 20-40 ms), but simple experiments I did with a timer to generate a Beep, had a lot of interruptions even at 100 ms intervals. Do I need to use some special synchronisation with screen updates, or some other Windows API trickery to block interruptions from other processes? Please help me I want to get the same smooth card movement I see on other card games. (Biggest problem is I'm a bit of a perfectionist!).
Sorry this post is so long.
 
bobbie,

I've not done a lot of graphics programming using the VCL and TCustomControls etc....I generally subclass a TPanel so that it 'contains' cards.

e.g.

TMyCardGame = class(TPanel)
private
FCards: TMyCardList;
FBackImage: TBitmap;
public
procedure Paint;
...
end;

I must admit that I haven't had to worry about card games, and therefore the user interaction with the individual cards (especially overlapping cards etc).

One thing I could suggest, is that you post your routine for moving the cards around, so we can have a look at that. I've just created a test form with a number of buttons that I move around via a simple loop. I get no really bad flicker, but a button is a little different to an image :). Have you tried the judicious use of Application.ProcessMessages???? :) (or the removal of it)

Cheers,

Bill
 
ok....I've since managed to get another version working with images, and I can see what you're talking about!!!!

I'm assuming its happening because the form is trying to repaint itself as the controls/windows are moved around....everytime a control or window changes position I would imagine....not very nice from your point of view....

perhaps you would be better off doing all of the drawing yourself?
 
Thanks :) BillDoorNZ for looking at my problem. My TCard class was deliberately not sub-classed from TImage to get more control over when Updates and Repaints occur - TImage seems to do a lot of this automatically. That way I can avoid a lot of unnecessary updates.
Your suggestion of doing all the drawing myself sounds rather daunting! Bear in mind I'm only new to this (6 weeks now).
Below are the relevant parts of the declarations of my card and card image window classes, together with the methods for sliding a card from A to B. I used the Windows API MoveWindow routine rather than setting Left and Top because when stepping through in the debugger the image window moved separately at the setting of Left and Top.
Any more comments (and solutions) would be greatly appreciated!!!
Bob

TCard = class(TGraphicControl)
private
FImage: TBitmap;
...
end;

TCardImageWin = class(TCustomControl)
private
FImage: TBitmap;
...
end;

procedure TCard.Slide(SlideSpeed: Integer; //Speed of the slide in pixels/sec
XEnd: Integer; //Horizontal position at the end of the slide
YEnd: Integer); //Vertical position at the end of the slide
var
_CardImageWin: TCardImageWin;
_XMax, _YMax: Integer;
_XMin, _YMin: Integer;
_XNext, _YNext: Integer;
_XSlide, _YSlide: Integer;
_XStart, _YStart: Integer;
_SlideDistance: Real;
_SlideDuration: Integer;
_TimeEnd: DWORD;
_TimeNow: DWORD;
_TimeStart: DWORD;
_TimeFromStart: Integer;
begin
{ Card image window created at a position outside the form }
_CardImageWin := TCardImageWin.Create(Owner);
try
{ Start of slide is from current X-Y card position }
_XStart := Left;
_YStart := Top;
{ Min-max X-Y bounds of card image during slide }
_XMin := Min(_XStart, XEnd);
_XMax := Max(_XStart, XEnd);
_YMin := Min(_YStart, YEnd);
_YMax := Max(_YStart, YEnd);
{ Change in X-Y position during slide }
_XSlide := XEnd - _XStart;
_YSlide := YEnd - _YStart;
{ Duration of the slide in ms }
_SlideDistance := Sqrt(Sqr(_XSlide) + Sqr(_YSlide));
_SlideDuration := Trunc((1000 * _SlideDistance) / SlideSpeed) + 1;
{ Set the image in the window to be the current card's image and move in front of the
card before hiding }
_CardImageWin.Image := Image;
_CardImageWin.BringToFront;
_CardImageWin.Move(_XStart, _YStart);
_CardImageWin.Show;
_CardImageWin.Update;
Hide;
{ Move card to end of the slide (ready to be made visible) }
Left := XEnd;
Top := YEnd;
{ Slide start and finish times in ms }
_TimeNow := GetTickCount;
_TimeStart := _TimeNow;
_TimeEnd := _TimeStart + DWORD(_SlideDuration);
{ Keep moving card image window until reach end of slide }
while (_TimeNow < _TimeEnd) do
begin
_TimeFromStart := _TimeNow - _TimeStart;
_XNext := ((_XSlide * _TimeFromStart) div _SlideDuration) + _XStart;
_YNext := ((_YSlide * _TimeFromStart) div _SlideDuration) + _YStart;
_XNext := EnsureRange(_XNext, _XMin, _XMax);
_YNext := EnsureRange(_YNext, _YMin, _YMax);
_CardImageWin.Move(_XNext, _YNext);
_TimeNow := GetTickCount;
end;
{ Finally set to end of slide position }
_CardImageWin.Move(XEnd, YEnd);
{ Make card visible before image window is destroyed }
Show;
finally
{ Delete image window }
_CardImageWin.Image := nil; //Unlink window image from Tcard image before freeing
_CardImageWin.Free;
end;
end;

procedure TCardImageWin.Move(ALeft: Integer;
ATop: Integer);
begin
MoveWindow(Self.Handle, ALeft, ATop, Width, Height, True);
Parent.Update; //Update invalidated parts of form
end;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top