- If you don't need the convenience of being able to easily switch a player's controlled character or have the character entity be destroyed without destroying player data, you could choose to make the Player and the Character be the same entity. This would remove the need to have one ghost for each. If you do this, you may also want to tweak the Player systems to use components on the same entity rather than getting those components via lookups.
- If the character will only ever rotate around the world up axis, you can synchronize only the Y euler angle of the character rotation instead of the full quaternion. For this to work, you'll have to add a prediction system that updates in the
PredictedSimulationSystemGroup
beforePredictedFixedStepSimulationSystemGroup
, and reconstructs the character'sLocalTransform.Rotation
from that Y euler angle before any other system tries to use the rotation (you might have to make sure this updates before theOrbitCameraPrePhysicsSystem
as well if using the third-person character). - Depending on whether or not you will need access to some of the synchronized character/player/camera data on interpolated clients, you could select the
Only send when "Known Predicted"
as theSend Optimization
for the various synchronized components in theGhost Authoring Inspection Component
of character/player/camera prefabs. - If your character does not need the concept of a "Parent Entity" (does not need to stand on moving platforms, etc...), you can remove ghost fields for the
ParentEntity
,ParentLocalAnchorPoint
, andParentVelocity
fields of theKinematicCharacterBody
component.- Even if you do still need to support character parent entities, additional optimizations are possible:
KinematicCharacterBody.ParentVelocity
synchronization can be omitted if you make sure you only ever de-ground the character from its parent entity (or destroy the parent entity while the character is parented to it) between theUpdate_ParentMovement
andUpdate_MovingPlatformDetection
steps of the character update.KinematicCharacterBody.ParentLocalAnchorPoint
synchronization can be omitted if you take care of setting it manually & deterministically after theUpdate_Initialize
and before theUpdate_ParentMovement
steps of the character update. For full precision, you would have to find the point of contact between the character collider and the parent entity using a physics query, and calculate the contact point's local position compared to the parent entity. Remember that you cannot use the character's ground hit for this, because this would be happening before the character has detected grounding. Otherwise, if you don't mind a precision/quality loss for the logic that makes the character follow a rotating moving platform, you can also set it to the local position of the bottom of the character compared to the parent entity. Since we must choose between a performance penalty (find contact point with a physics query), a quality penalty (using character capsule bottom instead of true contact point), or a bandwidth penalty (synchronizingKinematicCharacterBody.ParentLocalAnchorPoint
) in a netcode context, this isn't done by default.- You can limit what is synchronized on moving patform ghosts based on what you can assume in terms of how moving platforms move in your game. For example, if you know that your moving platforms will only ever move their position but not their rotation, you can only synchronize positions rather that full transforms.
- Even if you do still need to support character parent entities, additional optimizations are possible:
- If nothing in your game's simulation will need to rely on your character camera's position or distance, you may remove the ghost field attribute from
OrbitCamera.TargetDistance
, and move all of the camera distance/position handling code to the (non-predicted)OrbitCameraLateUpdateSystem
, beforeorbitCamera.SmoothedTargetDistance
is calculated. - You could avoid making the orbit camera prefab a ghost completely, if you make your character components and systems responsible for calculating and storing a "camera rotation". Then, owning clients would simply spawn a local prefab for the camera whenever their character is spawned by the server, and that prefab would always be setting its rotation to that calculated "camera rotation" stored in the character components. Instead of using the rotation of the camera entity in order to determine where the character should move or rotate to, you would be using this stored "camera rotation" on the character.
- If the character will only ever rotate around the world up axis, and the camera doesn't have to follow the change in the character's up direction, you could replace the camera's
float3 PlanarForward
ghost field with a simplefloat YawAngle
, and make camera yaw calculations based on this. This would require less bandwidth to synchronize.