Skip to content

Instantly share code, notes, and snippets.

@daleth90
Created August 25, 2016 09:54
Show Gist options
  • Save daleth90/ab7966412413c6f13d8a978a678ddf9a to your computer and use it in GitHub Desktop.
Save daleth90/ab7966412413c6f13d8a978a678ddf9a to your computer and use it in GitHub Desktop.
using UnityEngine;
using System;
public class ScrollCamera : MonoBehaviour {
public enum MovementType {
Unrestricted,
Elastic,
Clamped
}
[Serializable]
private struct ScrollBound {
public Vector2 center;
public Vector2 extents;
}
[SerializeField]
private bool horizontal = true;
[SerializeField]
private bool vertical = true;
[SerializeField]
private MovementType movementType = MovementType.Elastic;
[SerializeField]
[Range( 0f, 1f )]
private float elasticity = 0.1f;
[SerializeField]
private bool inertia = true;
[SerializeField]
[Range( 0f, 1f )]
private float decelerationRate = 0.135f;
[SerializeField]
private ScrollBound scrollBound;
private Camera cameraComponent;
private bool isDragging;
private Vector2 pointerStartPosition;
private Vector2 cameraStartPosition;
private Vector2 previousPosition;
private Vector2 velocity;
private void Awake() {
cameraComponent = GetComponent<Camera>();
}
private void Update() {
if ( Input.GetMouseButtonDown( 0 ) ) {
OnBeginDrag();
}
else if ( Input.GetMouseButton( 0 ) ) {
OnDrag();
}
else if ( Input.GetMouseButtonUp( 0 ) ) {
OnEndDrag();
}
}
private void OnBeginDrag() {
pointerStartPosition = cameraComponent.ScreenToViewportPoint( Input.mousePosition );
cameraStartPosition = transform.position;
isDragging = true;
}
private void OnEndDrag() {
isDragging = false;
}
private void OnDrag() {
Vector2 pointerPosition = cameraComponent.ScreenToViewportPoint( Input.mousePosition );
Vector2 pointerDeltaPosition = pointerPosition - pointerStartPosition;
Vector2 position = cameraStartPosition - pointerDeltaPosition * 10;
Vector2 offset = CalculateOffset( position );
position += offset;
if ( movementType == MovementType.Elastic ) {
if ( offset.x != 0 )
position.x = position.x - RubberDelta( offset.x, scrollBound.extents.x );
if ( offset.y != 0 )
position.y = position.y - RubberDelta( offset.y, scrollBound.extents.y );
}
SetPosition( position );
}
private Vector2 CalculateOffset( Vector2 position ) {
Vector2 offset = Vector2.zero;
if ( movementType == MovementType.Unrestricted )
return offset;
if ( horizontal ) {
if ( position.x < -scrollBound.extents.x )
offset.x = -scrollBound.extents.x - position.x;
else if ( position.x > scrollBound.extents.x )
offset.x = scrollBound.extents.x - position.x;
}
if ( vertical ) {
if ( position.y < -scrollBound.extents.y )
offset.y = -scrollBound.extents.y - position.y;
else if ( position.y > scrollBound.extents.y )
offset.y = scrollBound.extents.y - position.y;
}
return offset;
}
private void SetPosition( Vector2 position ) {
if ( !horizontal )
position.x = transform.position.x;
if ( !vertical )
position.y = transform.position.y;
if ( position != (Vector2)transform.position ) {
transform.position = new Vector3( position.x, position.y, transform.position.z );
}
}
private static float RubberDelta( float overStretching, float viewSize ) {
return ( 1 - ( 1 / ( ( Mathf.Abs( overStretching ) * 0.55f / viewSize ) + 1 ) ) ) * viewSize * Mathf.Sign( overStretching );
}
private void LateUpdate() {
float deltaTime = Time.unscaledDeltaTime;
Vector2 offset = CalculateOffset( transform.position );
if ( !isDragging && ( offset != Vector2.zero || velocity != Vector2.zero ) ) {
Vector2 position = transform.position;
for ( int axis = 0; axis < 2; ++axis ) {
if ( movementType == MovementType.Elastic && offset[ axis ] != 0 ) {
float speed = velocity[ axis ];
position[ axis ] = Mathf.SmoothDamp( transform.position[ axis ], transform.position[ axis ] + offset[ axis ], ref speed, elasticity, Mathf.Infinity, deltaTime );
velocity[ axis ] = speed;
}
else if ( inertia ) {
velocity[ axis ] *= Mathf.Pow( decelerationRate, deltaTime );
if ( Mathf.Abs( velocity[ axis ] ) < 1 )
velocity[ axis ] = 0;
position[ axis ] += velocity[ axis ] * deltaTime;
}
else {
velocity[ axis ] = 0;
}
}
if ( velocity != Vector2.zero ) {
if ( movementType == MovementType.Clamped ) {
offset = CalculateOffset( position );
position += offset;
}
SetPosition( position );
}
}
if ( isDragging && inertia ) {
Vector2 newVelocity = ( (Vector2)transform.position - previousPosition ) / deltaTime;
velocity = Vector2.Lerp( velocity, newVelocity, deltaTime * 10 );
}
previousPosition = transform.position;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment