Advertisement
Guest User

DemoMountains

a guest
Jul 28th, 2021
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pascal 9.87 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.     { Interval between two clicks }
  20.     DblClick: Single = 300;
  21.     { Rotation speed of the plane }
  22.     RotFactor: Single = 0.03;
  23.   private
  24.     { Components designed using CGE editor, loaded from gamestatemain.castle-user-interface. }
  25.     LabelFps: TCastleLabel;
  26.     LabelRot: TCastleLabel;
  27.     ImagePlayer: TCastleImageControl;
  28.     ImgFlying: Boolean;
  29.     ImgTarget: TVector2;
  30.     ImgRotStart, ImgRotStop: TVector2;
  31.     PlayerPosition: TVector2;
  32.     PlayerRotation: Single;
  33.     ImgSpeed: TVector2;
  34.     FirstClick: QWord;
  35.     MoveStart, MoveStop: Boolean;
  36.   public
  37.     constructor Create(AOwner: TComponent); override;
  38.     procedure Start; override;
  39.     procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
  40.     procedure GetRadians(PlayerPos, PlayerTarget: TVector2);
  41.     function Press(const Event: TInputPressRelease): Boolean; override;
  42.   end;
  43.  
  44. var
  45.   StateMain: TStateMain;
  46.  
  47. implementation
  48.  
  49. uses SysUtils;
  50.  
  51. { TStateMain ----------------------------------------------------------------- }
  52.  
  53.  
  54. constructor TStateMain.Create(AOwner: TComponent);
  55. begin
  56.   inherited;
  57.   DesignUrl := 'castle-data:/gamestatemain.castle-user-interface';
  58. end;
  59.  
  60. procedure TStateMain.Start;
  61. begin
  62.   inherited;
  63.  
  64.   { Find components, by name, that we need to access from code }
  65.   LabelFps := DesignedComponent('LabelFps') as TCastleLabel;
  66.   LabelRot := DesignedComponent('LabelRot') as TCastleLabel;
  67.   ImagePlayer := DesignedComponent('ImagePlayer') as TCastleImageControl;
  68.  
  69.   ImgSpeed := Vector2(300, 300);
  70.   FirstClick := 0;
  71. end;
  72.  
  73. procedure TStateMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
  74. { const
  75.     MoveSpeed = 800; Moved to ImgSpeed }
  76.   var
  77.     //PlayerPosition: TVector2;
  78.     CheckDblClick: QWord;
  79. begin
  80.   inherited;
  81.   { This virtual method is executed every frame.}
  82.   LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
  83.   LabelRot.Caption := 'Plane Rotation: ' + ImagePlayer.Rotation.ToString + ' (rad)';
  84.  
  85.   { Reset the first click if the double click has not occurred }
  86.   if (FirstClick > 0) then
  87.   begin
  88.     CheckDblClick := CastleGetTickCount64;
  89.     if ((CheckDblClick - FirstClick) > DblClick) then FirstClick := 0;
  90.   end;
  91.  
  92.   { update player position [to fall down] }
  93.   PlayerPosition := ImagePlayer.AnchorDelta;
  94.  
  95.   // NEW CODE WE ADD:
  96.   if Container.Pressed[keyArrowLeft] then
  97.     PlayerPosition := PlayerPosition + Vector2(-ImgSpeed.X * SecondsPassed, 0);
  98.   if Container.Pressed[keyArrowRight] then
  99.     PlayerPosition := PlayerPosition + Vector2( ImgSpeed.X * SecondsPassed, 0);
  100.   if Container.Pressed[keyArrowDown] then
  101.     PlayerPosition := PlayerPosition + Vector2(0, -ImgSpeed.Y * SecondsPassed);
  102.   if Container.Pressed[keyArrowUp] then
  103.     PlayerPosition := PlayerPosition + Vector2(0,  ImgSpeed.Y * SecondsPassed);
  104.  
  105.   //PlayerPosition.Y := Max(PlayerPosition.Y - SecondsPassed * 400, 0);
  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 = 300;
  179.   FactorY: Single = 300;
  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.     { Routine to intercept the double click
  208.       Note: at the first click the plane will start to move and only at the
  209.       second click will it increase its speed
  210.       This can be useful if the moving object is a character because you will
  211.       get the impression that it starts running
  212.       It would be good to introduce a control to check if the two clicks occur
  213.       close together in space }
  214.     if FirstClick = 0 then FirstClick := CastleGetTickCount64
  215.     else
  216.     begin
  217.         FactorX := 700;
  218.         FactorY := 700;
  219.     end;
  220.  
  221.     ImgTarget := ImagePlayer.Parent.ContainerToLocalPosition(Event.Position);
  222.  
  223.     { Move the arrival point to the center of the plane }
  224.     ImgTarget.X := ImgTarget.X - ImagePlayer.EffectiveWidth/2;
  225.     ImgTarget.Y := ImgTarget.Y - ImagePlayer.EffectiveHeight/2;
  226.  
  227.     { By changing the two speeds of the plane on the X and Y axis it will
  228.       arrive directly at the arrival point (unlike the Dragon demo,
  229.       it depends on the game }
  230.     LengthX := Abs(PlayerPosition.X - ImgTarget.X);
  231.     LengthY := Abs(PlayerPosition.Y - ImgTarget.Y);
  232.     if LengthX > LengthY then
  233.     begin
  234.       ImgSpeed.X:= FactorX;
  235.       ImgSpeed.Y := FactorY * LengthY / LengthX;
  236.     end
  237.     else
  238.     begin
  239.       ImgSpeed.Y := FactorY;
  240.       ImgSpeed.X := FactorX * LengthX / LengthY;
  241.     end;
  242.     GetRadians(PlayerPosition, imgTarget);
  243.     ImgFlying := true;
  244.     Exit(true); // event was handled
  245.   end;
  246.  
  247.   { This virtual method is executed when user presses
  248.     a key, a mouse button, or touches a touch-screen.
  249.  
  250.     Note that each UI control has also events like OnPress and OnClick.
  251.     These events can be used to handle the "press", if it should do something
  252.     specific when used in that UI control.
  253.     The TStateMain.Press method should be used to handle keys
  254.     not handled in children controls.
  255.   }
  256.  
  257.   // Use this to handle keys:
  258.   {
  259.   if Event.IsKey(keyXxx) then
  260.   begin
  261.     // DoSomething;
  262.     Exit(true); // key was handled
  263.   end;
  264.   }
  265. end;
  266.  
  267. { Get direction of plane in radians }
  268. procedure TStateMain.GetRadians(PlayerPos, PlayerTarget: TVector2);
  269. var
  270.   MouseX, MouseY,
  271.   PlayerX, PlayerY,
  272.   DiffX, DiffY,
  273.   ArcTanXY: single;
  274. begin
  275.   ImgRotStart := PlayerPos;
  276.   if PlayerPos.X > PlayerTarget.X then
  277.     ImagePlayer.FlipHorizontal:=true
  278.   else
  279.     ImagePlayer.FlipHorizontal:=false;
  280.   MouseX := PlayerTarget.X;
  281.   MouseY := PlayerTarget.y;
  282.   PlayerX := PlayerPos.X;
  283.   PlayerY := PlayerPos.Y;
  284.   if (PlayerY < MouseY) then
  285.   begin
  286.     DiffY := (MouseY - PlayerY);
  287.     if (PlayerX < MouseX) then
  288.     begin
  289.       DiffX := (MouseX - PlayerX);
  290.       ArcTanXY := (PI/2) - Math.arctan2(DiffX, DiffY);
  291.     end
  292.     else
  293.     begin
  294.       DiffX := (PlayerX - MouseX);
  295.       ArcTanXY := Math.arctan2(DiffX, DiffY) - (PI/2);
  296.     end;
  297.   end
  298.   else if PlayerY > MouseY then
  299.   begin
  300.     DiffY := (PlayerY - MouseY);
  301.     if (PlayerX < MouseX) then
  302.     begin
  303.       DiffX := (MouseX - PlayerX);
  304.       ArcTanXY := Math.arctan2(DiffX, DiffY) - (PI/2);
  305.     end
  306.     else
  307.     begin
  308.       DiffX := (PlayerX - MouseX);
  309.       ArcTanXY := (PI/2) - Math.arctan2(DiffX, DiffY);
  310.     end;
  311.   end;
  312.   PlayerRotation := ArcTanXY;
  313.   MoveStart := true;
  314. end;
  315.  
  316. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement