You can use any control you like with ORK Framework – you just need to let ORK know.

ORK Framework’s built in controls are a good starting point to get you going, but most likely you’ll want to add your own control scripts for player or camera control. Since ORK needs to enable/disable control at certain points in a game (e.g. during a cut-scene event or a battle without direct player control), you need to set up the name of your control scripts on the player or camera, to allow ORK accessing it.

The game controls are set up in the ORK Framework editor in Base/Controls > Game Controls. To set up the player or camera controls for using custom controls, change the following settings.

  • Control Type
    Select None.

Now, click on Add Custom Control in the Custom Control settings to add information about your custom control script.

  • Blocked By
    Select if the control script is blocked with the Player or Camera controls.
  • Placed On
    Select if the control script is placed on the Player or Camera.
  • Behaviour Name
    Set it to the name of your script.
    E.g. your script’s name is CustomControl.cs (and the name of the class is CustomControl), you need to set the name to CustomControl.
  • Add Component
    If your control script is already added to your player/camera, disable this setting.
    If you want ORK Framework to automatically add the script to the player/camera, enable this setting.

And that’s it – there are additional settings for control scripts that are placed on child objects of the player/camera, and you can set initial fields and parameters of the script.

howto_custom_controls1

Wrapper Components

In case your control component needs some kind of special treatment or setup that doesn’t work well with ORK’s custom control setup, consider writing a wrapper component.

A wrapper component works as a bridge between ORK and your custom control. You’d define the wrapper component in ORK’s custom control and manage blocking and unblocking the custom control in your wrapper component.

When ORK blocks a control, the component will be disabled, so you’ll use the OnDisable function of the component:

void OnDisable()
{
	// called when the control is blocked
}

When ORK unblocks a control, the component will be enabled, so you’ll use the OnEnable function of the component:

void OnEnable()
{
	// called when the control is unblocked
}

You can also add these functions to your actual custom control component and skip using a wrapper component.

Example: OOTII Camera Controller

Here’s an example wrapper component for OOTII Camera Controller. This wrapper will forward control blocks and supports Camera Control Target changes and transitions, you can download it here:

Download

In case transitions are not working, make sure the wrapper component is executed after the actual camera control component by adding it to the Script Execution Order. You can do this in Unity’s Project Settings, add the ORKCameraControlWrapper component with a time of 100 (or more).

The wrapper component has settings for resetting the camera’s position and rotation after restoring camera control (to the position/rotation it had when the camera control was blocked). This can be done using local or world space. For OOTII, the camera is usually a child object of the camera controller – the default setup is to restoring position/rotation in local space.

Setup

To set it up in ORK Framework, go to Base/Control > Game Controls in the ORK editor.

Camera Controls

Disable built-in camera controls.

  • Camera Control Type
    Select None.

Custom Controls

Click on Add Custom Control and change the following settings.

  • Blocked By
    Select Camera.
  • Placed On
    Select Camera.
  • Behaviour Name
    Set to ORKCameraControlWrapper.
  • From Root
    Enable this setting.
  • On Child Object
    Enable this setting.
  • Add Component
    Enable this setting.

And that’s it – don’t forget to save. ORK will now add the control wrapper to the camera when loading the scene, which will handle blocking camera controls, camera target changes and target change transitions for you. No need to do any further setup.

Script

The script looks like this – you can use it do wrap other custom camera controls as well by changing the OOTII related code to your custom control’s code.

using UnityEngine;
using com.ootii.Cameras;
using System.Collections.Generic;

namespace ORKFramework.Behaviours
{
	public class ORKCameraControlWrapper : BaseCameraControl
	{
		public enum CameraReset { None, LocalSpace, WorldSpace };

		[Tooltip("Reset the camera's position after restoring camera control.\n" + 
			"Use 'Local Space' if the camera is a child object of the camera controller.")]
		public CameraReset resetCameraPosition = CameraReset.LocalSpace;

