Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- { Main state, where most of the application logic takes place.
- Feel free to use this code as a starting point for your own projects.
- (This code is in public domain, unlike most other CGE code which
- is covered by the LGPL license variant, see the COPYING.txt file.) }
- unit GameStateMain;
- interface
- uses Classes,
- CastleVectors, CastleUIState, CastleComponentSerialize,
- CastleUIControls, CastleControls, CastleKeysMouse, CastleTimeUtils, Math;
- type
- { Main state, where most of the application logic takes place. }
- TStateMain = class(TUIState)
- private
- { Components designed using CGE editor, loaded from gamestatemain.castle-user-interface. }
- LastMousePressPosition: TVector2;
- LabelFps: TCastleLabel;
- LabelRot: TCastleLabel;
- ImagePlayer: TCastleImageControl;
- ImgFlying: Boolean;
- ImgTarget: TVector2;
- ImgRotStart, ImgRotStop: TVector2;
- PlayerPosition: TVector2;
- PlayerRotation: Single;
- ImgSpeed: TVector2;
- FirstClick: QWord;
- MoveStart, MoveStop: Boolean;
- public
- constructor Create(AOwner: TComponent); override;
- procedure Start; override;
- procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
- procedure MovePlane;
- procedure GetRadians(PlayerPos, PlayerTarget: TVector2);
- procedure CallSingleClick;
- procedure ResetPlane(IsDblClick: Boolean);
- function Press(const Event: TInputPressRelease): Boolean; override;
- end;
- var
- StateMain: TStateMain;
- implementation
- uses SysUtils;
- const
- { Interval between two clicks }
- DblClick: Single = 250;
- { Maximum distance between two clicks }
- MaxDistanceForDoubleClick = 10;
- { Rotation speed of the plane }
- RotFactor: Single = 0.03;
- { TStateMain ----------------------------------------------------------------- }
- constructor TStateMain.Create(AOwner: TComponent);
- begin
- inherited;
- DesignUrl := 'castle-data:/gamestatemain.castle-user-interface';
- end;
- procedure TStateMain.Start;
- begin
- inherited;
- { Find components, by name, that we need to access from code }
- LabelFps := DesignedComponent('LabelFps') as TCastleLabel;
- LabelRot := DesignedComponent('LabelRot') as TCastleLabel;
- ImagePlayer := DesignedComponent('ImagePlayer') as TCastleImageControl;
- FirstClick := 0;
- end;
- procedure TStateMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
- var
- CheckDblClick: QWord;
- begin
- inherited;
- { This virtual method is executed every frame.}
- LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
- LabelRot.Caption := 'Plane Rotation: ' + ImagePlayer.Rotation.ToString + ' (rad)';
- { Reset the first click if the double click has not occurred and run single click }
- if ((FirstClick > 0) and (imgFlying <> true)) then
- begin
- CheckDblClick := CastleGetTickCount64;
- if ((CheckDblClick - FirstClick) > DblClick) then
- CallSingleClick;
- end;
- { update player position [to fall down] }
- PlayerPosition := ImagePlayer.AnchorDelta;
- // NEW CODE WE ADD:
- if Container.Pressed[keyArrowLeft] then
- PlayerPosition := PlayerPosition + Vector2(-ImgSpeed.X * SecondsPassed, 0);
- if Container.Pressed[keyArrowRight] then
- PlayerPosition := PlayerPosition + Vector2( ImgSpeed.X * SecondsPassed, 0);
- if Container.Pressed[keyArrowDown] then
- PlayerPosition := PlayerPosition + Vector2(0, -ImgSpeed.Y * SecondsPassed);
- if Container.Pressed[keyArrowUp] then
- PlayerPosition := PlayerPosition + Vector2(0, ImgSpeed.Y * SecondsPassed);
- if ImgFlying then
- begin
- { Rotate the plane when it starts
- PlayerRotation returned by the GetRadians procedure }
- if MoveStart then
- begin
- if ImagePlayer.Rotation <> PlayerRotation then
- begin
- if PlayerRotation < 0 then
- begin
- if ImagePlayer.Rotation > PlayerRotation then ImagePlayer.Rotation := ImagePlayer.Rotation - RotFactor
- else
- ImagePlayer.Rotation := PlayerRotation;
- end
- else
- begin
- if ImagePlayer.Rotation < PlayerRotation then ImagePlayer.Rotation := ImagePlayer.Rotation + RotFactor
- else
- ImagePlayer.Rotation := PlayerRotation;
- end;
- end
- else
- begin
- MoveStart := false;
- MoveStop := true;
- { Stores the distance of the plane from the starting point when it finishes rotating
- When the plane is at the same distance from the point of arrival it will begin to rotate in reverse
- The action will be complete only if the distance between the two starting and ending points is not too short }
- ImgRotStop.X := Abs(ImgRotStart.X - PlayerPosition.X);
- imgRotStop.Y := Abs(ImgRotStart.Y - PlayerPosition.Y);
- LabelFps.Caption := ImgRotStop.X.ToString + ' ' + ImgRotStop.Y.ToString;
- end;
- end;
- { Rotate the plane when it arrives }
- if MoveStop then
- begin
- if (Abs(PlayerPosition.X - ImgTarget.X) < ImgRotStop.X) or
- (Abs(PlayerPosition.Y - ImgTarget.Y) < ImgRotStop.Y) then
- begin
- if ImagePlayer.Rotation < 0 then
- ImagePlayer.Rotation := ImagePlayer.Rotation + RotFactor
- else
- ImagePlayer.Rotation := ImagePlayer.Rotation - RotFactor
- end;
- end;
- if PlayerPosition.x < ImgTarget.X then
- PlayerPosition.X := (Min(ImgTarget.X, (PlayerPosition.X) + ImgSpeed.X * SecondsPassed))
- else
- PlayerPosition.X := (Max(ImgTarget.X, (PlayerPosition.X) - ImgSpeed.X * SecondsPassed));
- if PlayerPosition.Y < ImgTarget.Y then
- PlayerPosition.Y := (Min(ImgTarget.Y, (PlayerPosition.Y) + ImgSpeed.Y * SecondsPassed))
- else
- PlayerPosition.Y := (Max(ImgTarget.Y, (PlayerPosition.Y) - ImgSpeed.Y * SecondsPassed));
- end;
- ImagePlayer.AnchorDelta := PlayerPosition;
- if (PlayerPosition.X = ImgTarget.X) and
- (PlayerPosition.Y = ImgTarget.Y) then
- ResetPlane(false);
- end;
- function TStateMain.Press(const Event: TInputPressRelease): Boolean;
- begin
- Result := inherited;
- if Result then Exit; // allow the ancestor to handle keys
- if Event.IsKey(keyArrowLeft) then
- begin
- ImagePlayer.FlipHorizontal:=true;
- Exit(true);
- end;
- if Event.IsKey(keyArrowRight) then
- begin
- ImagePlayer.FlipHorizontal:=false;
- Exit(true);
- end;
- if Event.IsKey(keySpace) then
- begin
- ImagePlayer.Color := Vector4(Random, Random, Random, 1);
- Exit(true); // event was handled
- end;
- if Event.IsMouseButton(buttonLeft) then
- begin
- ImgFlying := false;
- ImgTarget := ImagePlayer.Parent.ContainerToLocalPosition(Event.Position);
- { Intercepts the double click if it occurs }
- if FirstClick = 0 then
- begin
- FirstClick := CastleGetTickCount64;
- LastMousePressPosition := Event.Position;
- end
- else if (PointsDistance(Event.Position, LastMousePressPosition) < MaxDistanceForDoubleClick) then
- begin
- ResetPlane(true);
- MovePlane;
- end;
- Exit(true); // event was handled
- end;
- end;
- procedure TStateMain.CallSingleClick;
- begin
- ResetPlane(false);
- MovePlane;
- end;
- procedure TStateMain.MovePlane;
- var
- LengthX, LengthY: Single;
- begin
- { Move the arrival point to the center of the plane }
- ImgTarget.X := ImgTarget.X - ImagePlayer.EffectiveWidth/2;
- ImgTarget.Y := ImgTarget.Y - ImagePlayer.EffectiveHeight/2;
- { By changing the two speeds of the plane on the X and Y axis it will
- arrive directly at the arrival point (unlike the Dragon demo,
- it depends on the game }
- LengthX := Abs(PlayerPosition.X - ImgTarget.X);
- LengthY := Abs(PlayerPosition.Y - ImgTarget.Y);
- if LengthX > LengthY then
- begin
- ImgSpeed.Y := ImgSpeed.Y * LengthY / LengthX;
- end
- else
- begin
- ImgSpeed.X := ImgSpeed.X * LengthX / LengthY;
- end;
- GetRadians(PlayerPosition, imgTarget);
- end;
- { Get direction of plane in radians }
- procedure TStateMain.GetRadians(PlayerPos, PlayerTarget: TVector2);
- var
- MouseX, MouseY,
- PlayerX, PlayerY,
- DiffX, DiffY,
- ArcTanXY: single;
- begin
- ImgRotStart := PlayerPos;
- if PlayerPos.X > PlayerTarget.X then
- ImagePlayer.FlipHorizontal:=true
- else
- ImagePlayer.FlipHorizontal:=false;
- MouseX := PlayerTarget.X;
- MouseY := PlayerTarget.y;
- PlayerX := PlayerPos.X;
- PlayerY := PlayerPos.Y;
- if (PlayerY < MouseY) then
- begin
- DiffY := (MouseY - PlayerY);
- if (PlayerX < MouseX) then
- begin
- DiffX := (MouseX - PlayerX);
- ArcTanXY := (PI/2) - Math.arctan2(DiffX, DiffY);
- end
- else
- begin
- DiffX := (PlayerX - MouseX);
- ArcTanXY := Math.arctan2(DiffX, DiffY) - (PI/2);
- end;
- end
- else if PlayerY > MouseY then
- begin
- DiffY := (PlayerY - MouseY);
- if (PlayerX < MouseX) then
- begin
- DiffX := (MouseX - PlayerX);
- ArcTanXY := Math.arctan2(DiffX, DiffY) - (PI/2);
- end
- else
- begin
- DiffX := (PlayerX - MouseX);
- ArcTanXY := (PI/2) - Math.arctan2(DiffX, DiffY);
- end;
- end;
- PlayerRotation := ArcTanXY;
- MoveStart := true;
- ImgFlying := true;
- end;
- procedure TStateMain.ResetPlane(IsDblClick: Boolean);
- begin
- FirstClick := 0;
- ImgFlying := false;
- MoveStart := false;
- MoveStop := false;
- ImagePlayer.Rotation := 0;
- if IsDblClick then
- ImgSpeed := Vector2(700, 700)
- else
- ImgSpeed := Vector2(300, 300);
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement