Skip to content

juniordiscart/ImpossibleOdds-TacticalCamera

Repository files navigation

Impossible Odds Logo Impossible Odds - Tactical Camera

The Impossible Odds Tactical Camera package provides a plugin camera system for smoothly navigating your environments in both a top-down tactical view as well as up-close action scenes.

You can expect to find the following set of features in this plugin:

  • Move the camera using the keyboard or screen edge detection, or double click to move to a target position.
  • Zoom in & out with a dynamic field of view to get a greater sense of scale.
  • Look around with restricted tilt angles, and orbit around a focus point.
  • Smooth collision detection with terrain and objects in your world.
  • Restricted area-of-operation to keep the camera inside the map boundaries.
  • Height-based parameters where the camera's behaviour changes based on its altitude.
  • Extensive customization of behaviour through simple animation curves.
  • Minimal setup and easy integration.

You can view a quick demo video of this plugin below.

Impossible Odds - Tactical Camera

Prerequisites & Installation

This package was developed on Unity 2020 LTS. So make sure you're on this version of Unity, or newer.

Open Unity's package manager and add the following git-tracked URLs to your project:

  • C# Toolkit:

https://github.com/juniordiscart/ImpossibleOdds-Toolkit.git?path=/Assets/Impossible%20Odds/Toolkit

  • Tactical Camera:

https://github.com/juniordiscart/ImpossibleOdds-TacticalCamera.git?path=/Assets/Impossible%20Odds/TacticalCamera

Quick Camera Setup

If you want to get started quickly without being bothered with all the details, then follow these few steps:

  1. Add the TacticalCamera component to your Camera game object. This will also add a CharacterController component to it.
  2. Create a TacticalCameraSettings data object (Assets → Create → Impossible Odds → Tactical Camera → new Tactical Camera Settings) and assign it to the Settings property. You can play around with the different values to make it feel/behave differently.
  3. Finally, add the TacticalCameraInputProvider component to the game object and assign it to the Input Provider property. Feel free to adjust the key bindings in a way that you see fit.
  4. Optionally, add some bounds in which the camera is allowed to operate and assign it to the Operational bounds property. The TacticalCameraBoxBounds component restricts it to operate within the defined outline of the box.

That's it!

Quick Camera Setup

Note: remember to check out the tooltips in the inspector if something is not clear!

Detailed Camera Setup

The Tactical Camera plugin has a central component that does all the heavy lifting: TacticalCamera. It will also add a CharacterController component on there which it uses to detect collisions as well as move smoothly over any terrain and objects.

The component requires a few additional data objects to operate correctly:

  • An input provider to move and rotate in and around the environment, and
  • A settings object that defines how it operates/behaves, e.g. movement and rotation speed, tilt angles, etc.

Optionally, the camera can also be equipped with a component that restricts its area of operation so that it can't move outside of your game world.

Tactical Camera Component

Input Provider

The input provider for the Tactical Camera instructs where the camera should move to and where to look at. Input is very project-dependent and there is no "one size fits all"-solution, e.g. mouse & keyboard versus gamepad versus touch screen, etc. That's why this camera is designed to be driven using an interface-component rather than forcing a single solution on you. However, a sample implementation of an input provider is given by the TacticalCameraInputProvider component. It's designed for use with mouse and keyboard and allows you to assign which keys and mouse axes should be used to control the movement and rotation.

Input Provider

Note: remember to check out the tooltips in the inspector if something is not clear!

Input Provider - Advanced

The ITacticalCameraInputProvider interface is the key to hooking the Tactical Camera system in your custom input code. Either have your input object implement this interface as well to pass it along to the Tactical Camera directly, or provide an abstraction layer for this interface in your input code.

The interface expects you to implement the following features:

  • Moving forward, sideways and upwards through the MoveForward, MoveSideways and MoveUp properties. These should return a value in the range of [-1, 1].
  • Moving to a target position through the MoveToTarget and CancelMoveToTarget properties. These should return true when the action is requested, i.e. when a button is pressed down that frame.
  • Rotating around its pivot or focus point through the TiltDelta and RotationDelta properties. The OrbitAroundTarget is the switch between rotating around the pivot or focus point. As long as this last one keeps returning true, the Tactical Camera will orbit around the focal point rather than rotate around its pivot point.

Note: the ITacticalCameraInputProvider interface in itself does not define which particular input method is used, e.g. moving using the keyboard versus the mouse cursor against the edge of the screen. The implementing class should define which methods are supported by way of returning appropriate values.

Settings

The Tactical Camera's behaviour is driven by a data object that tells it how fast it can move and rotate, as well as how smooth it comes to a standstill and how its movement is affected by altitude. The TacticalCameraSettings is the ScriptableObject that holds this data. It can be created through the Unity create menu: Assets → Create → Impossible Odds → Tactical Camera → new Tactical Camera Settings.

You can adjust the values in this object to suit the environment the camera will operate in, but sensible default values have already been set for a small-to-medium sized map. This object operates using value ranges and animation curves. The choice for using animation curves allows to visually define how a specific value should fade out, or how a value should transition from one end to the other, e.g. the movement speed versus the altitude of the camera.

The settings object also allows to set some world-interaction values which might be of particular interest for performance reasons:

  • The World interaction mask (InteractionMask) property defines which collision layers are interacted with during raycast operations. This is best set to only layers that are of interest to the camera to interact with, i.e. your terrain and some world-objects.
  • The Max ray casting distance (InteractionDistance) property defines the maximum length of raycasts used for interacting with your world. The larger this value, the further it has to check. Reduce this to a value that makes sense for your world setup.
  • The Collision radius (InteractionBubbleRadius) defines the sphere in which the camera collides with objects in your world. This adjusts the radius property on the attached CharacterController component.

Settings

Note: remember to check out the tooltips in the inspector if something is not clear!

Settings - Advanced

Compared to the input provision, this implementation of settings is immediately usable in a broad set of projects. Nonetheless, if you want to further alter or customize the behaviour, the ITacticalCameraSettings interface is what you should look into.

This interface will ask you to implement the following:

  • The height limits in which the Tactical Camera is allowed to operate in through the AbsoluteHeightRange property. This is a range in which the camera will always be restricted to, even if there are operational bounds assigned with higher ceiling or lower floor values defined.
  • Movement behaviour through MovementSpeedRange, MovementFadeTime and MoveToTargetSmoothingTime.
  • Rotational behaviour through MaxRotationalSpeed, RotationalFadeTime, TiltRangeLow and TiltRangeHigh. These last two define what the angle ranges are for the Tactical Camera when its at its lowest and highest point, respectively.
  • Field of view settings through UseDynamicFieldOfView and DynamicFieldOfViewRange.
  • World interation settings through InteractionMask, InteractionDistance and InteractionBubbleRadius.
  • Several evaluation methods for custom fade-outs and transition curves.

Most of these properties are self-explanatory, but the purpose of the evaluation methods might not be immediately clear. Each of these methods take a float value as input in the range of [0, 1]. The output of these methods can be exactly the same as their input value in case a linear transition is desirable, but it can also be transformed to create a more pleasant looking/feeling result, e.g. a smooth roll-off in case of fading, or an ease-in, ease-out in case of transitions. In the implementation of TacticalCameraSettings, this is done by evaluating animation curves which naturally lend themselves to this.

  • EvaluateMovementFadeOut and EvaluateRotationFadeOut are fading methods that determine how the movement and rotation of the camera fade out when no more input is given.
  • EvaluateMovementTransition, EvaluateTiltTransition and EvaluateFieldOfViewTransition methods determine how the camera reacts to transitions in altitude. When the camera moves around, several values or value ranges may change in response to that, e.g. when higher up, the faster the camera can move around.

Settings

Area of Operation

In most situations it's desirable to restrict the camera to a specific area so that it can't wander off in areas not meant for the player to visit. The Tactical Camera can be equipped with some bounds that force it to be in a particular area.

How such an area is defined is very project-dependent and could become a complex matter. For example, polygonal level bounds in case the map is not just a square, or a fog-of-war restriction where undiscovered pieces of the map may not be accessible yet.

To give a basic form of restriction already, the TacticalCameraBoxBounds component can restrict the Tactical Camera's position to a simple box. Whenever it tries to leave the area, its position is reset to the nearest valid location inside the box. The box bounds can be made to align and scale with the game object it is put on by ticking the Follow Game Object toggle.

The TacticalCameraCompositeBounds component can stitch together multiple bounds objects and make them act like a single one. You can include custom bounds implementations to the list as well!

Box Bounds

Area of Operation - Advanced

To have the Tactical Camera be restricted to more complex areas, have your restriction tool implement the ITacticalCameraBounds interface with a couple of straightforward calls:

  • void Apply(TacticalCamera) should check on the camera's current position and place it back within the bounds if the camera is currently outside of them.
  • Vector3 Apply(Vector3) should check on the provided position and either return the same value when aleady within the bounds, or the closest point that lies within.
  • bool IsWithinBounds(Vector3) should simply check whether the provided position is within the bounds.

Dependency Injection

The external resources the Tactical Camera system requires to operate can all be assigned through Unity's inspector view or through your own scripts. Additionally, you can also have them delivered by the Dependency Injection framework from the Impossible Odds C# Toolkit. It allows you to inject resources and values into objects that require them to operate, which makes managing resources in your project easier.

The TacticalCamera component's properties for the input provider, settings and bounds are all marked for injection in case you prefer to work using this system as well.

Gotcha's

When using the Tactical Camera system you might run into a few limits of the system as well. You'll find them listed here:

  • The z-value of the local Euler rotation angle is always set to 0 at the end of its LateUpdate phase. This is to prevent drift and keeps the camera straight up.
  • The operating range of the tilt angle in the TacticalCameraSettings objects can be no larger than [-90, 90] degrees, with 0 degrees being level with the horizon. This range is defined to prevent flipping over. If you make a custom implementation through ITacticalCameraSettings, best to keep this in mind.

Example

Check out the demo scene for a complete setup and demonstration of how the camera behaves in different circumstances. This scene is setup using the dependency injection method, i.e. the resources the camera needs are injected upon Start from the TacticalCameraDemo component.

Unity Version

Developed and tested on Unity 2020.3 LTS.

License

This package is provided under the MIT license.