Skip to content

luizppa/third-person-camera

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

58 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐ŸŽฅ Unity Third Person Camera

Third person camera behaviour for Unity. Concept was inspired by Unity's Cinemachine, the code is entirely mine with exception for for the ShowIfAttribute and ShowIfAttributeDrawer scripts. Although inspired by, it is much more simple (and depending on your necessities, much more limited) than the original Cinemachine scripts. It gives you, however, the possibility to align the normal of the camera plane with the target's normal.

๐Ÿ‘พ Installation

Paste the ThirdPersonCamera.cs and ShowIfAttribute.cs script into your project.

Paste the ShowIfAttributeDrawer.cs script into any folder named "Editor" in your project.

Attach the ThirdPersonCamera script to your camera and tune the attributes to your needs. Bind the Game Object which the camera should follow to the follow property. Bind the Game Object which the camera should look at to the lookAt property.

Note: the camera should not be nested in the lookAt nor the follow game objects.

๐Ÿงฉ Features

Most features are similar to the original Cinemachine scripts. The only difference is that the camera plane may be aligned with the target's normal. Basic settings can be configured in the inspector to your liking.

๐Ÿช Orbits

The camera uses three different orbits to position itself around the follow target. Each orbit can be configured regarding his height, radius and color in the editor through the inspector.

The height is relative to the transform of the follow target.

The camera circles around the target with a radius that is equal to the quadratic interpolation of the surrounding rings's radius and its height is clamped by the top and bottom rings.

The resulting rings are shown in the editor like so:

Rings shown in editor

๐Ÿ“Œ Positioning

The position of the camera can be further adjusted with the following attributes:

Attribute Type Default value Description
lockHeight boolean false If set to true, the camera will not move vertically
lockTranslation boolean false If set to true, the camera will not rotate around it's follow target
avoidClipping boolean true Defines whether the camera should avoid clipping into objects, see the example below
clipDistance float 5 The maximum distance of a collider to the camera's follow target to be considered as clipping
clippingOffset float 0 The distance between the camera and any clipping objects if avoidClipping is enabled
horizontalTilt float 0 The horizontal angle offset for the camera view
horizontalOffset float 0 The horizontal offset on the camera position in unities
verticalTilt float 0 The vertical angle offset for the camera view
verticalOffset float 0 The vertical offset on the camera position in unities
useTargetNormal boolean true If enabled, the camera will align its normal with the follow target's normal, see the example below

If avoidClipping is enabled, the camera will try to avoid clipping into the ground and other surrounding objects (as long as they have a collider) by moving closer to the follow target. An offset can be applied to move the camera further away from the clipping objects, which can help avoid seeing through objects, however it currently may lead to some glitches regarding the camera position. The following gif illustrates this behavior (true on the left, false on the right).

No camera clipping gif Camera clipping gif

If useTargetNormal is enabled, the camera will align it's normal to the follow target's normal, otherwise it will use Vector3.up, defined by (0, 1, 0), as shown below (true on the left, false on the right).

Using target normal Using world normal

๐ŸŽฎ Controls

Attribute Type Default value Description
horizontalAxis string "Mouse X" Defines the input axis used for the horizontal movement of the camera
horizontalSensitivity float 1 The multiplier for the horizontal input value
invertX boolean false Defines whether the horizontal movement should be inverted
verticalAxis string "Mouse Y" Defines the input axis used for the vertical movement of the camera
verticalSensitivity float 0.8 The multiplier for the vertical input value
invertY boolean true Defines whether the vertical movement should be inverted

โœจ Effects

A few motion effects are available out of the box. Each can be enabled/disabled and configured as you wish. The effects and configurations available are:

Although I described this section as available effects (plural), as it is, there are only two effects available, zoom out on motion and motion shake. I expect to implement more in the future, for the time being, feel free to contribute!


Zoom out on motion

Note: This effect depends on the target having a rigidbody attached to it.

The zoom out on motion effect is a simple way to make the camera zoom out on the target when the target is moving at certain speeds. This can help giving a sense of depth and speed to the motion. The configurations for this effect are:

Attribute Type Default value Description
startSpeed float 10 At which speed (in m/s) should the camera begin to zoom out
capSpeed float 15 At which speed (in m/s) should the camera stop to zoom out
startDistanceRatio float 0 How much should the camera zoom out (in %) when it starts to move
capDistanceRatio float 0.3 How much should the camera zoom out (in %) when it stops to move

The effect is done by increasing the camera and the target by a certain amount, this amount is determined by a linear interpolation of the zoomStartDistanceRatio and zoomCapDistanceRatio with a value equals to the inverse linear interpolation of the target's speed between zoomOutStartSpeed and zoomCapDistanceRatio.

For example, suppose we are using the default configurations. If the target is below 10 m/s, the camera will be at it's default distance, as the target increases it's speed beyond 10 m/s, the camera will start to zoom out. At a speed of 12.5 m/s, the inverse linear interpolation value will be 0.5, so the camera will zoom out by a value equals the linear interpolation of the speed at 0, that is, 0.3, the equation is:

(v * startDistanceRatio) + ((1 - v) * capDistanceRatio)

with v = 0.5. The zoom out amount is represented by the percentage of the default distance that will be added, therefore the camera will zoom out by 15% of the default distance (115% in total). Past the cap speed of 15 m/s, the camera will always be zoomed out by 30%.

The result can be seen in the following gif:

Zoom out on motion gif

Motion shake

Note: This effect depends on the target having a rigidbody attached to it.

The motion shake effect is a way to make the motion feel more natural and dynamic. The configurations for this effect are:

Attribute Type Default value Description
startSpeed float 10 At which speed (in m/s) should the camera begin to shake
capSpeed float 15 Until which speed (in m/s) should the camera increase the shake intensity
verticalStartIntensity float 0.02 How much should the camera move vertically as it starts to shake
verticalCapIntensity float 0.05 How much should the camera move vertically at most as it shakes
verticalSpeed float 15 How fast should the camera move vertically as it shakes
verticalPhase float 0.5 At which point of the cycle should the camera start (vertically)
horizontalStartIntensity float 0.03 How much should the camera move horizontally as it starts to shake
horizontalCapIntensity float 0.07 How much should the camera move horizontally at most as it shakes
horizontalSpeed float 7.5 How fast should the camera move horizontally as it shakes
horizontalPhase float 0 At which point of the cycle should the camera start (horizontally)

This effect is done by using a sinusoidal wave to move the camera vertically and horizontally. The vertical wave is a sinusoidal wave with a frequency of verticalSpeed and a phase of verticalPhase. The horizontal wave is a sinusoidal wave with a frequency of horizontalSpeed and a phase of horizontalPhase.

The phase must be between 0 and 2 (the reason being that it is going to be multiplied by PI and then applied to the sine function, as the sine wave has a period of 2PI, any value out of this range would be redundant).

The result can be seen in the following gif:

Zoom out on motion gif

๐Ÿž Contributing

Bug reports, feature requests, suggestions (please create an issue) and pull requests are welcome.