Below are four scripts that will help you make the camcorder effect, but to add the GUI like the REC thing, isn’t in here.
Once you are done adding the below scripts as I’ve written them, on your camera object, input the Inspector values as shown in the screenshot:
The link takes you to the image of the screenshot I uploaded online.
Then follow these instructions with these scripts:
First, have a script called “AbstractTargetFollower” and put it in your scripts folder. Do not attach it to any object. This is a parent type script. The code is as follows:
using UnityEngine;
public abstract class AbstractTargetFollower : MonoBehaviour
{
public enum UpdateType // The available methods of updating are:
{
Auto, // Let the script decide how to update
FixedUpdate, // Update in FixedUpdate (for tracking rigidbodies).
LateUpdate, // Update in LateUpdate. (for tracking objects that are moved in Update)
}
[SerializeField] protected Transform target; // The target object to follow
[SerializeField] private bool autoTargetPlayer = true; // Whether the rig should automatically target the player.
[SerializeField] private UpdateType updateType; // stores the selected update type
virtual protected void Start() {
// if auto targeting is used, find the object tagged "Player"
// any class inheriting from this should call base.Start() to perform this action!
if (autoTargetPlayer) {
FindAndTargetPlayer();
}
}
void FixedUpdate() {
// we update from here if updatetype is set to Fixed, or in auto mode,
// if the target has a rigidbody, and isn't kinematic.
if (autoTargetPlayer && (target == null || !target.gameObject.activeSelf)) {
FindAndTargetPlayer();
}
if (updateType == UpdateType.FixedUpdate || updateType == UpdateType.Auto && target != null && (target.rigidbody != null && !target.rigidbody.isKinematic)) {
FollowTarget(Time.deltaTime);
}
}
void LateUpdate() {
// we update from here if updatetype is set to Late, or in auto mode,
// if the target does not have a rigidbody, or - does have a rigidbody but is set to kinematic.
if (autoTargetPlayer && (target == null || !target.gameObject.activeSelf)) {
FindAndTargetPlayer();
}
if (updateType == UpdateType.LateUpdate || updateType == UpdateType.Auto && target != null && (target.rigidbody == null || target.rigidbody.isKinematic)) {
FollowTarget(Time.deltaTime);
}
}
protected abstract void FollowTarget(float deltaTime);
public void FindAndTargetPlayer() {
// only target if we don't already have a target
if (target == null) {
// auto target an object tagged player, if no target has been assigned
var targetObj = GameObject.FindGameObjectWithTag("Player");
if (targetObj) {
SetTarget(targetObj.transform);
}
}
}
public virtual void SetTarget (Transform newTransform) {
target = newTransform;
}
public Transform Target { get { return this.target; } }
}
Then, have a script called “LookatTarget”. The code is as follows:
using UnityEngine;
using System.Collections;
public class LookatTarget : AbstractTargetFollower {
// A simple script to make one object look at another,
// but with optional constraints which operate relative to
// this gameobject's initial rotation.
// Only rotates around local X and Y.
// Works in local coordinates, so if this object is parented
// to another moving gameobject, its local constraints will
// operate correctly
// (Think: looking out the side window of a car, or a gun turret
// on a moving spaceship with a limited angular range)
// to have no constraints on an axis, set the rotationRange greater than 360.
[SerializeField] Vector2 rotationRange;
[SerializeField] float followSpeed = 1;
Vector3 followAngles;
protected Vector3 followVelocity;
Quaternion originalRotation;
// Use this for initialization
protected override void Start () {
base.Start();
originalRotation = transform.localRotation;
}
protected override void FollowTarget (float deltaTime)
{
// we make initial calculations from the original local rotation
transform.localRotation = originalRotation;
// tackle rotation around Y first
Vector3 localTarget = transform.InverseTransformPoint(target.position);
float yAngle = Mathf.Atan2( localTarget.x, localTarget.z) * Mathf.Rad2Deg;
yAngle = Mathf.Clamp ( yAngle, -rotationRange.y * 0.5f, rotationRange.y * 0.5f );
transform.localRotation = originalRotation * Quaternion.Euler( 0, yAngle, 0 );
// then recalculate new local target position for rotation around X
localTarget = transform.InverseTransformPoint(target.position);
float xAngle = Mathf.Atan2( localTarget.y, localTarget.z) * Mathf.Rad2Deg;
xAngle = Mathf.Clamp ( xAngle, -rotationRange.x * 0.5f, rotationRange.x * 0.5f );
var targetAngles = new Vector3( followAngles.x + Mathf.DeltaAngle( followAngles.x, xAngle ), followAngles.y + Mathf.DeltaAngle( followAngles.y, yAngle ) );
// smoothly interpolate the current angles to the target angles
followAngles = Vector3.SmoothDamp( followAngles, targetAngles, ref followVelocity, followSpeed );
// and update the gameobject itself
transform.localRotation = originalRotation * Quaternion.Euler( -followAngles.x, followAngles.y, 0 );
}
}
Then have a script called “HandHeldCam”. This is the script that you will actually place on your camera. The code is as follows:
using UnityEngine;
using System.Collections;
public class HandHeldCam : LookatTarget {
[SerializeField] float swaySpeed = .5f;
[SerializeField] float baseSwayAmount = .5f;
[SerializeField] float trackingSwayAmount = .5f;
[Range(-1,1)][SerializeField] float trackingBias = 0;
// Use this for initialization
protected override void Start () {
base.Start();
}
protected override void FollowTarget (float deltaTime)
{
base.FollowTarget(deltaTime);
float bx = (Mathf.PerlinNoise(0,Time.time*swaySpeed)-0.5f);
float by = (Mathf.PerlinNoise(0,(Time.time*swaySpeed)+100))-0.5f;
bx *= baseSwayAmount;
by *= baseSwayAmount;
float tx = (Mathf.PerlinNoise(0,Time.time*swaySpeed)-0.5f)+trackingBias;
float ty = ((Mathf.PerlinNoise(0,(Time.time*swaySpeed)+100))-0.5f)+trackingBias;
tx *= -trackingSwayAmount * followVelocity.x;
ty *= trackingSwayAmount * followVelocity.y;
transform.Rotate( bx+tx, by+ty, 0 );
}
}
Have one last script called “TargetFieldOfView” and attach it to your camera as well. The code is as follows:
using UnityEngine;
using System.Collections;
public class TargetFieldOfView : AbstractTargetFollower {
// This script is primarily designed to be used with the "LookAtTarget" script to enable a
// CCTV style camera looking at a target to also adjust its field of view (zoom) to fit the
// target (so that it zooms in as the target becomes further away).
// When used with a follow cam, it will automatically use the same target.
[SerializeField] float fovAdjustTime = 1; // the time taken to adjust the current FOV to the desired target FOV amount.
[SerializeField] float zoomAmountMultiplier = 2; // a multiplier for the FOV amount. The default of 2 makes the field of view twice as wide as required to fit the target.
[SerializeField] bool includeEffectsInSize = false; // changing this only takes effect on startup, or when new target is assigned.
float boundSize;
float fovAdjustVelocity;
Camera cam;
Transform lastTarget;
// Use this for initialization
protected override void Start ()
{
base.Start ();
boundSize = MaxBoundsExtent( target, includeEffectsInSize );
// get a reference to the actual camera component:
cam = GetComponentInChildren<Camera>();
}
protected override void FollowTarget (float deltaTime)
{
// calculate the correct field of view to fit the bounds size at the current distance
float dist = (target.position-transform.position).magnitude;
float requiredFOV = Mathf.Atan2(boundSize,dist) * Mathf.Rad2Deg * zoomAmountMultiplier;
cam.fieldOfView = Mathf.SmoothDamp(cam.fieldOfView, requiredFOV, ref fovAdjustVelocity, fovAdjustTime);
}
public override void SetTarget (Transform newTransform)
{
base.SetTarget (newTransform);
boundSize = MaxBoundsExtent( newTransform, includeEffectsInSize );
}
public static float MaxBoundsExtent(Transform obj, bool includeEffects)
{
// get the maximum bounds extent of object, including all child renderers,
// but excluding particles and trails, for FOV zooming effect.
Renderer[] renderers = obj.GetComponentsInChildren<Renderer>();
Bounds bounds = new Bounds();
bool initBounds = false;
foreach(Renderer r in renderers)
{
if (!((r is TrailRenderer) || (r is ParticleRenderer) || (r is ParticleSystemRenderer)))
{
if (!initBounds)
{
initBounds = true;
bounds = r.bounds;
} else {
bounds.Encapsulate(r.bounds);
}
}
}
float max = Mathf.Max(bounds.extents.x, bounds.extents.y, bounds.extents.z);
return max;
}
}
There are many variables to tweak the perlin noise head bobbing etc. All the scripts came from Unity’s own Sample Assets Beta.