247 lines
11 KiB
C#
247 lines
11 KiB
C#
using System;
|
|
using UnityEngine;
|
|
|
|
namespace Com.LuisPedroFonseca.ProCamera2D
|
|
{
|
|
public struct RaycastOrigins
|
|
{
|
|
public Vector3 TopRight;
|
|
public Vector3 TopLeft;
|
|
public Vector3 BottomRight;
|
|
public Vector3 BottomLeft;
|
|
}
|
|
|
|
public struct CameraCollisionState
|
|
{
|
|
public bool VTopLeft;
|
|
public bool HTopLeft;
|
|
public bool VTopRight;
|
|
public bool HTopRight;
|
|
public bool VBottomLeft;
|
|
public bool HBottomLeft;
|
|
public bool VBottomRight;
|
|
public bool HBottomRight;
|
|
}
|
|
|
|
public class MoveInColliderBoundaries
|
|
{
|
|
Func<Vector3, float> Vector3H;
|
|
Func<Vector3, float> Vector3V;
|
|
Func<float, float, Vector3> VectorHV;
|
|
|
|
const float Offset = .2f;
|
|
const float RaySizeCompensation = .2f;
|
|
|
|
public Transform CameraTransform;
|
|
public Vector2 CameraSize;
|
|
public LayerMask CameraCollisionMask;
|
|
|
|
public int TotalHorizontalRays = 3;
|
|
public int TotalVerticalRays = 3;
|
|
|
|
public RaycastOrigins RaycastOrigins { get { return _raycastOrigins; } }
|
|
RaycastOrigins _raycastOrigins;
|
|
|
|
public CameraCollisionState CameraCollisionState { get { return _cameraCollisionState; } }
|
|
CameraCollisionState _cameraCollisionState;
|
|
|
|
RaycastHit _raycastHit;
|
|
|
|
float _verticalDistanceBetweenRays;
|
|
float _horizontalDistanceBetweenRays;
|
|
|
|
ProCamera2D _proCamera2D;
|
|
|
|
public MoveInColliderBoundaries(ProCamera2D proCamera2D)
|
|
{
|
|
_proCamera2D = proCamera2D;
|
|
|
|
switch (_proCamera2D.Axis)
|
|
{
|
|
case MovementAxis.XY:
|
|
Vector3H = vector => vector.x;
|
|
Vector3V = vector => vector.y;
|
|
VectorHV = (h, v) => new Vector3(h, v, 0);
|
|
break;
|
|
case MovementAxis.XZ:
|
|
Vector3H = vector => vector.x;
|
|
Vector3V = vector => vector.z;
|
|
VectorHV = (h, v) => new Vector3(h, 0, v);
|
|
break;
|
|
case MovementAxis.YZ:
|
|
Vector3H = vector => vector.z;
|
|
Vector3V = vector => vector.y;
|
|
VectorHV = (h, v) => new Vector3(0, v, h);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public Vector3 Move(Vector3 deltaMovement)
|
|
{
|
|
// Update raycasts origins
|
|
UpdateRaycastOrigins();
|
|
|
|
// Shoot corner rays to calculate offset and force movement if needed
|
|
GetOffsetAndForceMovement(_raycastOrigins.BottomLeft, ref deltaMovement, ref _cameraCollisionState.HBottomLeft, ref _cameraCollisionState.VBottomLeft, -1f, -1f);
|
|
GetOffsetAndForceMovement(_raycastOrigins.BottomRight, ref deltaMovement, ref _cameraCollisionState.HBottomRight, ref _cameraCollisionState.VBottomRight, 1f, -1f);
|
|
GetOffsetAndForceMovement(_raycastOrigins.TopLeft, ref deltaMovement, ref _cameraCollisionState.HTopLeft, ref _cameraCollisionState.VTopLeft, -1f, 1f);
|
|
GetOffsetAndForceMovement(_raycastOrigins.TopRight, ref deltaMovement, ref _cameraCollisionState.HTopRight, ref _cameraCollisionState.VTopRight, 1f, 1f);
|
|
|
|
// Check movement in the horizontal dir
|
|
float h = 0f;
|
|
if (Vector3H(deltaMovement) != 0)
|
|
h = MoveInAxis(Vector3H(deltaMovement), true);
|
|
|
|
// Check movement in the vertical dir
|
|
float v = 0f;
|
|
if (Vector3V(deltaMovement) != 0)
|
|
v = MoveInAxis(Vector3V(deltaMovement), false);
|
|
|
|
// Return updated movement
|
|
return VectorHV(h, v);
|
|
}
|
|
|
|
void UpdateRaycastOrigins()
|
|
{
|
|
_raycastOrigins.BottomRight = VectorHV(Vector3H(CameraTransform.localPosition) + (CameraSize.x / 2), Vector3V(CameraTransform.localPosition) - (CameraSize.y / 2));
|
|
|
|
_raycastOrigins.BottomLeft = VectorHV(Vector3H(CameraTransform.localPosition) - (CameraSize.x / 2), Vector3V(CameraTransform.localPosition) - (CameraSize.y / 2));
|
|
|
|
_raycastOrigins.TopRight = VectorHV(Vector3H(CameraTransform.localPosition) + (CameraSize.x / 2), Vector3V(CameraTransform.localPosition) + (CameraSize.y / 2));
|
|
|
|
_raycastOrigins.TopLeft = VectorHV(Vector3H(CameraTransform.localPosition) - (CameraSize.x / 2), Vector3V(CameraTransform.localPosition) + (CameraSize.y / 2));
|
|
|
|
_horizontalDistanceBetweenRays = CameraSize.x / (TotalVerticalRays - 1);
|
|
_verticalDistanceBetweenRays = CameraSize.y / (TotalHorizontalRays - 1);
|
|
}
|
|
|
|
void GetOffsetAndForceMovement(Vector3 rayTargetPos, ref Vector3 deltaMovement, ref bool horizontalCheck, ref bool verticalCheck, float hSign, float vSign)
|
|
{
|
|
Vector3 rayOrigin = VectorHV(Vector3H(CameraTransform.localPosition), Vector3V(CameraTransform.localPosition));
|
|
Vector3 rayDirection = (rayTargetPos - rayOrigin).normalized;
|
|
float raySize = (rayTargetPos - rayOrigin).magnitude + .01f + .5f;
|
|
|
|
DrawRay(rayOrigin, rayDirection * raySize, Color.yellow);
|
|
|
|
if (Physics.Raycast(rayOrigin, rayDirection, out _raycastHit, raySize, CameraCollisionMask))
|
|
{
|
|
if (Mathf.Abs(Vector3H(_raycastHit.normal)) > Mathf.Abs(Vector3V(_raycastHit.normal)))
|
|
{
|
|
horizontalCheck = !verticalCheck;
|
|
if (Vector3H(deltaMovement) == 0)
|
|
{
|
|
var deltaMovH = .1f * hSign;
|
|
deltaMovement = VectorHV(deltaMovH, Vector3V(deltaMovement));
|
|
var h = MoveInAxis(Vector3H(deltaMovement), true);
|
|
deltaMovement = VectorHV(h, Vector3V(deltaMovement));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
verticalCheck = !horizontalCheck;
|
|
if (Vector3V(deltaMovement) == 0)
|
|
{
|
|
var deltaMovV = .1f * vSign;
|
|
deltaMovement = VectorHV(Vector3H(deltaMovement), deltaMovV);
|
|
var v = MoveInAxis(Vector3V(deltaMovement), false);
|
|
deltaMovement = VectorHV(Vector3H(deltaMovement), v);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
horizontalCheck = false;
|
|
verticalCheck = false;
|
|
}
|
|
}
|
|
|
|
float MoveInAxis(float deltaMovement, bool isHorizontal)
|
|
{
|
|
bool isPositiveDirection = deltaMovement > 0;
|
|
float rayDistance = Mathf.Abs(deltaMovement) + RaySizeCompensation;
|
|
|
|
Vector3 rayDirection;
|
|
Vector3 initialRayOrigin;
|
|
if (isHorizontal)
|
|
{
|
|
rayDirection = isPositiveDirection ? CameraTransform.right : -CameraTransform.right;
|
|
initialRayOrigin = isPositiveDirection ? _raycastOrigins.BottomRight : _raycastOrigins.BottomLeft;
|
|
}
|
|
else
|
|
{
|
|
rayDirection = isPositiveDirection ? CameraTransform.up : -CameraTransform.up;
|
|
initialRayOrigin = isPositiveDirection ? _raycastOrigins.TopLeft : _raycastOrigins.BottomLeft;
|
|
}
|
|
|
|
float raycastHitPos = Mathf.NegativeInfinity;
|
|
bool hasRayHit = false;
|
|
var totalRays = isHorizontal ? TotalHorizontalRays : TotalVerticalRays;
|
|
for (int i = 0; i < totalRays; i++)
|
|
{
|
|
float rayH = isHorizontal ? Vector3H(initialRayOrigin) : Vector3H(initialRayOrigin) + i * _horizontalDistanceBetweenRays;
|
|
float rayV = isHorizontal ? Vector3V(initialRayOrigin) + i * _verticalDistanceBetweenRays : Vector3V(initialRayOrigin);
|
|
|
|
// Add a small offset to avoid collisions at "zero"
|
|
if (isHorizontal)
|
|
{
|
|
if ((isPositiveDirection && _cameraCollisionState.VBottomRight && i == 0) ||
|
|
(!isPositiveDirection && _cameraCollisionState.VBottomLeft && i == 0))
|
|
rayV += Offset;
|
|
|
|
if ((isPositiveDirection && _cameraCollisionState.VTopRight && i == totalRays - 1) ||
|
|
(!isPositiveDirection && _cameraCollisionState.VTopLeft && i == totalRays - 1))
|
|
rayV -= Offset;
|
|
}
|
|
else
|
|
{
|
|
if ((isPositiveDirection && _cameraCollisionState.HTopLeft && i == 0) ||
|
|
(!isPositiveDirection && _cameraCollisionState.HBottomLeft && i == 0))
|
|
rayH += Offset;
|
|
|
|
if ((isPositiveDirection && _cameraCollisionState.HTopRight && i == totalRays - 1) ||
|
|
(!isPositiveDirection && _cameraCollisionState.HBottomRight && i == totalRays - 1))
|
|
rayH -= Offset;
|
|
}
|
|
|
|
Vector3 ray = VectorHV(rayH, rayV);
|
|
|
|
// Raycast
|
|
if (Physics.Raycast(ray, rayDirection, out _raycastHit, rayDistance, CameraCollisionMask))
|
|
{
|
|
DrawRay(ray, rayDirection * rayDistance, Color.red);
|
|
|
|
if (isHorizontal &&
|
|
hasRayHit &&
|
|
(isPositiveDirection && raycastHitPos <= Vector3H(_raycastHit.point)) ||
|
|
(!isPositiveDirection && raycastHitPos >= Vector3H(_raycastHit.point)))
|
|
continue;
|
|
else if (hasRayHit &&
|
|
(isPositiveDirection && raycastHitPos <= Vector3V(_raycastHit.point)) ||
|
|
(!isPositiveDirection && raycastHitPos >= Vector3V(_raycastHit.point)))
|
|
continue;
|
|
|
|
hasRayHit = true;
|
|
|
|
deltaMovement = isHorizontal ? Vector3H(_raycastHit.point) - Vector3H(ray) + (isPositiveDirection ? -RaySizeCompensation : RaySizeCompensation) :
|
|
Vector3V(_raycastHit.point) - Vector3V(ray) + (isPositiveDirection ? -RaySizeCompensation : RaySizeCompensation);
|
|
|
|
raycastHitPos = isHorizontal ? Vector3H(_raycastHit.point) : Vector3V(_raycastHit.point);
|
|
}
|
|
else
|
|
{
|
|
DrawRay(ray, rayDirection * rayDistance, Color.cyan);
|
|
}
|
|
}
|
|
|
|
return deltaMovement;
|
|
}
|
|
|
|
private void DrawRay(Vector3 start, Vector3 dir, Color color, float duration = 0)
|
|
{
|
|
if (duration != 0)
|
|
Debug.DrawRay(start, dir, color, duration);
|
|
else
|
|
Debug.DrawRay(start, dir, color);
|
|
}
|
|
}
|
|
} |