Advertisement
valterb

TestDblClick2

Jul 29th, 2021
162
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pascal 9.32 KB | None | 0 0
  1. { Main state, where most of the application logic takes place.
  2.  
  3.   Feel free to use this code as a starting point for your own projects.
  4.   (This code is in public domain, unlike most other CGE code which
  5.   is covered by the LGPL license variant, see the COPYING.txt file.) }
  6. unit GameStateMain;
  7.  
  8. interface
  9.  
  10. uses Classes,
  11.   CastleVectors, CastleUIState, CastleComponentSerialize,
  12.   CastleUIControls, CastleControls, CastleKeysMouse, CastleTimeUtils, Math;
  13.  
  14. type
  15.   { Main state, where most of the application logic takes place. }
  16.   TStateMain = class(TUIState)
  17.  
  18.   private
  19.     { Components designed using CGE editor, loaded from gamestatemain.castle-user-interface. }
  20.     LastMousePressPosition: TVector2;
  21.     LabelFps: TCastleLabel;
  22.     LabelRot: TCastleLabel;
  23.     ImagePlayer: TCastleImageControl;
  24.     ImgFlying: Boolean;
  25.     ImgTarget: TVector2;
  26.     ImgRotStart, ImgRotStop: TVector2;
  27.     PlayerPosition: TVector2;
  28.     PlayerRotation: Single;
  29.     ImgSpeed: TVector2;
  30.     FirstClick: QWord;
  31.     MoveStart, MoveStop: Boolean;
  32.   public
  33.     constructor Create(AOwner: TComponent); override;
  34.     procedure Start; override;
  35.     procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
  36.     procedure MovePlane;
  37.     procedure GetRadians(PlayerPos, PlayerTarget: TVector2);
  38.     procedure CallSingleClick;
  39.     procedure ResetPlane(IsDblClick: Boolean);
  40.     function Press(const Event: TInputPressRelease): Boolean; override;
  41.  
  42.   end;
  43.  
  44. var
  45.   StateMain: TStateMain;
  46.  
  47. implementation
  48.  
  49. uses SysUtils;
  50.  
  51. const
  52.   { Interval between two clicks }
  53.   DblClick: Single = 250;
  54.   { Maximum distance between two clicks }
  55.   MaxDistanceForDoubleClick = 10;
  56.   { Rotation speed of the plane }
  57.   RotFactor: Single = 0.03;
  58.  
  59. { TStateMain ----------------------------------------------------------------- }
  60.  
  61. constructor TStateMain.Create(AOwner: TComponent);
  62. begin
  63.   inherited;
  64.   DesignUrl := 'castle-data:/gamestatemain.castle-user-interface';
  65. end;
  66.  
  67. procedure TStateMain.Start;
  68. begin
  69.   inherited;
  70.   { Find components, by name, that we need to access from code }
  71.   LabelFps := DesignedComponent('LabelFps') as TCastleLabel;
  72.   LabelRot := DesignedComponent('LabelRot') as TCastleLabel;
  73.   ImagePlayer := DesignedComponent('ImagePlayer') as TCastleImageControl;
  74.   FirstClick := 0;
  75. end;
  76.  
  77. procedure TStateMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
  78. var
  79.   CheckDblClick: QWord;
  80. begin
  81.   inherited;
  82.   { This virtual method is executed every frame.}
  83.   LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
  84.   LabelRot.Caption := 'Plane Rotation: ' + ImagePlayer.Rotation.ToString + ' (rad)';
  85.  
  86.   { Reset the first click if the double click has not occurred and run single click }
  87.   if ((FirstClick > 0) and (imgFlying <> true)) then
  88.   begin
  89.     CheckDblClick := CastleGetTickCount64;
  90.     if ((CheckDblClick - FirstClick) > DblClick) then
  91.       CallSingleClick;
  92.   end;
  93.  
  94.   { update player position [to fall down] }
  95.   PlayerPosition := ImagePlayer.AnchorDelta;
  96.  
  97.   // NEW CODE WE ADD:
  98.   if Container.Pressed[keyArrowLeft] then
  99.     PlayerPosition := PlayerPosition + Vector2(-ImgSpeed.X * SecondsPassed, 0);
  100.   if Container.Pressed[keyArrowRight] then
  101.     PlayerPosition := PlayerPosition + Vector2( ImgSpeed.X * SecondsPassed, 0);
  102.   if Container.Pressed[keyArrowDown] then
  103.     PlayerPosition := PlayerPosition + Vector2(0, -ImgSpeed.Y * SecondsPassed);
  104.   if Container.Pressed[keyArrowUp] then
  105.     PlayerPosition := PlayerPosition + Vector2(0,  ImgSpeed.Y * SecondsPassed);
  106.  
  107.   if ImgFlying then
  108.   begin
  109.     { Rotate the plane when it starts
  110.       PlayerRotation returned by the GetRadians procedure }
  111.     if MoveStart then
  112.     begin
  113.       if ImagePlayer.Rotation <> PlayerRotation then
  114.       begin
  115.       if PlayerRotation < 0 then
  116.         begin
  117.           if ImagePlayer.Rotation > PlayerRotation then ImagePlayer.Rotation := ImagePlayer.Rotation - RotFactor
  118.             else
  119.              ImagePlayer.Rotation := PlayerRotation;
  120.         end
  121.         else
  122.         begin
  123.           if ImagePlayer.Rotation < PlayerRotation then ImagePlayer.Rotation := ImagePlayer.Rotation + RotFactor
  124.             else
  125.              ImagePlayer.Rotation := PlayerRotation;
  126.         end;
  127.       end
  128.       else
  129.       begin
  130.         MoveStart := false;
  131.         MoveStop := true;
  132.         { Stores the distance of the plane from the starting point when it finishes rotating
  133.           When the plane is at the same distance from the point of arrival it will begin to rotate in reverse
  134.           The action will be complete only if the distance between the two starting and ending points is not too short }
  135.         ImgRotStop.X := Abs(ImgRotStart.X - PlayerPosition.X);
  136.         imgRotStop.Y := Abs(ImgRotStart.Y - PlayerPosition.Y);
  137.         LabelFps.Caption := ImgRotStop.X.ToString + '   ' + ImgRotStop.Y.ToString;
  138.       end;
  139.     end;
  140.  
  141.     { Rotate the plane when it arrives }
  142.     if MoveStop then
  143.     begin
  144.       if (Abs(PlayerPosition.X - ImgTarget.X) < ImgRotStop.X) or
  145.          (Abs(PlayerPosition.Y - ImgTarget.Y) < ImgRotStop.Y) then
  146.       begin
  147.         if ImagePlayer.Rotation < 0 then
  148.           ImagePlayer.Rotation := ImagePlayer.Rotation + RotFactor
  149.         else
  150.           ImagePlayer.Rotation := ImagePlayer.Rotation - RotFactor
  151.       end;
  152.     end;
  153.  
  154.     if PlayerPosition.x < ImgTarget.X then
  155.       PlayerPosition.X := (Min(ImgTarget.X, (PlayerPosition.X) + ImgSpeed.X * SecondsPassed))
  156.     else
  157.       PlayerPosition.X := (Max(ImgTarget.X, (PlayerPosition.X) - ImgSpeed.X * SecondsPassed));
  158.  
  159.     if PlayerPosition.Y < ImgTarget.Y then
  160.       PlayerPosition.Y := (Min(ImgTarget.Y, (PlayerPosition.Y) + ImgSpeed.Y * SecondsPassed))
  161.     else
  162.       PlayerPosition.Y := (Max(ImgTarget.Y, (PlayerPosition.Y) - ImgSpeed.Y * SecondsPassed));
  163.   end;
  164.  
  165.   ImagePlayer.AnchorDelta := PlayerPosition;
  166.  
  167.   if (PlayerPosition.X = ImgTarget.X) and
  168.      (PlayerPosition.Y = ImgTarget.Y) then
  169.     ResetPlane(false);
  170. end;
  171.  
  172. function TStateMain.Press(const Event: TInputPressRelease): Boolean;
  173. begin
  174.   Result := inherited;
  175.   if Result then Exit; // allow the ancestor to handle keys
  176.  
  177.   if Event.IsKey(keyArrowLeft) then
  178.   begin
  179.     ImagePlayer.FlipHorizontal:=true;
  180.     Exit(true);
  181.   end;
  182.  
  183.   if Event.IsKey(keyArrowRight) then
  184.   begin
  185.     ImagePlayer.FlipHorizontal:=false;
  186.     Exit(true);
  187.   end;
  188.  
  189.   if Event.IsKey(keySpace) then
  190.   begin
  191.     ImagePlayer.Color := Vector4(Random, Random, Random, 1);
  192.     Exit(true); // event was handled
  193.   end;
  194.  
  195.   if Event.IsMouseButton(buttonLeft) then
  196.   begin
  197.     ImgFlying := false;
  198.     ImgTarget := ImagePlayer.Parent.ContainerToLocalPosition(Event.Position);
  199.  
  200.     { Intercepts the double click if it occurs }
  201.     if FirstClick = 0 then
  202.     begin
  203.       FirstClick := CastleGetTickCount64;
  204.       LastMousePressPosition := Event.Position;
  205.     end
  206.     else if (PointsDistance(Event.Position, LastMousePressPosition) < MaxDistanceForDoubleClick) then
  207.     begin
  208.         ResetPlane(true);
  209.         MovePlane;
  210.     end;
  211.     Exit(true); // event was handled
  212.   end;
  213. end;
  214.  
  215. procedure TStateMain.CallSingleClick;
  216. begin
  217.   ResetPlane(false);
  218.   MovePlane;
  219. end;
  220.  
  221. procedure TStateMain.MovePlane;
  222. var
  223.   LengthX, LengthY: Single;
  224. begin
  225.   { Move the arrival point to the center of the plane }
  226.   ImgTarget.X := ImgTarget.X - ImagePlayer.EffectiveWidth/2;
  227.   ImgTarget.Y := ImgTarget.Y - ImagePlayer.EffectiveHeight/2;
  228.  
  229.   { By changing the two speeds of the plane on the X and Y axis it will
  230.     arrive directly at the arrival point (unlike the Dragon demo,
  231.     it depends on the game }
  232.   LengthX := Abs(PlayerPosition.X - ImgTarget.X);
  233.   LengthY := Abs(PlayerPosition.Y - ImgTarget.Y);
  234.   if LengthX > LengthY then
  235.   begin
  236.     ImgSpeed.Y := ImgSpeed.Y * LengthY / LengthX;
  237.   end
  238.   else
  239.   begin
  240.     ImgSpeed.X := ImgSpeed.X * LengthX / LengthY;
  241.   end;
  242.   GetRadians(PlayerPosition, imgTarget);
  243. end;
  244.  
  245. { Get direction of plane in radians }
  246. procedure TStateMain.GetRadians(PlayerPos, PlayerTarget: TVector2);
  247. var
  248.   MouseX, MouseY,
  249.   PlayerX, PlayerY,
  250.   DiffX, DiffY,
  251.   ArcTanXY: single;
  252. begin
  253.   ImgRotStart := PlayerPos;
  254.   if PlayerPos.X > PlayerTarget.X then
  255.     ImagePlayer.FlipHorizontal:=true
  256.   else
  257.     ImagePlayer.FlipHorizontal:=false;
  258.   MouseX := PlayerTarget.X;
  259.   MouseY := PlayerTarget.y;
  260.   PlayerX := PlayerPos.X;
  261.   PlayerY := PlayerPos.Y;
  262.   if (PlayerY < MouseY) then
  263.   begin
  264.     DiffY := (MouseY - PlayerY);
  265.     if (PlayerX < MouseX) then
  266.     begin
  267.       DiffX := (MouseX - PlayerX);
  268.       ArcTanXY := (PI/2) - Math.arctan2(DiffX, DiffY);
  269.     end
  270.     else
  271.     begin
  272.       DiffX := (PlayerX - MouseX);
  273.       ArcTanXY := Math.arctan2(DiffX, DiffY) - (PI/2);
  274.     end;
  275.   end
  276.   else if PlayerY > MouseY then
  277.   begin
  278.     DiffY := (PlayerY - MouseY);
  279.     if (PlayerX < MouseX) then
  280.     begin
  281.       DiffX := (MouseX - PlayerX);
  282.       ArcTanXY := Math.arctan2(DiffX, DiffY) - (PI/2);
  283.     end
  284.     else
  285.     begin
  286.       DiffX := (PlayerX - MouseX);
  287.       ArcTanXY := (PI/2) - Math.arctan2(DiffX, DiffY);
  288.     end;
  289.   end;
  290.   PlayerRotation := ArcTanXY;
  291.   MoveStart := true;
  292.   ImgFlying := true;
  293. end;
  294.  
  295. procedure TStateMain.ResetPlane(IsDblClick: Boolean);
  296. begin
  297.   FirstClick := 0;
  298.   ImgFlying := false;
  299.   MoveStart := false;
  300.   MoveStop := false;
  301.   ImagePlayer.Rotation := 0;
  302.   if IsDblClick then
  303.     ImgSpeed := Vector2(700, 700)
  304.   else
  305.     ImgSpeed := Vector2(300, 300);
  306. end;
  307.  
  308. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement