using UnityEngine;
using System.Collections;
namespace RTS_Cam
{
[RequireComponent(typeof(Camera))]
[AddComponentMenu("RTS Camera")]
public class RTS_Camera : MonoBehaviour
{
#region Foldouts
#if UNITY_EDITOR
public int lastTab = 0;
public bool movementSettingsFoldout;
public bool zoomingSettingsFoldout;
public bool rotationSettingsFoldout;
public bool heightSettingsFoldout;
public bool mapLimitSettingsFoldout;
public bool targetingSettingsFoldout;
public bool inputSettingsFoldout;
#endif
#endregion
private Transform m_Transform; //camera tranform
public bool useFixedUpdate = false; //use FixedUpdate() or Update()
#region Movement
public float keyboardMovementSpeed = 5f; //speed with keyboard movement
public float screenEdgeMovementSpeed = 3f; //spee with screen edge movement
public float followingSpeed = 5f; //speed when following a target
public float rotationSped = 3f;
public float panningSpeed = 10f;
public float mouseRotationSpeed = 10f;
#endregion
#region Height
public bool autoHeight = true;
public LayerMask groundMask = -1; //layermask of ground or other objects that affect height
public float maxHeight = 10f; //maximal height
public float minHeight = 15f; //minimnal height
public float heightDampening = 5f;
public float keyboardZoomingSensitivity = 2f;
public float scrollWheelZoomingSensitivity = 25f;
private float zoomPos = 0; //value in range (0, 1) used as t in Matf.Lerp
#endregion
#region MapLimits
public bool limitMap = true;
public float limitX = 50f; //x limit of map
public float limitY = 50f; //z limit of map
#endregion
#region Targeting
public Transform targetFollow; //target to follow
public Vector3 targetOffset;
///
/// are we following target
///
public bool FollowingTarget
{
get
{
return targetFollow != null;
}
}
#endregion
#region Input
public bool useScreenEdgeInput = true;
public float screenEdgeBorder = 25f;
public bool useKeyboardInput = true;
public string horizontalAxis = "Horizontal";
public string verticalAxis = "Vertical";
public bool usePanning = true;
public KeyCode panningKey = KeyCode.Mouse2;
public bool useKeyboardZooming = true;
public KeyCode zoomInKey = KeyCode.E;
public KeyCode zoomOutKey = KeyCode.Q;
public bool useScrollwheelZooming = true;
public string zoomingAxis = "Mouse ScrollWheel";
public bool useKeyboardRotation = true;
public KeyCode rotateRightKey = KeyCode.X;
public KeyCode rotateLeftKey = KeyCode.Z;
public bool useMouseRotation = true;
public KeyCode mouseRotationKey = KeyCode.Mouse1;
private Vector2 KeyboardInput
{
get { return useKeyboardInput ? new Vector2(Input.GetAxis(horizontalAxis), Input.GetAxis(verticalAxis)) : Vector2.zero; }
}
private Vector2 MouseInput
{
get { return Input.mousePosition; }
}
private float ScrollWheel
{
get { return Input.GetAxis(zoomingAxis); }
}
private Vector2 MouseAxis
{
get { return new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y")); }
}
private int ZoomDirection
{
get
{
bool zoomIn = Input.GetKey(zoomInKey);
bool zoomOut = Input.GetKey(zoomOutKey);
if (zoomIn && zoomOut)
return 0;
else if (!zoomIn && zoomOut)
return 1;
else if (zoomIn && !zoomOut)
return -1;
else
return 0;
}
}
private int RotationDirection
{
get
{
bool rotateRight = Input.GetKey(rotateRightKey);
bool rotateLeft = Input.GetKey(rotateLeftKey);
if(rotateLeft && rotateRight)
return 0;
else if(rotateLeft && !rotateRight)
return -1;
else if(!rotateLeft && rotateRight)
return 1;
else
return 0;
}
}
#endregion
#region Unity_Methods
private void Start()
{
m_Transform = transform;
}
private void Update()
{
if (!useFixedUpdate)
CameraUpdate();
}
private void FixedUpdate()
{
if (useFixedUpdate)
CameraUpdate();
}
#endregion
#region RTSCamera_Methods
///
/// update camera movement and rotation
///
private void CameraUpdate()
{
if (FollowingTarget)
FollowTarget();
else
Move();
HeightCalculation();
Rotation();
LimitPosition();
}
///
/// move camera with keyboard or with screen edge
///
private void Move()
{
if (useKeyboardInput)
{
Vector3 desiredMove = new Vector3(KeyboardInput.x, 0, KeyboardInput.y);
desiredMove *= keyboardMovementSpeed;
desiredMove *= Time.deltaTime;
desiredMove = Quaternion.Euler(new Vector3(0f, transform.eulerAngles.y, 0f)) * desiredMove;
desiredMove = m_Transform.InverseTransformDirection(desiredMove);
m_Transform.Translate(desiredMove, Space.Self);
}
if (useScreenEdgeInput)
{
Vector3 desiredMove = new Vector3();
Rect leftRect = new Rect(0, 0, screenEdgeBorder, Screen.height);
Rect rightRect = new Rect(Screen.width - screenEdgeBorder, 0, screenEdgeBorder, Screen.height);
Rect upRect = new Rect(0, Screen.height - screenEdgeBorder, Screen.width, screenEdgeBorder);
Rect downRect = new Rect(0, 0, Screen.width, screenEdgeBorder);
desiredMove.x = leftRect.Contains(MouseInput) ? -1 : rightRect.Contains(MouseInput) ? 1 : 0;
desiredMove.z = upRect.Contains(MouseInput) ? 1 : downRect.Contains(MouseInput) ? -1 : 0;
desiredMove *= screenEdgeMovementSpeed;
desiredMove *= Time.deltaTime;
desiredMove = Quaternion.Euler(new Vector3(0f, transform.eulerAngles.y, 0f)) * desiredMove;
desiredMove = m_Transform.InverseTransformDirection(desiredMove);
m_Transform.Translate(desiredMove, Space.Self);
}
if(usePanning && Input.GetKey(panningKey) && MouseAxis != Vector2.zero)
{
Vector3 desiredMove = new Vector3(-MouseAxis.x, 0, -MouseAxis.y);
desiredMove *= panningSpeed;
desiredMove *= Time.deltaTime;
desiredMove = Quaternion.Euler(new Vector3(0f, transform.eulerAngles.y, 0f)) * desiredMove;
desiredMove = m_Transform.InverseTransformDirection(desiredMove);
m_Transform.Translate(desiredMove, Space.Self);
}
}
///
/// calcualte height
///
private void HeightCalculation()
{
float distanceToGround = DistanceToGround();
if(useScrollwheelZooming)
zoomPos += ScrollWheel * Time.deltaTime * scrollWheelZoomingSensitivity;
if (useKeyboardZooming)
zoomPos += ZoomDirection * Time.deltaTime * keyboardZoomingSensitivity;
zoomPos = Mathf.Clamp01(zoomPos);
float targetHeight = Mathf.Lerp(minHeight, maxHeight, zoomPos);
float difference = 0;
if(distanceToGround != targetHeight)
difference = targetHeight - distanceToGround;
m_Transform.position = Vector3.Lerp(m_Transform.position,
new Vector3(m_Transform.position.x, targetHeight + difference, m_Transform.position.z), Time.deltaTime * heightDampening);
}
///
/// rotate camera
///
private void Rotation()
{
if(useKeyboardRotation)
transform.Rotate(Vector3.up, RotationDirection * Time.deltaTime * rotationSped, Space.World);
if (useMouseRotation && Input.GetKey(mouseRotationKey))
m_Transform.Rotate(Vector3.up, -MouseAxis.x * Time.deltaTime * mouseRotationSpeed, Space.World);
}
///
/// follow targetif target != null
///
private void FollowTarget()
{
Vector3 targetPos = new Vector3(targetFollow.position.x, m_Transform.position.y, targetFollow.position.z) + targetOffset;
m_Transform.position = Vector3.MoveTowards(m_Transform.position, targetPos, Time.deltaTime * followingSpeed);
}
///
/// limit camera position
///
private void LimitPosition()
{
if (!limitMap)
return;
m_Transform.position = new Vector3(Mathf.Clamp(m_Transform.position.x, -limitX, limitX),
m_Transform.position.y,
Mathf.Clamp(m_Transform.position.z, -limitY, limitY));
}
///
/// set the target
///
///
public void SetTarget(Transform target)
{
targetFollow = target;
}
///
/// reset the target (target is set to null)
///
public void ResetTarget()
{
targetFollow = null;
}
///
/// calculate distance to ground
///
///
private float DistanceToGround()
{
Ray ray = new Ray(m_Transform.position, Vector3.down);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, groundMask.value))
return (hit.point - m_Transform.position).magnitude;
return 0f;
}
#endregion
}
}