Advertisement
valterb

TestDblClick

Jul 29th, 2021 (edited)
743
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pascal 10.41 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.   const
  19.     { Rotation speed of the plane }
  20.     RotFactor: Single = 0.03;
  21.   private
  22.     HasLastMousePressPosition: Boolean;
  23.     LastMousePressPosition: TVector2;
  24.     LastMousePressTime: TTimerResult;
  25.     { Components designed using CGE editor, loaded from gamestatemain.castle-user-interface. }
  26.     LabelFps: TCastleLabel;
  27.     LabelRot: TCastleLabel;
  28.     ImagePlayer: TCastleImageControl;
  29.     ImgFlying: Boolean;
  30.     ImgTarget: TVector2;
  31.     ImgRotStart, ImgRotStop: TVector2;
  32.     PlayerPosition: TVector2;
  33.     PlayerRotation: Single;
  34.     ImgSpeed: TVector2;
  35.     FirstClick: QWord;
  36.     MoveStart, MoveStop: Boolean;
  37.   public
  38.     constructor Create(AOwner: TComponent); override;
  39.     procedure Start; override;
  40.     procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
  41.     procedure GetRadians(PlayerPos, PlayerTarget: TVector2);
  42.     function Press(const Event: TInputPressRelease): Boolean; override;
  43.     //procedure ExecuteAction(FactorX, FactorY: Single);
  44.   end;
  45.  
  46. var
  47.   StateMain: TStateMain;
  48.  
  49. implementation
  50.  
  51. uses SysUtils;
  52.  
  53. const
  54.   MaxDistanceForDoubleClick = 10;
  55.   MaxTimeForDoubleClick = 0.5;
  56.  
  57.  
  58. { TStateMain ----------------------------------------------------------------- }
  59.  
  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.  
  71.   HasLastMousePressPosition := false;
  72.   { Find components, by name, that we need to access from code }
  73.   LabelFps := DesignedComponent('LabelFps') as TCastleLabel;
  74.   LabelRot := DesignedComponent('LabelRot') as TCastleLabel;
  75.   ImagePlayer := DesignedComponent('ImagePlayer') as TCastleImageControl;
  76.  
  77.   ImgSpeed := Vector2(300, 300);
  78. end;
  79.  
  80. procedure TStateMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
  81. begin
  82.   inherited;
  83.   { This virtual method is executed every frame.}
  84.   LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
  85.   LabelRot.Caption := 'Plane Rotation: ' + ImagePlayer.Rotation.ToString + ' (rad)';
  86.  
  87.   if HasLastMousePressPosition and
  88.      (LastMousePressTime.ElapsedTime >= MaxTimeForDoubleClick) then
  89.   begin
  90.     // Single-click handled, so forget about previous press event and do not store this press event.
  91.     HasLastMousePressPosition := false;
  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 (Abs(PlayerPosition.Y - ImgTarget.Y) < ImgRotStop.Y) then
  145.       begin
  146.         if ImagePlayer.Rotation < 0 then
  147.           ImagePlayer.Rotation := ImagePlayer.Rotation + RotFactor
  148.         else
  149.           ImagePlayer.Rotation := ImagePlayer.Rotation - RotFactor
  150.       end;
  151.     end;
  152.  
  153.     if PlayerPosition.x < ImgTarget.X then
  154.       PlayerPosition.X := (Min(ImgTarget.X, (PlayerPosition.X) + ImgSpeed.X * SecondsPassed))
  155.     else
  156.       PlayerPosition.X := (Max(ImgTarget.X, (PlayerPosition.X) - ImgSpeed.X * SecondsPassed));
  157.  
  158.     if PlayerPosition.Y < ImgTarget.Y then
  159.       PlayerPosition.Y := (Min(ImgTarget.Y, (PlayerPosition.Y) + ImgSpeed.Y * SecondsPassed))
  160.     else
  161.       PlayerPosition.Y := (Max(ImgTarget.Y, (PlayerPosition.Y) - ImgSpeed.Y * SecondsPassed));
  162.   end;
  163.  
  164.   ImagePlayer.AnchorDelta := PlayerPosition;
  165.  
  166.   if (PlayerPosition.X = ImgTarget.X) and
  167.      (PlayerPosition.Y = ImgTarget.Y) then
  168.   begin
  169.     ImagePlayer.Rotation := 0;
  170.     ImgSpeed := Vector2(300, 300);
  171.     ImgFlying := false;
  172.     MoveStop := false;
  173.   end;
  174. end;
  175.  
  176. function TStateMain.Press(const Event: TInputPressRelease): Boolean;
  177. var
  178.   FactorX: Single;
  179.   FactorY: Single;
  180.   LengthX, LengthY: Single;
  181. begin
  182.   Result := inherited;
  183.   if Result then Exit; // allow the ancestor to handle keys
  184.  
  185.   if Event.IsKey(keyArrowLeft) then
  186.   begin
  187.     ImagePlayer.FlipHorizontal:=true;
  188.     Exit(true);
  189.   end;
  190.  
  191.   if Event.IsKey(keyArrowRight) then
  192.   begin
  193.     ImagePlayer.FlipHorizontal:=false;
  194.     Exit(true);
  195.   end;
  196.  
  197.   if Event.IsKey(keySpace) then
  198.   begin
  199.     ImagePlayer.Color := Vector4(Random, Random, Random, 1);
  200.     Exit(true); // event was handled
  201.   end;
  202.  
  203.   if Event.IsMouseButton(buttonLeft) then
  204.   begin
  205.     ImgTarget := ImagePlayer.Parent.ContainerToLocalPosition(Event.Position);
  206.  
  207.     if HasLastMousePressPosition and
  208.        (PointsDistance(Event.Position, LastMousePressPosition) < MaxDistanceForDoubleClick) and
  209.        (LastMousePressTime.ElapsedTime < MaxTimeForDoubleClick) then
  210.     begin
  211.       // Double-click handled, so forget about previous press event and do not store this press event.
  212.       FactorX := 700;
  213.       FactorY := 700;
  214.       { Move the arrival point to the center of the plane }
  215.       ImgTarget.X := ImgTarget.X - ImagePlayer.EffectiveWidth/2;
  216.       ImgTarget.Y := ImgTarget.Y - ImagePlayer.EffectiveHeight/2;
  217.  
  218.       { By changing the two speeds of the plane on the X and Y axis it will
  219.         arrive directly at the arrival point (unlike the Dragon demo,
  220.         it depends on the game }
  221.       LengthX := Abs(PlayerPosition.X - ImgTarget.X);
  222.       LengthY := Abs(PlayerPosition.Y - ImgTarget.Y);
  223.       if LengthX > LengthY then
  224.       begin
  225.         ImgSpeed.X:= FactorX;
  226.         ImgSpeed.Y := FactorY * LengthY / LengthX;
  227.       end
  228.       else
  229.       begin
  230.         ImgSpeed.Y := FactorY;
  231.         ImgSpeed.X := FactorX * LengthX / LengthY;
  232.       end;
  233.       GetRadians(PlayerPosition, imgTarget);
  234.       ImgFlying := true;
  235.  
  236.       HasLastMousePressPosition := false;
  237.     end else
  238.     begin
  239.       // Make single-click, if we have an unprocessed press event that wasn't double-click (because of too far distance).
  240.       if HasLastMousePressPosition then
  241.       begin
  242.         FactorX := 300;
  243.         FactorY := 300;
  244.         { Move the arrival point to the center of the plane }
  245.         ImgTarget.X := ImgTarget.X - ImagePlayer.EffectiveWidth/2;
  246.         ImgTarget.Y := ImgTarget.Y - ImagePlayer.EffectiveHeight/2;
  247.  
  248.         { By changing the two speeds of the plane on the X and Y axis it will
  249.           arrive directly at the arrival point (unlike the Dragon demo,
  250.           it depends on the game }
  251.         LengthX := Abs(PlayerPosition.X - ImgTarget.X);
  252.         LengthY := Abs(PlayerPosition.Y - ImgTarget.Y);
  253.         if LengthX > LengthY then
  254.         begin
  255.           ImgSpeed.X:= FactorX;
  256.           ImgSpeed.Y := FactorY * LengthY / LengthX;
  257.         end
  258.         else
  259.         begin
  260.           ImgSpeed.Y := FactorY;
  261.           ImgSpeed.X := FactorX * LengthX / LengthY;
  262.         end;
  263.         GetRadians(PlayerPosition, imgTarget);
  264.         ImgFlying := true;
  265.       end;
  266.  
  267.       HasLastMousePressPosition := true;
  268.       LastMousePressPosition := Event.Position;
  269.       LastMousePressTime := Timer;
  270.     end;
  271.  
  272.     Exit(true); // event was handled
  273.   end;
  274. end;
  275.  
  276. { Get direction of plane in radians }
  277. procedure TStateMain.GetRadians(PlayerPos, PlayerTarget: TVector2);
  278. var
  279.   MouseX, MouseY,
  280.   PlayerX, PlayerY,
  281.   DiffX, DiffY,
  282.   ArcTanXY: single;
  283. begin
  284.   ImgRotStart := PlayerPos;
  285.   if PlayerPos.X > PlayerTarget.X then
  286.     ImagePlayer.FlipHorizontal:=true
  287.   else
  288.     ImagePlayer.FlipHorizontal:=false;
  289.   MouseX := PlayerTarget.X;
  290.   MouseY := PlayerTarget.y;
  291.   PlayerX := PlayerPos.X;
  292.   PlayerY := PlayerPos.Y;
  293.   if (PlayerY < MouseY) then
  294.   begin
  295.     DiffY := (MouseY - PlayerY);
  296.     if (PlayerX < MouseX) then
  297.     begin
  298.       DiffX := (MouseX - PlayerX);
  299.       ArcTanXY := (PI/2) - Math.arctan2(DiffX, DiffY);
  300.     end
  301.     else
  302.     begin
  303.       DiffX := (PlayerX - MouseX);
  304.       ArcTanXY := Math.arctan2(DiffX, DiffY) - (PI/2);
  305.     end;
  306.   end
  307.   else if PlayerY > MouseY then
  308.   begin
  309.     DiffY := (PlayerY - MouseY);
  310.     if (PlayerX < MouseX) then
  311.     begin
  312.       DiffX := (MouseX - PlayerX);
  313.       ArcTanXY := Math.arctan2(DiffX, DiffY) - (PI/2);
  314.     end
  315.     else
  316.     begin
  317.       DiffX := (PlayerX - MouseX);
  318.       ArcTanXY := (PI/2) - Math.arctan2(DiffX, DiffY);
  319.     end;
  320.   end;
  321.   PlayerRotation := ArcTanXY;
  322.   MoveStart := true;
  323. end;
  324.  
  325. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement