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)
- const
- { Rotation speed of the plane }
- RotFactor: Single = 0.03;
- private
- HasLastMousePressPosition: Boolean;
- LastMousePressPosition: TVector2;
- LastMousePressTime: TTimerResult;
- { Components designed using CGE editor, loaded from gamestatemain.castle-user-interface. }
- 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 GetRadians(PlayerPos, PlayerTarget: TVector2);
- function Press(const Event: TInputPressRelease): Boolean; override;
- //procedure ExecuteAction(FactorX, FactorY: Single);
- end;
- var
- StateMain: TStateMain;
- implementation
- uses SysUtils;
- const
- MaxDistanceForDoubleClick = 10;
- MaxTimeForDoubleClick = 0.5;
- { TStateMain ----------------------------------------------------------------- }
- constructor TStateMain.Create(AOwner: TComponent);
- begin
- inherited;
- DesignUrl := 'castle-data:/gamestatemain.castle-user-interface';
- end;
- procedure TStateMain.Start;
- begin
- inherited;
- HasLastMousePressPosition := false;
- { 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;
- ImgSpeed := Vector2(300, 300);
- end;
- procedure TStateMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
- begin
- inherited;
- { This virtual method is executed every frame.}
- LabelFps.Caption := 'FPS: ' + Container.Fps.ToString;
- LabelRot.Caption := 'Plane Rotation: ' + ImagePlayer.Rotation.ToString + ' (rad)';
- if HasLastMousePressPosition and
- (LastMousePressTime.ElapsedTime >= MaxTimeForDoubleClick) then
- begin
- // Single-click handled, so forget about previous press event and do not store this press event.
- HasLastMousePressPosition := false;
- 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
- begin
- ImagePlayer.Rotation := 0;
- ImgSpeed := Vector2(300, 300);
- ImgFlying := false;
- MoveStop := false;
- end;
- end;
- function TStateMain.Press(const Event: TInputPressRelease): Boolean;
- var
- FactorX: Single;
- FactorY: Single;
- LengthX, LengthY: Single;
- 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
- ImgTarget := ImagePlayer.Parent.ContainerToLocalPosition(Event.Position);
- if HasLastMousePressPosition and
- (PointsDistance(Event.Position, LastMousePressPosition) < MaxDistanceForDoubleClick) and
- (LastMousePressTime.ElapsedTime < MaxTimeForDoubleClick) then
- begin
- // Double-click handled, so forget about previous press event and do not store this press event.
- FactorX := 700;
- FactorY := 700;
- { 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.X:= FactorX;
- ImgSpeed.Y := FactorY * LengthY / LengthX;
- end
- else
- begin
- ImgSpeed.Y := FactorY;
- ImgSpeed.X := FactorX * LengthX / LengthY;
- end;
- GetRadians(PlayerPosition, imgTarget);
- ImgFlying := true;
- HasLastMousePressPosition := false;
- end else
- begin
- // Make single-click, if we have an unprocessed press event that wasn't double-click (because of too far distance).
- if HasLastMousePressPosition then
- begin
- FactorX := 300;
- FactorY := 300;
- { 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.X:= FactorX;
- ImgSpeed.Y := FactorY * LengthY / LengthX;
- end
- else
- begin
- ImgSpeed.Y := FactorY;
- ImgSpeed.X := FactorX * LengthX / LengthY;
- end;
- GetRadians(PlayerPosition, imgTarget);
- ImgFlying := true;
- end;
- HasLastMousePressPosition := true;
- LastMousePressPosition := Event.Position;
- LastMousePressTime := Timer;
- end;
- Exit(true); // event was handled
- end;
- 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;
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement