Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Playing card flip animation

Do you know of any free components/libraries, which allow to achieve a 3D flip effect?

Demo here: snorkl.tv

like image 936
Pateman Avatar asked May 14 '12 14:05

Pateman


2 Answers

Here's an attempt using SetWorldTransform:

type
  TForm1 = class(TForm)
    PaintBox1: TPaintBox;
    Button1: TButton;
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure PaintBox1Paint(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    FFrontBmp, FBackBmp: TBitmap;
    FBmps: array [Boolean] of TBitmap;
    FXForm: TXForm;
    FStep: Integer;
  end;

var
  Form1: TForm1;

implementation

uses
  Math;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FFrontBmp := TBitmap.Create;
  FFrontBmp.LoadFromFile(ExtractFilePath(Application.ExeName) + '53.bmp');
  FBackBmp := TBitmap.Create;
  FBackBmp.LoadFromFile(ExtractFilePath(Application.ExeName) + 'b1fv.bmp');
  FBmps[True] := FFrontBmp;
  FBmps[False] := FBackBmp;

  FXForm.eM11 := 1;
  FXForm.eM12 := 0;
  FXForm.eM21 := 0;
  FXForm.eM22 := 1;
  FXForm.eDx := 0;
  FXForm.eDy := 0;

  Timer1.Enabled := False;
  Timer1.Interval := 30;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FFrontBmp.Free;
  FBackBmp.Free;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  SetGraphicsMode(PaintBox1.Canvas.Handle, GM_ADVANCED);
  SetWorldTransform(PaintBox1.Canvas.Handle, FXForm);
  PaintBox1.Canvas.Draw(0, 0, FBmps[FStep < 20]);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  Bmp: TBitmap;
  Sign: Integer;
begin
  Inc(FStep);

  Sign := math.Sign(FStep - 20);
  FXForm.eM11 := FXForm.eM11 + 0.05 * Sign;
  FXForm.eM21 := FXForm.eM21 - 0.005 * Sign;
  FXForm.eDx := FXForm.eDx - 1 * Sign;
  if FStep = 39 then begin
    Timer1.Enabled := False;
    PaintBox1.Refresh;
  end else
    PaintBox1.Invalidate;

  if not Timer1.Enabled then begin
    Bmp := FBmps[True];
    FBmps[True] := FBmps[False];
    FBmps[False] := Bmp;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Timer1.Enabled := True;
  FStep := 0;
end;


I'm not sure if this stood a chance of turning out to be anything beautiful in case I had some maths capability, but here's currently how it looks:

enter image description here

The images used:  enter image description here  enter image description here

like image 197
Sertac Akyuz Avatar answered Oct 03 '22 00:10

Sertac Akyuz


Something like this might do the similar effect (just another attempt to show how this could be done, also not so precise, but it's just for fun since you've asked for a library or component). The principle is based on a rectnagle that is being resized and centered in the paint box where the card is being rendered with the StretchDraw function:

Unit1.pas

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, PNGImage;

type
  TCardSide = (csBack, csFront);
  TForm1 = class(TForm)
    Timer1: TTimer;
    Timer2: TTimer;
    PaintBox1: TPaintBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
    procedure PaintBox1Click(Sender: TObject);
    procedure PaintBox1Paint(Sender: TObject);
  private
    FCardRect: TRect;
    FCardSide: TCardSide;
    FCardBack: TPNGImage;
    FCardFront: TPNGImage;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FCardSide := csBack;
  FCardRect := PaintBox1.ClientRect;
  FCardBack := TPNGImage.Create;
  FCardBack.LoadFromFile('tps2N.png');
  FCardFront := TPNGImage.Create;
  FCardFront.LoadFromFile('Ey3cv.png');
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FCardBack.Free;
  FCardFront.Free;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if FCardRect.Right - FCardRect.Left > 0 then
  begin
    FCardRect.Left := FCardRect.Left + 3;
    FCardRect.Right := FCardRect.Right - 3;
    PaintBox1.Invalidate;
  end
  else
  begin
    Timer1.Enabled := False;
    case FCardSide of
      csBack: FCardSide := csFront;
      csFront: FCardSide := csBack;
    end;
    Timer2.Enabled := True;
  end;
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
  if FCardRect.Right - FCardRect.Left < PaintBox1.ClientWidth then
  begin
    FCardRect.Left := FCardRect.Left - 3;
    FCardRect.Right := FCardRect.Right + 3;
    PaintBox1.Invalidate;
  end
  else
    Timer2.Enabled := False;
end;

procedure TForm1.PaintBox1Click(Sender: TObject);
begin
  Timer1.Enabled := False;
  Timer2.Enabled := False;
  FCardRect := PaintBox1.ClientRect;
  Timer1.Enabled := True;
  PaintBox1.Invalidate;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  case FCardSide of
    csBack: PaintBox1.Canvas.StretchDraw(FCardRect, FCardBack);
    csFront: PaintBox1.Canvas.StretchDraw(FCardRect, FCardFront);
  end;
end;

end.

Unit1.dfm

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 203
  ClientWidth = 173
  Color = clBtnFace
  DoubleBuffered = True
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object PaintBox1: TPaintBox
    Left = 48
    Top = 40
    Width = 77
    Height = 121
    OnClick = PaintBox1Click
    OnPaint = PaintBox1Paint
  end
  object Timer1: TTimer
    Enabled = False
    Interval = 10
    OnTimer = Timer1Timer
    Left = 32
    Top = 88
  end
  object Timer2: TTimer
    Enabled = False
    Interval = 10
    OnTimer = Timer2Timer
    Left = 88
    Top = 88
  end
end

Cards

enter image description hereenter image description here

like image 35
TLama Avatar answered Oct 03 '22 02:10

TLama