UnitMain.pas 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. unit UnitMain;
  2. interface
  3. uses
  4. Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  5. Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
  6. GR32,
  7. GR32_Image,
  8. GR32_Layers,
  9. amEasing;
  10. type
  11. TEaseOptions = set of (eoHorizontal, eoVertical);
  12. TEaseThread = class(TThread)
  13. private
  14. FEaseHorizontal: TEaseFunc;
  15. FEaseVertical: TEaseFunc;
  16. FCycleTime: integer;
  17. FUpdateDelegate: TThreadMethod;
  18. FHorizontalValue: Double;
  19. FVerticalValue: Double;
  20. FOptions: TEaseOptions;
  21. protected
  22. procedure Execute; override;
  23. public
  24. constructor Create(AEaseHorizontal, AEaseVertical: TEaseFunc; ACycleTime: integer; AUpdateDelegate: TThreadMethod);
  25. property Options: TEaseOptions read FOptions write FOptions;
  26. property HorizontalValue: Double read FHorizontalValue;
  27. property VerticalValue: Double read FVerticalValue;
  28. end;
  29. type
  30. TFormMain = class(TForm)
  31. Image32: TImage32;
  32. PanelOptions: TPanel;
  33. CheckBoxAnimateHorizontal: TCheckBox;
  34. CheckBoxAnimateVertical: TCheckBox;
  35. ButtonBounce: TButton;
  36. procedure CheckBoxAnimateHorizontalClick(Sender: TObject);
  37. procedure CheckBoxAnimateVerticalClick(Sender: TObject);
  38. procedure FormResize(Sender: TObject);
  39. procedure ButtonBounceClick(Sender: TObject);
  40. private
  41. FPlanetLayer: TBitmapLayer;
  42. FAlienLayer: TBitmapLayer;
  43. FEaseThread: TEaseThread;
  44. private
  45. procedure UpdatePosition;
  46. public
  47. constructor Create(AOwner: TCOmponent); override;
  48. destructor Destroy; override;
  49. end;
  50. var
  51. FormMain: TFormMain;
  52. implementation
  53. {$R *.dfm}
  54. uses
  55. GR32.Examples,
  56. GR32_Resamplers,
  57. GR32_Math;
  58. constructor TFormMain.Create(AOwner: TCOmponent);
  59. begin
  60. inherited;
  61. FPlanetLayer := TBitmapLayer(Image32.Layers.Add(TBitmapLayer));
  62. FPlanetLayer.Bitmap.LoadFromFile(Graphics32Examples.MediaFolder + '\sprite4.bmp');
  63. FPlanetLayer.Bitmap.DrawMode := dmBlend;
  64. FPlanetLayer.Bitmap.CombineMode := cmMerge;
  65. FPlanetLayer.Bitmap.ResamplerClassName := TLinearResampler.ClassName;
  66. FAlienLayer := TBitmapLayer(Image32.Layers.Add(TBitmapLayer));
  67. FAlienLayer.Bitmap.LoadFromFile(Graphics32Examples.MediaFolder + '\sprite1.bmp');
  68. FAlienLayer.Bitmap.DrawMode := dmBlend;
  69. FAlienLayer.Bitmap.CombineMode := cmMerge;
  70. FAlienLayer.Bitmap.ResamplerClassName := TLinearResampler.ClassName;
  71. FEaseThread := TEaseThread.Create(TEaseCircular.EaseInOut, TEaseExponential.EaseInOut, 5000, UpdatePosition);
  72. FEaseThread.Start;
  73. end;
  74. destructor TFormMain.Destroy;
  75. begin
  76. FEaseThread.Terminate;
  77. FEaseThread.WaitFor;
  78. FEaseThread.Free;
  79. inherited;
  80. end;
  81. procedure TFormMain.FormResize(Sender: TObject);
  82. var
  83. r: TFloatRect;
  84. begin
  85. r.Left := (Image32.ClientWidth - FAlienLayer.Bitmap.Width) / 2;
  86. r.Right := r.Left + FAlienLayer.Bitmap.Width;
  87. r.Top := Image32.ClientHeight - FAlienLayer.Bitmap.Height;
  88. r.Bottom := r.Top + FAlienLayer.Bitmap.Height;
  89. FAlienLayer.Location := r;
  90. end;
  91. procedure TFormMain.ButtonBounceClick(Sender: TObject);
  92. begin
  93. // First animate the alien being shot into "space"...
  94. AnimatedTween(TEaseQuartic.EaseOut, 1500,
  95. procedure(Value: Double; var Continue: boolean)
  96. var
  97. r: TFloatRect;
  98. begin
  99. r := FAlienLayer.Location;
  100. r.Top := (Image32.ClientHeight - FAlienLayer.Bitmap.Height) * (1-Value);
  101. r.Bottom := r.Top + FAlienLayer.Bitmap.Height;
  102. FAlienLayer.Location := r;
  103. Image32.Update;
  104. CheckSynchronize; // Also give thread synchronize some love
  105. end, 50);
  106. // ...and then let it fall back and bounce
  107. AnimatedTween(TEaseBounce.EaseOut, 2000,
  108. procedure(Value: Double; var Continue: boolean)
  109. var
  110. r: TFloatRect;
  111. begin
  112. r := FAlienLayer.Location;
  113. r.Top := (Image32.ClientHeight - FAlienLayer.Bitmap.Height) * Value;
  114. r.Bottom := r.Top + FAlienLayer.Bitmap.Height;
  115. FAlienLayer.Location := r;
  116. Image32.Update;
  117. CheckSynchronize;
  118. end, 50);
  119. end;
  120. procedure TFormMain.CheckBoxAnimateHorizontalClick(Sender: TObject);
  121. begin
  122. if (TCheckBox(Sender).Checked) then
  123. FEaseThread.Options := FEaseThread.Options + [eoHorizontal]
  124. else
  125. FEaseThread.Options := FEaseThread.Options - [eoHorizontal];
  126. end;
  127. procedure TFormMain.CheckBoxAnimateVerticalClick(Sender: TObject);
  128. begin
  129. if (TCheckBox(Sender).Checked) then
  130. FEaseThread.Options := FEaseThread.Options + [eoVertical]
  131. else
  132. FEaseThread.Options := FEaseThread.Options - [eoVertical];
  133. end;
  134. procedure TFormMain.UpdatePosition;
  135. var
  136. r: TFloatRect;
  137. begin
  138. // Called from thread to update the position of the planet layer
  139. // Center
  140. r.Left := (Image32.ClientWidth - FPlanetLayer.Bitmap.Width) / 2;
  141. r.Top := (Image32.ClientHeight - FPlanetLayer.Bitmap.Height) / 2;
  142. // Offset from center
  143. if (eoHorizontal in FEaseThread.Options) then
  144. r.Left := r.Left + (Image32.ClientWidth - FPlanetLayer.Bitmap.Width) * (FEaseThread.HorizontalValue - 0.5);
  145. if (eoVertical in FEaseThread.Options) then
  146. r.Top := r.Top + (Image32.ClientHeight - FPlanetLayer.Bitmap.Height) * (FEaseThread.VerticalValue - 0.5);
  147. r.Right := r.Left + FPlanetLayer.Bitmap.Width;
  148. r.Bottom := r.Top + FPlanetLayer.Bitmap.Height;
  149. FPlanetLayer.Location := r;
  150. end;
  151. { TEaseThread }
  152. constructor TEaseThread.Create(AEaseHorizontal, AEaseVertical: TEaseFunc; ACycleTime: integer; AUpdateDelegate: TThreadMethod);
  153. begin
  154. inherited Create(True);
  155. FEaseHorizontal := AEaseHorizontal;
  156. FEaseVertical := AEaseVertical;
  157. FCycleTime := ACycleTime;
  158. FUpdateDelegate := AUpdateDelegate;
  159. end;
  160. procedure TEaseThread.Execute;
  161. const
  162. VerticalScale = 3;
  163. begin
  164. while (not Terminated) do
  165. begin
  166. // Use a linear ease to produce a linear value from [0..1]. Then use that value
  167. // to produce a vertical and a horizontal value using the specified easing
  168. // functions.
  169. AnimatedTween(TEaseLinear.Ease, FCycleTime,
  170. procedure(Value: Double; var Continue: boolean)
  171. var
  172. HorValue, VerValue: Double;
  173. begin
  174. // Map from [0..1] to [0..1..0]
  175. HorValue := Abs((Value - 0.5) * 2);
  176. VerValue := Abs((FMod(Value * VerticalScale, 1.0) - 0.5) * 2);
  177. if (eoHorizontal in FOptions) then
  178. FHorizontalValue := FEaseHorizontal(HorValue);
  179. if (eoVertical in FOptions) then
  180. FVerticalValue := FEaseVertical(VerValue);
  181. Continue := not Terminated;
  182. // Update the planet layer position
  183. if (not Terminated) then
  184. Queue(FUpdateDelegate);
  185. end, 50);
  186. end;
  187. end;
  188. end.