		[Tooltip("Reset the camera's rotation after restoring camera control.\n" +
			"Use 'Local Space' if the camera is a child object of the camera controller.")]
		public CameraReset resetCameraRotation = CameraReset.LocalSpace;

		[Tooltip("Hide the mouse cursor while the camera control is enabled.")]
		public bool hideCursor = false;

		/// <summary>
		/// The wrapped camera control component.
		/// Replace 'CameraController' with your custom camera control component's name if you're not using ootii (also remove 'using com.ootii.Cameras;').
		/// </summary>
		protected CameraController cameraControl;

		protected Camera cameraComponent;

		protected Vector3 cameraPosition = Vector3.zero;

		protected Quaternion cameraRotation = Quaternion.identity;

		/// <summary>
		/// Marks if the initial camera target is set.
		/// </summary>
		protected bool initialChange = false;

		/// <summary>
		/// Searches for the wrapped camera control component in child and parent objects.
		/// Disables the component if no camera control is found.
		/// </summary>
		protected void Start()
		{
			this.cameraControl = this.GetComponentInChildren<CameraController>();
			if(this.cameraControl == null)
			{
				this.cameraControl = this.GetComponentInParent<CameraController>();
			}
			if(this.cameraControl == null)
			{
				this.enabled = false;
			}
			else
			{
				this.cameraComponent = this.GetComponentInChildren<Camera>();
				if(this.cameraComponent == null)
				{
					this.cameraComponent = this.GetComponentInParent<Camera>();
				}
			}
		}

		/// <summary>
		/// Changes the target of the wrapped camera control component, called when ORK changes the target.
		/// </summary>
		/// <param name="oldTarget">The game object of the old target.</param>
		/// <param name="newTarget">The game object of the new target.</param>
		public override void CameraTargetChanged(GameObject oldTarget, GameObject newTarget)
		{
			if(this.cameraControl != null)
			{
				// sets the target of the wrapped component, change this with what's needed for your custom control when not using ootii.
				if(newTarget != null)
				{
					this.cameraControl.Anchor = newTarget.transform;
				}
				else
				{
					this.cameraControl.Anchor = null;
				}
			}
		}

		/// <summary>
		/// Sets the initial camera control target and handles camera target transitions.
		/// </summary>
		protected void LateUpdate()
		{
			if(!this.initialChange)
			{
				GameObject target = this.CameraTarget;
				if(target != null)
				{
					this.initialChange = true;
					this.CameraTargetChanged(null, target);
				}
			}

			if(this.IsCameraTargetTransition)
			{
				this.TransitionUpdate(this.transform.position, this.transform.rotation);
			}
		}

		/// <summary>
		/// Enables the wrapped camera control component.
		/// </summary>
		protected void OnEnable()
		{
			if(this.cameraComponent != null)
			{
				if(CameraReset.LocalSpace == this.resetCameraPosition)
				{
					this.cameraComponent.transform.localPosition = this.cameraPosition;
				}
				else if(CameraReset.WorldSpace == this.resetCameraPosition)
				{
					this.cameraComponent.transform.position = this.cameraPosition;
				}
				if(CameraReset.LocalSpace == this.resetCameraRotation)
				{
					this.cameraComponent.transform.localRotation = this.cameraRotation;
				}
				else if(CameraReset.WorldSpace == this.resetCameraRotation)
				{
					this.cameraComponent.transform.rotation = this.cameraRotation;
				}
			}
			if(this.cameraControl != null)
			{
				this.cameraControl.enabled = true;
			}
			if(this.hideCursor)
			{
				Cursor.lockState = CursorLockMode.Locked;
			}
		}

		/// <summary>
		/// Disables the wrapped camera control component.
		/// </summary>
		protected void OnDisable()
		{
			if(this.cameraComponent != null)
			{
				if(CameraReset.LocalSpace == this.resetCameraPosition)
				{
					this.cameraPosition = this.cameraComponent.transform.localPosition;
				}
				else if(CameraReset.WorldSpace == this.resetCameraPosition)
				{
					this.cameraPosition = this.cameraComponent.transform.position;
				}
				if(CameraReset.LocalSpace == this.resetCameraRotation)
				{
					this.cameraRotation = this.cameraComponent.transform.localRotation;
				}
				else if(CameraReset.WorldSpace == this.resetCameraRotation)
				{
					this.cameraRotation = this.cameraComponent.transform.rotation;
				}
			}
			if(this.cameraControl != null)
			{
				this.cameraControl.enabled = false;
			}
			if(this.hideCursor)
			{
				Cursor.lockState = CursorLockMode.None;
			}
		}
	}
}

Example: Cinemachine Camera Controller

Here’s an example wrapper component for Cinemachine. This wrapper will forward control blocks and supports Camera Control Target changes and transitions, you can download it here:

Download

In case transitions are not working, make sure the wrapper component is executed after the actual camera control component by adding it to the Script Execution Order. You can do this in Unity’s Project Settings, add the ORKCinemachineCameraControlWrapper component with a time of 100 (or more).

The wrapper component has settings for resetting the camera’s position and rotation after restoring camera control (to the position/rotation it had when the camera control was blocked). This can be done using local or world space.

Setup

To set it up in ORK Framework, go to Base/Control > Game Controls in the ORK editor.

Camera Controls

Disable built-in camera controls.

  • Camera Control Type
    Select None.

Custom Controls

Click on Add Custom Control and change the following settings.

  • Blocked By
    Select Camera.
  • Placed On
    Select Camera.
  • Behaviour Name
    Set to ORKCinemachineCameraControlWrapper.
  • Add Component
    Enable this setting.

And that’s it – don’t forget to save. ORK will now add the control wrapper to the camera when loading the scene, which will handle blocking camera controls, camera target changes and target change transitions for you. No need to do any further setup.

Please note that the wrapper has to be on the same game object as the CinemachineBrain component, which is usually the camera. By default, the wrapper will use the player as follow and look at target – if you want a different setup, you can add the component manually to your scene’s camera and adjust the settings there.

Script

The script looks like this – you can use it do wrap other custom camera controls as well by changing the Cinemachine related code to your custom control’s code.

using UnityEngine;
using Cinemachine;
using System.Collections.Generic;

namespace ORKFramework.Behaviours
{
	public class ORKCinemachineCameraControlWrapper : BaseCameraControl
	{
		[Tooltip("Follow the player/camera target.")]
		public bool followTarget = true;

		[Tooltip("Look at the player/camera target.")]
		public bool lookAtTarget = true;

		public enum CameraReset { None, LocalSpace, WorldSpace };

		[Tooltip("Reset the camera's position after restoring camera control.\n" +
			"Use 'Local Space' if the camera is a child object of the camera controller.")]
		public CameraReset resetCameraPosition = CameraReset.LocalSpace;

		[Tooltip("Reset the camera's rotation after restoring camera control.\n" +
			"Use 'Local Space' if the camera is a child object of the camera controller.")]
		public CameraReset resetCameraRotation = CameraReset.LocalSpace;

		[Tooltip("Hide the mouse cursor while the camera control is enabled.")]
		public bool hideCursor = false;

		/// <summary>
		/// The wrapped camera control component.
		/// Replace 'CinemachineBrain' with your custom camera control component's name if you're not using Cinemachine (also remove 'using Cinemachine;' and replace it with your camera control's namespace).
		/// </summary>
		protected CinemachineBrain cameraControl;

		protected Camera cameraComponent;

		protected Vector3 cameraPosition = Vector3.zero;

		protected Quaternion cameraRotation = Quaternion.identity;

		/// <summary>
		/// Marks if the initial camera target is set.
		/// </summary>
		protected bool initialChange = false;

		/// <summary>
		/// Searches for the wrapped camera control component in child and parent objects.
		/// Disables the component if no camera control is found.
		/// </summary>
		protected void Start()
		{
			this.cameraControl = this.GetComponentInChildren<CinemachineBrain>();
			if(this.cameraControl == null)
			{
				this.cameraControl = this.GetComponentInParent<CinemachineBrain>();
			}
			if(this.cameraControl == null)
			{
				this.enabled = false;
			}
			else
			{
				this.cameraComponent = this.GetComponentInChildren<Camera>();
				if(this.cameraComponent == null)
				{
					this.cameraComponent = this.GetComponentInParent<Camera>();
				}
			}
		}

		/// <summary>
		/// Changes the target of the wrapped camera control component, called when ORK changes the target.
		/// </summary>
		/// <param name="oldTarget">The game object of the old target.</param>
		/// <param name="newTarget">The game object of the new target.</param>
		public override void CameraTargetChanged(GameObject oldTarget, GameObject newTarget)
		{
			if(this.cameraControl != null)
			{
				// sets the target of the wrapped component, change this with what's needed for your custom control when not using Cinemachine.
				if(newTarget != null)
				{
					if(this.followTarget)
					{
						this.cameraControl.ActiveVirtualCamera.Follow = newTarget.transform;
					}
					if(this.lookAtTarget)
					{
						this.cameraControl.ActiveVirtualCamera.LookAt = newTarget.transform;
					}
				}
				else
				{
					if(this.followTarget)
					{
						this.cameraControl.ActiveVirtualCamera.Follow = null;
					}
					if(this.lookAtTarget)
					{
						this.cameraControl.ActiveVirtualCamera.LookAt = null;
					}
				}
			}
		}

		/// <summary>
		/// Sets the initial camera control target and handles camera target transitions.
		/// </summary>
		protected void LateUpdate()
		{
			if(!this.initialChange)
			{
				GameObject target = this.CameraTarget;
				if(target != null)
				{
					this.initialChange = true;
					this.CameraTargetChanged(null, target);
				}
			}

			if(this.IsCameraTargetTransition)
			{
				this.TransitionUpdate(this.transform.position, this.transform.rotation);
			}
		}

		/// <summary>
		/// Enables the wrapped camera control component.
		/// </summary>
		protected void OnEnable()
		{
			if(this.cameraComponent != null)
			{
				if(CameraReset.LocalSpace == this.resetCameraPosition)
				{
					this.cameraComponent.transform.localPosition = this.cameraPosition;
				}
				else if(CameraReset.WorldSpace == this.resetCameraPosition)
				{
					this.cameraComponent.transform.position = this.cameraPosition;
				}
				if(CameraReset.LocalSpace == this.resetCameraRotation)
				{
					this.cameraComponent.transform.localRotation = this.cameraRotation;
				}
				else if(CameraReset.WorldSpace == this.resetCameraRotation)
				{
					this.cameraComponent.transform.rotation = this.cameraRotation;
				}
			}
			if(this.cameraControl != null)
			{
				this.cameraControl.enabled = true;
			}
			if(this.hideCursor)
			{
				Cursor.lockState = CursorLockMode.Locked;
			}
		}

		/// <summary>
		/// Disables the wrapped camera control component.
		/// </summary>
		protected void OnDisable()
		{
			if(this.cameraComponent != null)
			{
				if(CameraReset.LocalSpace == this.resetCameraPosition)
				{
					this.cameraPosition = this.cameraComponent.transform.localPosition;
				}
				else if(CameraReset.WorldSpace == this.resetCameraPosition)
				{
					this.cameraPosition = this.cameraComponent.transform.position;
				}
				if(CameraReset.LocalSpace == this.resetCameraRotation)
				{
					this.cameraRotation = this.cameraComponent.transform.localRotation;
				}
				else if(CameraReset.WorldSpace == this.resetCameraRotation)
				{
					this.cameraRotation = this.cameraComponent.transform.rotation;
				}
			}
			if(this.cameraControl != null)
			{
				this.cameraControl.enabled = false;
			}
			if(this.hideCursor)
			{
				Cursor.lockState = CursorLockMode.None;
			}
		}
	}
}