123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- unit UnitMain;
- interface
- uses
- Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
- Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
- GR32,
- GR32_Image,
- GR32_Layers,
- amEasing;
- type
- TEaseOptions = set of (eoHorizontal, eoVertical);
- TEaseThread = class(TThread)
- private
- FEaseHorizontal: TEaseFunc;
- FEaseVertical: TEaseFunc;
- FCycleTime: integer;
- FUpdateDelegate: TThreadMethod;
- FHorizontalValue: Double;
- FVerticalValue: Double;
- FOptions: TEaseOptions;
- protected
- procedure Execute; override;
- public
- constructor Create(AEaseHorizontal, AEaseVertical: TEaseFunc; ACycleTime: integer; AUpdateDelegate: TThreadMethod);
- property Options: TEaseOptions read FOptions write FOptions;
- property HorizontalValue: Double read FHorizontalValue;
- property VerticalValue: Double read FVerticalValue;
- end;
- type
- TFormMain = class(TForm)
- Image32: TImage32;
- PanelOptions: TPanel;
- CheckBoxAnimateHorizontal: TCheckBox;
- CheckBoxAnimateVertical: TCheckBox;
- ButtonBounce: TButton;
- procedure CheckBoxAnimateHorizontalClick(Sender: TObject);
- procedure CheckBoxAnimateVerticalClick(Sender: TObject);
- procedure FormResize(Sender: TObject);
- procedure ButtonBounceClick(Sender: TObject);
- private
- FPlanetLayer: TBitmapLayer;
- FAlienLayer: TBitmapLayer;
- FEaseThread: TEaseThread;
- private
- procedure UpdatePosition;
- public
- constructor Create(AOwner: TCOmponent); override;
- destructor Destroy; override;
- end;
- var
- FormMain: TFormMain;
- implementation
- {$R *.dfm}
- uses
- GR32.Examples,
- GR32_Resamplers,
- GR32_Math;
- constructor TFormMain.Create(AOwner: TCOmponent);
- begin
- inherited;
- FPlanetLayer := TBitmapLayer(Image32.Layers.Add(TBitmapLayer));
- FPlanetLayer.Bitmap.LoadFromFile(Graphics32Examples.MediaFolder + '\sprite4.bmp');
- FPlanetLayer.Bitmap.DrawMode := dmBlend;
- FPlanetLayer.Bitmap.CombineMode := cmMerge;
- FPlanetLayer.Bitmap.ResamplerClassName := TLinearResampler.ClassName;
- FAlienLayer := TBitmapLayer(Image32.Layers.Add(TBitmapLayer));
- FAlienLayer.Bitmap.LoadFromFile(Graphics32Examples.MediaFolder + '\sprite1.bmp');
- FAlienLayer.Bitmap.DrawMode := dmBlend;
- FAlienLayer.Bitmap.CombineMode := cmMerge;
- FAlienLayer.Bitmap.ResamplerClassName := TLinearResampler.ClassName;
- FEaseThread := TEaseThread.Create(TEaseCircular.EaseInOut, TEaseExponential.EaseInOut, 5000, UpdatePosition);
- FEaseThread.Start;
- end;
- destructor TFormMain.Destroy;
- begin
- FEaseThread.Terminate;
- FEaseThread.WaitFor;
- FEaseThread.Free;
- inherited;
- end;
- procedure TFormMain.FormResize(Sender: TObject);
- var
- r: TFloatRect;
- begin
- r.Left := (Image32.ClientWidth - FAlienLayer.Bitmap.Width) / 2;
- r.Right := r.Left + FAlienLayer.Bitmap.Width;
- r.Top := Image32.ClientHeight - FAlienLayer.Bitmap.Height;
- r.Bottom := r.Top + FAlienLayer.Bitmap.Height;
- FAlienLayer.Location := r;
- end;
- procedure TFormMain.ButtonBounceClick(Sender: TObject);
- begin
- // First animate the alien being shot into "space"...
- AnimatedTween(TEaseQuartic.EaseOut, 1500,
- procedure(Value: Double; var Continue: boolean)
- var
- r: TFloatRect;
- begin
- r := FAlienLayer.Location;
- r.Top := (Image32.ClientHeight - FAlienLayer.Bitmap.Height) * (1-Value);
- r.Bottom := r.Top + FAlienLayer.Bitmap.Height;
- FAlienLayer.Location := r;
- Image32.Update;
- CheckSynchronize; // Also give thread synchronize some love
- end, 50);
- // ...and then let it fall back and bounce
- AnimatedTween(TEaseBounce.EaseOut, 2000,
- procedure(Value: Double; var Continue: boolean)
- var
- r: TFloatRect;
- begin
- r := FAlienLayer.Location;
- r.Top := (Image32.ClientHeight - FAlienLayer.Bitmap.Height) * Value;
- r.Bottom := r.Top + FAlienLayer.Bitmap.Height;
- FAlienLayer.Location := r;
- Image32.Update;
- CheckSynchronize;
- end, 50);
- end;
- procedure TFormMain.CheckBoxAnimateHorizontalClick(Sender: TObject);
- begin
- if (TCheckBox(Sender).Checked) then
- FEaseThread.Options := FEaseThread.Options + [eoHorizontal]
- else
- FEaseThread.Options := FEaseThread.Options - [eoHorizontal];
- end;
- procedure TFormMain.CheckBoxAnimateVerticalClick(Sender: TObject);
- begin
- if (TCheckBox(Sender).Checked) then
- FEaseThread.Options := FEaseThread.Options + [eoVertical]
- else
- FEaseThread.Options := FEaseThread.Options - [eoVertical];
- end;
- procedure TFormMain.UpdatePosition;
- var
- r: TFloatRect;
- begin
- // Called from thread to update the position of the planet layer
- // Center
- r.Left := (Image32.ClientWidth - FPlanetLayer.Bitmap.Width) / 2;
- r.Top := (Image32.ClientHeight - FPlanetLayer.Bitmap.Height) / 2;
- // Offset from center
- if (eoHorizontal in FEaseThread.Options) then
- r.Left := r.Left + (Image32.ClientWidth - FPlanetLayer.Bitmap.Width) * (FEaseThread.HorizontalValue - 0.5);
- if (eoVertical in FEaseThread.Options) then
- r.Top := r.Top + (Image32.ClientHeight - FPlanetLayer.Bitmap.Height) * (FEaseThread.VerticalValue - 0.5);
- r.Right := r.Left + FPlanetLayer.Bitmap.Width;
- r.Bottom := r.Top + FPlanetLayer.Bitmap.Height;
- FPlanetLayer.Location := r;
- end;
- { TEaseThread }
- constructor TEaseThread.Create(AEaseHorizontal, AEaseVertical: TEaseFunc; ACycleTime: integer; AUpdateDelegate: TThreadMethod);
- begin
- inherited Create(True);
- FEaseHorizontal := AEaseHorizontal;
- FEaseVertical := AEaseVertical;
- FCycleTime := ACycleTime;
- FUpdateDelegate := AUpdateDelegate;
- end;
- procedure TEaseThread.Execute;
- const
- VerticalScale = 3;
- begin
- while (not Terminated) do
- begin
- // Use a linear ease to produce a linear value from [0..1]. Then use that value
- // to produce a vertical and a horizontal value using the specified easing
- // functions.
- AnimatedTween(TEaseLinear.Ease, FCycleTime,
- procedure(Value: Double; var Continue: boolean)
- var
- HorValue, VerValue: Double;
- begin
- // Map from [0..1] to [0..1..0]
- HorValue := Abs((Value - 0.5) * 2);
- VerValue := Abs((FMod(Value * VerticalScale, 1.0) - 0.5) * 2);
- if (eoHorizontal in FOptions) then
- FHorizontalValue := FEaseHorizontal(HorValue);
- if (eoVertical in FOptions) then
- FVerticalValue := FEaseVertical(VerValue);
- Continue := not Terminated;
- // Update the planet layer position
- if (not Terminated) then
- Queue(FUpdateDelegate);
- end, 50);
- end;
- end;
- end.
|