Class TCastleThirdPersonNavigation
Unit
CastleThirdPersonNavigation
Declaration
type TCastleThirdPersonNavigation = class(TCastleMouseLookNavigation)
Description
3rd-person (with visible avatar) navigation.
Create an instance of this and put as TCastleViewport child to use.
Assign Avatar to automatically run proper animations on the avatar defined as a single TCastleScene. Alternatively, assign AvatarHierarchy, and leave Avatar as Nil
, and assign the OnAnimation event to do whatever is necessary to visualize proper animation of the avatar – this makes sense esp. if your avatar is composed from multiple TCastleScene instances. You have to assign at least one of Avatar or AvatarHierarchy, otherwise this navigation doesn't affect anything. and you only need to assign one of them for the navigation component to do the work.
Call Init once the parameters that determine initial camera location are all set.
Turn on MouseLook to allow user to move the mouse to orbit with the camera around the avatar. When AimAvatar is aaNone (default), it allows to look at the avatar easily from any side (e.g. you can then see avatar's face easily). When AimAvatar is aaHorizontal or aaFlying, rotating allows to point the avatar at the appropriate direction.
Using keys AWSD and arrows you can move and rotate the avatar, and the camera will follow.
Using the mouse wheel you can get closer / further to the avatar.
The implementation relies on the TCastleTransform.Direction and TCastleTransform.Up vectors being useful, i.e. they should point in the direction of the avatar and up. This works out-of-the-box if your model orientation follows glTF standard, up in +Y and direction in +Z (see DefaultOrientation, otUpYDirectionZ). Customize TCastleTransform.Orientation to make these vectors work if your avatar has non-standard orientation.
The navigation will honor physics if you have configured rigid body and collider components on the avatar. Otherwise, we use "old simple physics" documented on https://castle-engine.io/physics#_old_system_for_collisions_and_gravity . Right now, the "old simple physics" may be actually simpler to control. To make them work:
This is an example Start
view method implementation to setup the navigation:
procedure TViewMain.Start;
var
DebugAvatar: TDebugTransform;
begin
inherited;
ThirdPersonNavigation.MouseLook := true;
AvatarTransform.MiddleHeight := 0.9;
AvatarTransform.CollisionSphereRadius := 0.5;
AvatarTransform.GrowSpeed := 10.0;
AvatarTransform.FallSpeed := 10.0;
ThirdPersonNavigation.Init;
DebugAvatar := TDebugTransform.Create(FreeAtStop);
DebugAvatar.Parent := AvatarTransform;
DebugAvatar.Exists := true;
end;
See also the news post with demo movie about this component: https://castle-engine.io/wp/2020/06/29/third-person-navigation-with-avatar-component-in-castle-game-engine/
Hierarchy
Overview
Fields
Methods
Properties
Description
Fields
 |
nested const DefaultInitialHeightAboveTarget = 1.0; |
|
 |
nested const DefaultDistanceToAvatarTarget = 4.0; |
|
 |
nested const DefaultAvatarRotationSpeed = 10; |
|
 |
nested const DefaultAvatarTarget: TVector3 = (X: 0; Y: 2; Z: 0); |
|
 |
nested const DefaultCameraSpeed = 10; |
|
 |
nested const DefaultMoveSpeed = 1.0; |
|
 |
nested const DefaultCrouchSpeed = 0.5; |
|
 |
nested const DefaultRunSpeed = 2.0; |
|
 |
nested const DefaultJumpSpeed = 5.0; |
|
 |
nested const DefaultRotationSpeed = Pi * 150 / 180; |
|
 |
nested const DefaultCameraDistanceChangeSpeed = 1; |
|
 |
nested const DefaultMinDistanceToAvatarTarget = 0.5; |
|
 |
nested const DefaultMaxDistanceToAvatarTarget = 10; |
|
 |
nested const DefaultAnimationIdle = 'idle'; |
|
 |
nested const DefaultAnimationRotate = 'rotate'; |
|
 |
nested const DefaultAnimationWalk = 'walk'; |
|
 |
nested const DefaultAnimationRun = 'run'; |
|
 |
nested const DefaultAnimationCrouch = 'crouch'; |
|
 |
nested const DefaultAnimationCrouchIdle = 'crouch_idle'; |
|
 |
nested const DefaultAnimationCrouchRotate = 'crouch_rotate'; |
|
 |
nested const DefaultAnimationJump = 'jump'; |
|
 |
nested const DefaultAnimationFall = 'fall'; |
|
 |
nested const DefaultAirMovementControl = 0.5; |
|
 |
nested const DefaultAirRotationControl = 0.5; |
|
Methods
 |
procedure ProcessMouseLookDelta(const Delta: TVector2); override; |
|
 |
function Zoom(const Factor: Single): Boolean; override; |
|
 |
procedure SetAnimation(const AnimationNames: array of String); virtual; |
Make avatar play given animation.
The desired animation is specified as a list of strings, from the most preferred name of the animation to the least preferred. This allows to perform a "fallback" mechanism in case some animations are missing on the model. For example if AnimationCrouch is not available, we will use AnimationCrouchIdle instead, and if that is also not available we will use AnimationIdle. Some basic animations must still exist – if even AnimationIdle doesn't exist, we'll just show a warning.
The default implementation in TCastleThirdPersonNavigation changes Avatar.AutoAnimation method. It does nothing if Avatar is Nil .
Moreover the default implementation implements a "fallback" mechanism in case some animations are not available in the scene. This is checked using Avatar.HasAnimation.
To apply animations in custom way, either override this method, or assign event to OnAnimation. E.g. you can animate a hierarchy of scenes composed from MD3 pieces. When overriding this, you don't need to call inherited . If you override this to apply the animation to something else than Avatar, then it may even be reasonable to leave Avatar as Nil , and only set AvatarHierarchy.
The implementation of this method (after performing the "fallback" mechanism described above to find the real name on the AnimationName list) should check whether the object is not already playing the same animation. This is important to avoid unnecessary animation restarts.
|
 |
constructor Create(AOwner: TComponent); override; |
|
 |
destructor Destroy; override; |
|
 |
procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override; |
|
 |
procedure Init; |
Makes camera be positioned with respect to the current properties and avatar. Always call this explicitly once. Use this after setting properties like Avatar, AvatarHierarchy, DistanceToAvatarTarget, InitialHeightAboveTarget.
At design-time (in CGE editor), this is automatically called after changing relevant properties of this navigation.
|
 |
function Input_CameraCloser: TInputShortcut; deprecated 'use Input_ZoomIn'; |
Warning: this symbol is deprecated: use Input_ZoomIn |
 |
function Input_CameraFurther: TInputShortcut; deprecated 'use Input_ZoomOut'; |
Warning: this symbol is deprecated: use Input_ZoomOut |
Properties
 |
property AvatarTarget: TVector3 read FAvatarTarget write FAvatarTarget; |
Translation, from the avatar origin, to the "target" of the avatar where camera looks at. This is usually head, and this vector should just describe the height of head above the ground. By default this is DefaultAvatarTarget = (0, 2, 0).
|
 |
property ZoomEnabled default true; |
Zooming in this navigation mode makes camera move closer/further from avatar.
|
 |
property MouseLookHorizontalSensitivity; |
|
 |
property MouseLookVerticalSensitivity; |
|
 |
property InvertVerticalMouseLook; |
|
 |
property CameraFollows: Boolean read FCameraFollows write SetCameraFollows default true; |
Does camera follow the avatar, by default yes.
When this is False , camera remains unchanged by anything here (avatar movement/rotations, mouse look, even by calling Init). Some properties of this then are meaningless (e.g. DistanceToAvatarTarget).
However, all the inputs to control the avatar continue to work.
|
 |
property Avatar: TCastleScene read FAvatar write SetAvatar; |
Avatar scene, that is animated, moved and rotated when this navigation changes. This navigation component will just call Avatar.AutoAnimation := 'xxx' when necessary.
We will use animation names configured using properties like AnimationWalk, AnimationIdle and other `AnimationXxx`. By default they are just equal to simple names 'walk' , 'idle' and such, but you can change AnimationWalk, AnimationIdle if your model exposes different animation names.
When AvatarHierarchy is Nil , then Avatar is directly moved and rotated to move avatar.
Otherwise (when AvatarHierarchy is assigned), then AvatarHierarchy is moved, and Avatar should be inside AvatarHierarchy. In this case, the only purpose of Avatar is to let navigation automatically adjust animations. But you can leave Avatar unassigned, and override SetAnimation to do this.
This scene assigned here should be part of TCastleViewport.Items to make this navigation work, in particular when you call Init.
|
 |
property AvatarHierarchy: TCastleTransform read FAvatarHierarchy write SetAvatarHierarchy; |
Optional avatar hierarchy that is moved and rotated when this navigation changes. When this is Nil , we just move and rotate the Avatar. When this is non-nil, then we only move and rotate this AvatarHierarchy .
If AvatarHierarchy is non-nil, then it should contain Avatar (if it is assigned) as a child. AvatarHierarchy can even be equal to Avatar (it is equivalent to just leaving AvatarHierarchy as Nil ).
This object should be part of TCastleViewport.Items to make this navigation work, in particular when you call Init.
|
 |
property AvatarRotationSpeed: Single read FAvatarRotationSpeed write FAvatarRotationSpeed
default DefaultAvatarRotationSpeed; |
When AimAvatar, this is avatar's rotation speed (in radians per second). Should make avatar rotation "catch up" (with some delay after camera rotation.
|
 |
property CameraSpeed: Single read FCameraSpeed write FCameraSpeed
default DefaultCameraSpeed; |
Camera position tracks the desired position with given speed (in units per second). This makes camera adjust to avatar moving (because of input, or because of gravity or other external code) and to not being blocked by the collider.
|
 |
property AimAvatar: TAimAvatar read FAimAvatar write FAimAvatar default aaNone; |
If not aaNone then rotating the camera also rotates (with some delay) the avatar, to face the same direction as the camera. This allows to rotate the avatar with mouse look (which is comfortable), on the other hand it takes away some flexibility, e.g. you cannot look at avatar's face for a long time anymore.
|
 |
property ImmediatelyFixBlockedCamera: Boolean read FImmediatelyFixBlockedCamera write FImmediatelyFixBlockedCamera
default false; |
Immediately (not with delay of CameraSpeed) update camera to never block avatar view by a wall, enemy etc. When it is True , we avoid seeing an invalid geometry (e.g. from the wrong side of the wall or inside a creature) ever, but in exchange the camera sometimes has to be adjusted very abrtupty (testcase: third_person_navigation demo, stand in the middle of moving enemies, and look around).
|
 |
property DistanceToAvatarTarget: Single read FDistanceToAvatarTarget write SetDistanceToAvatarTarget
default DefaultDistanceToAvatarTarget; |
Preferred distance from camera to the avatar target (head). User can change it with Input_ZoomIn, Input_ZoomOut if you set these inputs to some key/mouse button/mouse wheel.
|
 |
property MinDistanceToAvatarTarget: Single read FMinDistanceToAvatarTarget write FMinDistanceToAvatarTarget
default DefaultMinDistanceToAvatarTarget; |
Limit of the distance to avatar, used when changing DistanceToAvatarTarget, and also when deciding how to adjust camera to avoid collisions.
|
 |
property MoveSpeed: Single read FMoveSpeed write FMoveSpeed
default DefaultMoveSpeed; |
Speed of movement by keys.
|
 |
property CrouchSpeed: Single read FCrouchSpeed write FCrouchSpeed
default DefaultCrouchSpeed; |
Speed of movement by keys, when crouching.
|
 |
property RunSpeed: Single read FRunSpeed write FRunSpeed
default DefaultRunSpeed; |
Speed of movement by keys, when running.
|
 |
property JumpSpeed: Single read FJumpSpeed write FJumpSpeed
default DefaultJumpSpeed; |
Speed of jump by keys.
|
 |
property RotationSpeed: Single read FRotationSpeed write FRotationSpeed
default DefaultRotationSpeed; |
Speed of rotating by keys, in radians per second.
|
 |
property AirMovementControl: Single read FAirMovementControl write FAirMovementControl
default DefaultAirMovementControl; |
Should we have control on the avatar movement in the air. Must be >= 0.
0 -> no control in the air
1 -> full control in the air, just like on the ground
between 0 and 1 -> limited control, smoothly changes between no control and full control
above 1 -> in the air you move even faster than on the ground
|
 |
property AirRotationControl: Single read FAirRotationControl write FAirRotationControl
default DefaultAirRotationControl; |
Should we have control on the avatar rotation in the air.
0 -> no control in the air
1 -> full control in the air, just like on the ground
between 0 and 1 -> limited control, smoothly changes between no control and full control
above 1 -> in the air you rotate even faster than on the ground
|
 |
property AnimationIdle: String read FAnimationIdle write FAnimationIdle stored AnimationIdleStored nodefault; |
Animation when character is not moving, not rotating and not crouching. Default 'idle'.
|
 |
property AnimationRotate: String read FAnimationRotate write FAnimationRotate stored AnimationRotateStored nodefault; |
Animation when character is rotating, but otherwise remains in place (not moving) and it is not crouching. Default 'rotate'.
|
 |
property AnimationWalk: String read FAnimationWalk write FAnimationWalk stored AnimationWalkStored nodefault; |
Animation when character is walking. Default 'walk'.
|
 |
property AnimationRun: String read FAnimationRun write FAnimationRun stored AnimationRunStored nodefault; |
Animation when character is running. Default 'run'.
|
 |
property AnimationCrouch: String read FAnimationCrouch write FAnimationCrouch stored AnimationCrouchStored nodefault; |
Animation when character is moving while crouching. Default 'crouch'.
|
 |
property AnimationCrouchIdle: String read FAnimationCrouchIdle write FAnimationCrouchIdle stored AnimationCrouchIdleStored nodefault; |
Animation when character is crouching (Input_Crouch is pressed) but not moving or rotating. Default 'crouch_idle'.
|
 |
property AnimationCrouchRotate: String read FAnimationCrouchRotate write FAnimationCrouchRotate stored AnimationCrouchRotateStored nodefault; |
Animation when character is crouching (Input_Crouch is pressed) and rotating, but not moving. Default 'crouch_rotate'.
|
 |
property AnimationJump: String read FAnimationJump write FAnimationJump stored AnimationJumpStored nodefault; |
Animation when character is jumping (Input_Jump is pressed). Default 'jump'.
|
 |
property AnimationFall: String read FAnimationFall write FAnimationFall stored AnimationFallStored nodefault; |
Animation when character is fall. Default 'fall'.
|
 |
property Radius; |
Camera will keep at least this distance from walls.
|
 |
property OnAnimation: TCastleThirdPersonNavigationAnimationEvent
read FOnAnimation write FOnAnimation; |
Update the animation displayed by the current avatar.
See SetAnimation for details.
Assigning event to this makes sense if your avatar is composed from multiple TCastleScene instances. This may be called very often, to update animation every frame, so do call SubScene.PlayAnimation from here. Rather, set SubScene.AutoAnimation to not restart the animation if it's already running. For example:
procedure TViewMain.NavigationSetAnimation(const Sender: TCastleThirdPersonNavigation;
const AnimationNames: array of String);
begin
if AnimationNames[0] = 'idle' then
begin
SceneLegs.AutoAnimation := 'legs_idle';
SceneTorso.AutoAnimation := 'torso_idle';
end else
begin
SceneLegs.AutoAnimation := 'legs_walk';
SceneTorso.AutoAnimation := 'torso_walk';
end
|
 |
property AvatarTargetPersistent: TCastleVector3Persistent read FAvatarTargetPersistent ; |
AvatarTarget that can be visually edited in Castle Game Engine Editor, Lazarus and Delphi. Normal user code does not need to deal with this, instead read or write AvatarTarget directly.
See also
- AvatarTarget
- Translation, from the avatar origin, to the "target" of the avatar where camera looks at.
|
Generated by PasDoc 0.16.0.