8. Player

For a full-featured game it is good to have a central player object, an instance of TPlayer, assigned to SceneManager.Player. This is used for various things:

  1. It will make camera automatically tied to the player, making it a first-person perspective game. (More camera approaches, like 3rd person view, will be available later — for now you have to manually code your camera if you want 3rd person view.)

  2. By default player is also a central enemy of all hostile creatures created using CastleCreatures unit. This is configurable (by overriding TCreature.Enemy).

Note that the player instance is not necessary for basic 3D navigation (the only thing really necessary is a camera, which is automatically created and placed in TCastleAbstractViewport.Camera). But for games, it's usually most comfortable to create and use it.

To load a Player do this:

uses ..., CastlePlayer;
var
  Player: TPlayer;
 
...
Player := TPlayer.Create(SceneManager);
SceneManager.Items.Add(Player);
SceneManager.Player := Player;

It's best to do this (assign SceneManager.Player) before SceneManager.LoadLevel, this way Player.Camera is automatically configured as SceneManager.Camera and it follows level's properties like PreferredHeight (from level's NavigationInfo.avatarSize).

3D models relative to player

Player is a descendant of T3DList, which means that you can add additional 3D objects as it's children, like Player.Add(Some3DObject). These 3D objects will always be rendered relative to the player, so they will move along with the player. This is an easy way to add 3D weapon models and similar things to your display. Although, for weapons, we actually handle it automatically for you, using TPlayer.EquippedWeapon model. But you can also add/remove additional 3D objects this way (e.g. a 3D torch that is held by the player).

As an additional feature, all 3D objects that are children of player will be rendered on top of other 3D world. This means that even if you 3D weapon model is large (like a long sword pointing out from camera), it will never go "inside the wall". You can turn this feature on/off by TPlayer.RenderOnTop property.

Aside from special TPlayer.RenderOnTop behavior, the 3D objects that are children of player are rendered and processed just like all other 3D stuff. For example, they can be animated (by using TCastlePrecalculatedAnimation or by using TCastleScene with TCastleScene.ProcessEvents := true).

Note that the player 3D objects do not make the player collision sphere (aka camera radius) larger. If you want to make the collision sphere larger, you can do it by placing a NavigationInfo node in a level 3D file, and adjusting the 1st item of avatarSize field — it determines the camera radius. See examples/fps_game/data/example_level/example_level_final.x3dv for an example VRML/X3D configuring the player.

Alternative method: There is an alternative way to place things relative to player view: use X3D ProximitySensor node. See demo_models/sensors_environmental/follow_camera_by_proximity_sensor.x3dv in our demo VRML/X3D models for a simple example how to code it in X3D. This allows you to place the 3D things that are relative to player inside a larger X3D file, together e.g. with normal level geometry (which may be an advantage or disadvantage, depending on what you want). The disadvantage is that we do not implement layers in X3D now, so such geometry will overlap with 3D level geometry (unless it will always fit within camera radius).

Load player configuration from XML file

Sometimes it's nice to give content creators a way to modify player behavior without touching the game source code. To allow this you can load player configuration by TPlayer.LoadFromFile method. See creating player data for a sample and documentation how player configuration file looks like.