GBE.Joystick.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. unit GBE.Joystick;
  2. interface
  3. uses
  4. System.SysUtils,
  5. System.Classes,
  6. FMX.Types,
  7. FMX.Controls,
  8. FMX.Layouts,
  9. GBE.PlayerPosition,
  10. System.Math.Vectors,
  11. System.Types,
  12. FMX.Viewport3D,
  13. System.UITypes,
  14. FMX.Dialogs,
  15. FMX.Objects,
  16. FMX.Graphics,
  17. FMX.Ani,
  18. uGBEUtils3D;
  19. type
  20. TGBEJoystickType = (jtOrientation, jtDeplacement, jtOrientationDeplacement);
  21. TGBEJoystick = class(TLayout)
  22. private
  23. fPlayerPosition: TGBEPlayerPosition;
  24. FPosDepartCurseur: TPointF;
  25. // Position of the mouse mark at the start of the mouse movement
  26. fViewport3D: TViewport3D;
  27. fCircle, fCircle2: TCircle;
  28. fSensitivity: Integer;
  29. fShowIntegrateJoystick, useJoystick, fMouseCapture: Boolean;
  30. fPoint: TPoint3D;
  31. fJoystickType: TGBEJoystickType;
  32. Offset: TPointF; // Offset between click location and joystick circle center
  33. fAcceleration: Single;
  34. procedure SetAngleDeVue(const Value: TPointF); // Changing the viewing angle
  35. function GetDirection: TPoint3D;
  36. procedure SetShowIntegrateJoystick(const Value: Boolean);
  37. procedure SetJoystickType(const Value: TGBEJoystickType);
  38. function GetDirectionSidewayRight: TPoint3D;
  39. function GetDirectionSidewayLeft: TPoint3D;
  40. function GetMouseCapture: Boolean;
  41. procedure SetMouseCapture(const Value: Boolean);
  42. protected
  43. public
  44. constructor Create(AOwner: TComponent); override;
  45. destructor Destroy; override;
  46. procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  47. X, Y: Single); override;
  48. procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  49. X, Y: Single); override;
  50. procedure MouseMove(Shift: TShiftState; X, Y: Single); override;
  51. procedure DoMouseLeave; override;
  52. procedure Resize; override;
  53. procedure Paint; override;
  54. procedure InitialiserJoystick;
  55. function OrientationKeyManagement(rightKey, leftKey, upKey, downKey, goUp,
  56. goDown, sideWayRight, sideWayLeft: Boolean;
  57. sensibility, speed, maxspeed: Single): Single;
  58. published
  59. property PlayerPosition: TGBEPlayerPosition read fPlayerPosition
  60. write fPlayerPosition;
  61. property JoystickType: TGBEJoystickType read fJoystickType
  62. write SetJoystickType;
  63. property AngleDeVue: TPointF write SetAngleDeVue; // Viewing angle property
  64. property Direction: TPoint3D read GetDirection;
  65. property DirectionSidewayRight: TPoint3D read GetDirectionSidewayRight;
  66. property DirectionSidewayLeft: TPoint3D read GetDirectionSidewayLeft;
  67. property Deplacement: TPoint3D read fPoint write fPoint;
  68. property HitTest default true;
  69. property Viewport3D: TViewport3D read fViewport3D write fViewport3D;
  70. property ShowIntegrateJoystick: Boolean read fShowIntegrateJoystick
  71. write SetShowIntegrateJoystick;
  72. property Acceleration: Single read fAcceleration write fAcceleration;
  73. property Sensitivity: Integer read fSensitivity write fSensitivity;
  74. property MouseCapture: Boolean read GetMouseCapture write SetMouseCapture;
  75. end;
  76. procedure Register;
  77. implementation // --------------------------------------------------------------
  78. // TGBEJoystick
  79. constructor TGBEJoystick.Create(AOwner: TComponent);
  80. begin
  81. inherited;
  82. HitTest := true;
  83. fCircle := TCircle.Create(nil);
  84. fCircle.Parent := self;
  85. fCircle.Stored := false;
  86. fCircle.Locked := true;
  87. fCircle.Fill.Kind := TBrushKind.Gradient;
  88. fCircle.Fill.Gradient.Color := $FFB6B6B6;
  89. fCircle.Fill.Gradient.Color1 := $FF888888;
  90. fCircle.Fill.Gradient.Style := TGradientStyle.Linear;
  91. fCircle.HitTest := false;
  92. fCircle2 := TCircle.Create(nil);
  93. fCircle2.Parent := fCircle;
  94. fCircle2.Stored := false;
  95. fCircle2.Locked := true;
  96. fCircle2.Fill.Kind := TBrushKind.Gradient;
  97. fCircle2.Fill.Gradient.Color := $FF888888;
  98. fCircle2.Fill.Gradient.Color1 := $FFB6B6B6;
  99. fCircle2.Fill.Gradient.Style := TGradientStyle.Linear;
  100. fCircle.Stroke.Thickness := 2;
  101. fCircle2.width := fCircle.width - 20;
  102. fCircle2.height := fCircle.height - 20;
  103. fCircle2.position.X := (fCircle.width - fCircle2.width) / 2;
  104. fCircle2.position.Y := (fCircle.height - fCircle2.height) / 2;
  105. fCircle2.HitTest := false;
  106. fCircle2.Opacity := 0.7;
  107. fShowIntegrateJoystick := true;
  108. fSensitivity := 90;
  109. fCircle.Align := TAlignLayout.Client;
  110. fPoint := Point3D(1, 0, 1);
  111. fAcceleration := 0;
  112. useJoystick := false;
  113. fMouseCapture := false;
  114. fJoystickType := TGBEJoystickType.jtDeplacement;
  115. end;
  116. function TGBEJoystick.GetDirection: TPoint3D;
  117. begin
  118. if (fJoystickType = jtDeplacement) or
  119. (fJoystickType = jtOrientationDeplacement) then
  120. begin
  121. if assigned(fPlayerPosition) then
  122. begin
  123. result := fPoint * (fPlayerPosition.getPositionDirection.AbsolutePosition
  124. - fPlayerPosition.AbsolutePosition).Normalize;
  125. end
  126. else
  127. result := fPoint;
  128. end
  129. else
  130. result := Point3D(0, 0, 0);
  131. end;
  132. function TGBEJoystick.GetDirectionSidewayRight: TPoint3D;
  133. begin
  134. result := GetDirection.Rotate(Point3D(0, 1, 0), -Pi * 0.5);
  135. // if (fJoystickType = jtDeplacement) or (fJoystickType = jtOrientationDeplacement) then
  136. // begin
  137. // if assigned(fPlayerPosition) then
  138. // begin
  139. // result := fPoint * (fPlayerPosition.getSidewayRightDirection.AbsolutePosition - fPlayerPosition.AbsolutePosition).Normalize;
  140. // end
  141. // else result := fPoint;
  142. // end
  143. // else result := Point3D(0,0,0);
  144. end;
  145. function TGBEJoystick.GetMouseCapture: Boolean;
  146. begin
  147. result := fMouseCapture;
  148. end;
  149. function TGBEJoystick.GetDirectionSidewayLeft: TPoint3D;
  150. begin
  151. result := GetDirection.Rotate(Point3D(0, 1, 0), Pi * 0.5);
  152. // if (fJoystickType = jtDeplacement) or (fJoystickType = jtOrientationDeplacement) then
  153. // begin
  154. // if assigned(fPlayerPosition) then
  155. // begin
  156. // result := fPoint * (fPlayerPosition.getSidewayLeftDirection.AbsolutePosition - fPlayerPosition.AbsolutePosition).Normalize;
  157. // end
  158. // else result := fPoint;
  159. // end
  160. // else result := Point3D(0,0,0);
  161. end;
  162. procedure TGBEJoystick.InitialiserJoystick;
  163. begin
  164. useJoystick := false;
  165. TAnimator.AnimateFloat(fCircle2, 'Position.X',
  166. (fCircle.width - fCircle2.width) / 2);
  167. TAnimator.AnimateFloat(fCircle2, 'Position.Y',
  168. (fCircle.height - fCircle2.height) / 2);
  169. if (fJoystickType = jtDeplacement) or
  170. (fJoystickType = jtOrientationDeplacement) then
  171. fAcceleration := 0;
  172. end;
  173. procedure TGBEJoystick.SetAngleDeVue(const Value: TPointF);
  174. var
  175. // ptA arrival point, ptD departure point, S sensitivity
  176. ptA, ptD, S: TPointF;
  177. begin
  178. if assigned(fPlayerPosition) then
  179. begin
  180. if assigned(fViewport3D) then
  181. begin
  182. // Sensitivity adjustment for right/left orientation
  183. S.X := fSensitivity / self.width;
  184. // Sensitivity adjustment for up/down orientation
  185. S.Y := fSensitivity / self.height;
  186. ptA := Value * S; // Arrival point adapted to sensitivity
  187. ptD := FPosDepartCurseur * S; // Starting point adapted to sensitivity
  188. // Right/Left view
  189. with fPlayerPosition.RotationAngle do
  190. Y := Y + (ptA.X - ptD.X);
  191. // right/left orientation (y axis) based on mouse movement in X
  192. // Top/Bottom View
  193. with fPlayerPosition.getDummyOrientation.RotationAngle do
  194. X := X + (ptD.Y - ptA.Y);
  195. // the same for the up/down orientation by adapting
  196. // (rotation on the x axis, e function of the movement of the mouse in Y
  197. FPosDepartCurseur := Value;
  198. // the cursor position when the user clicked (the origin of the direction),
  199. // is updated with the new cursor position: on the next call to OnMouseMove,
  200. // the starting position must be the ending position of the previous move
  201. end;
  202. end;
  203. end;
  204. procedure TGBEJoystick.MouseDown(Button: TMouseButton; Shift: TShiftState;
  205. X, Y: Single);
  206. begin
  207. inherited;
  208. if ssLeft in Shift then
  209. begin
  210. FPosDepartCurseur := PointF(X, Y);
  211. useJoystick := true;
  212. end;
  213. Offset.X := X;
  214. Offset.Y := Y;
  215. end;
  216. procedure TGBEJoystick.DoMouseLeave;
  217. begin
  218. inherited;
  219. InitialiserJoystick;
  220. end;
  221. procedure TGBEJoystick.MouseMove(Shift: TShiftState; X, Y: Single);
  222. begin
  223. inherited;
  224. if ssLeft in Shift then
  225. begin
  226. if (Viewport3D <> nil) and (PlayerPosition <> nil) then
  227. begin
  228. if (fJoystickType = jtOrientation) or
  229. (fJoystickType = jtOrientationDeplacement) then
  230. AngleDeVue := PointF(X, Y);
  231. fCircle2.position.X := X - Offset.X;
  232. fCircle2.position.Y := Y - Offset.Y;
  233. interactionIHM(Viewport3D);
  234. end;
  235. end;
  236. end;
  237. procedure TGBEJoystick.MouseUp(Button: TMouseButton; Shift: TShiftState;
  238. X, Y: Single);
  239. begin
  240. inherited;
  241. InitialiserJoystick;
  242. end;
  243. procedure TGBEJoystick.Paint;
  244. begin
  245. inherited;
  246. // if useJoystick then
  247. // begin
  248. // if (fJoystickType = jtDeplacement) or (fJoystickType = jtOrientationDeplacement) then
  249. // begin
  250. // if assigned(fPlayerPosition) then
  251. // begin
  252. /// / FAcceleration := FAcceleration + ((fCircle.Height - fCircle2.Height)*0.5 + fCircle2.position.Y) / Sensitivity;
  253. /// / fPlayerPosition.RotationAngle.Y := fPlayerPosition.RotationAngle.Y - ((fCircle.Width - fCircle2.Width)*0.5 - fCircle2.Position.X) / Sensitivity;
  254. // end;
  255. // end;
  256. // end;
  257. end;
  258. procedure TGBEJoystick.Resize;
  259. begin
  260. inherited;
  261. fCircle2.width := fCircle.width - 20;
  262. fCircle2.height := fCircle.height - 20;
  263. fCircle2.position.X := (fCircle.width - fCircle2.width) * 0.5;
  264. fCircle2.position.Y := (fCircle.height - fCircle2.height) * 0.5;
  265. end;
  266. procedure TGBEJoystick.SetJoystickType(const Value: TGBEJoystickType);
  267. begin
  268. fJoystickType := Value;
  269. case Value of
  270. jtOrientation:
  271. begin // To improve
  272. end;
  273. jtDeplacement:
  274. begin // To improve
  275. end;
  276. jtOrientationDeplacement:
  277. begin // To improve
  278. end;
  279. end;
  280. end;
  281. procedure TGBEJoystick.SetMouseCapture(const Value: Boolean);
  282. begin
  283. if Value <> fMouseCapture then
  284. begin
  285. fMouseCapture := Value;
  286. AutoCapture := Value;
  287. end;
  288. end;
  289. procedure TGBEJoystick.SetShowIntegrateJoystick(const Value: Boolean);
  290. begin
  291. fShowIntegrateJoystick := Value;
  292. fCircle.Visible := fShowIntegrateJoystick;
  293. fCircle2.Visible := fShowIntegrateJoystick;
  294. end;
  295. destructor TGBEJoystick.Destroy;
  296. begin
  297. DoDeleteChildren;
  298. inherited;
  299. end;
  300. function TGBEJoystick.OrientationKeyManagement(rightKey, leftKey, upKey,
  301. downKey, goUp, goDown, sideWayRight, sideWayLeft: Boolean;
  302. sensibility, speed, maxspeed: Single): Single;
  303. begin
  304. if assigned(PlayerPosition) then
  305. begin
  306. if rightKey then
  307. PlayerPosition.RotationAngle.Y := PlayerPosition.RotationAngle.Y +
  308. sensibility;
  309. if leftKey then
  310. PlayerPosition.RotationAngle.Y := PlayerPosition.RotationAngle.Y -
  311. sensibility;
  312. if goUp then
  313. PlayerPosition.getDummyOrientation.RotationAngle.X :=
  314. PlayerPosition.getDummyOrientation.RotationAngle.X + sensibility;
  315. if goDown then
  316. PlayerPosition.getDummyOrientation.RotationAngle.X :=
  317. PlayerPosition.getDummyOrientation.RotationAngle.X - sensibility;
  318. if upKey or sideWayRight or sideWayLeft then
  319. begin
  320. if speed > -maxspeed then
  321. speed := speed - sensibility
  322. else
  323. speed := -maxspeed;
  324. end;
  325. if downKey then
  326. begin
  327. if speed < maxspeed then
  328. speed := speed + sensibility
  329. else
  330. speed := maxspeed;
  331. end;
  332. end;
  333. result := speed;
  334. end;
  335. // ----------------------------------------------------------------------
  336. procedure Register;
  337. begin
  338. RegisterComponents('GXScene GBE', [TGBEJoystick]);
  339. end;
  340. end.