So the camera behaviour in the Code Third Person is as simple as it looks. It is a basic solution that makes decent prototype third person camera, but is not good enough for a finished product. The SpringArmComponent does most of the heavy lifting here, so lets examine it to see if we would be better off extending it or creating our own class that has similar behaviours. Extending the class will mean that we do not need to duplicate code, but rewriting it provides more freedom.
I'll start with a paraphrased quotation from John Nesky's talk "50 Camera Mistakes" that applies to our topic today;
"It is a mistake to push the camera away from an obstacle while the player is trying to swing the camera towards it - conflicts between ideal camera collision avoidance and player intent must favour player intent."
The current SpringArmComponent is not ideal because the player may see something like this if they try to walk up to wall and then look away from it:
This goes against player intent because they are moving the camera to see away from the wall, so they can move safely in that direction but end up obscuring gameplay because the camera is avoiding collision.
So what does the SpringArmComponent do? It shortens, bring the camera closer to the player when it collides with an object. This may be useful in some cases, however, there are many exceptions that we will want to handle - including the one above. Let's take a look at the header file to see what variables we are working with here (grouped by all-caps titles):
SPRING ARM
(a)
/** Natural length of the spring arm when there are no collisions */
float TargetArmLength;
(b)
/** offset at end of spring arm; use this instead of the relative offset of the attached component to ensure the line trace works as desired */
FVector SocketOffset;
(c)
/** Offset at start of spring, applied in world space. Use this if you want a world-space offset from the parent component instead of the usual relative-space offset. */
FVector TargetOffset;
PROBE
(d)
/** How big should the query probe sphere be (in unreal units) */
float ProbeSize;
(e)
/** Collision channel of the query probe (defaults to ECC_Camera) */
TEnumAsByte<ECollisionChannel> ProbeChannel;
(f)
/** If true, do a collision test using ProbeChannel and ProbeSize to prevent camera clipping into level. */
uint32 bDoCollisionTest:1;
INHERITANCE
(g)
/** If this component is placed on a pawn, should it use the view rotation of the pawn where possible? */
uint32 bUseControllerViewRotation:1;
(h)
/** Should we inherit pitch from parent component. Does nothing if using Absolute Rotation. */
uint32 bInheritPitch : 1;
(i)
/** Should we inherit yaw from parent component. Does nothing if using Absolute Rotation. */
uint32 bInheritYaw : 1;
(j)
/** Should we inherit roll from parent component. Does nothing if using Absolute Rotation. */
uint32 bInheritRoll : 1;
LAG
(k)
/** If true, camera lags behind target position to smooth its movement */
uint32 bEnableCameraLag : 1;
(l)
/** If true, camera lags behind target position to smooth its movement */
uint32 bEnableCameraRotationLag : 1;
(m)
/** If bEnableCameraLag is true, controls how quickly camera reaches target position */
float CameraLagSpeed;
(n)
/** If bEnableCameraLag is true, controls how quickly camera reaches target position */
float CameraRotationLagSpeed;
(o)
/** Temporary variable when using camera lag, to record previous camera position */
FVector PreviousDesiredLoc;
(p)
/** Temporary variable for lagging camera rotation, for previous rotation */
FRotator PreviousDesiredRot;
Here is a comment by Jeff Verba on a feature request regarding SpringArmCompenents in March:
"From what I've experienced so far, all other object collision is built around identifying what other types of objects they interact with, as seen in any components default collision settings. You can easily setup what and how you want any object to react to with a few simple check boxes. From a workflow standpoint this is great, because for every custom component you can tell it exactly what types of objects you want it to react (or not react) to, and you only have to worry about setting it up or changing it in that one object class.
However, the Spring Arm Components actually work against that workflow, and can potentially cause issues... just because they work opposite everything else."
I also found two tutorials on implementing custom camera scripts, one of them creating a camera similar to Dark Souls'.
Check the two videos posted here to see how I got to the next step of planning for this camera script.