xxxxxxxxxx
// PART 2/3
// SEE MY OTHER GREPPER ANSWERS UNDER "Unity constriain object to bounds"
// FOR THE OTHER PART OF THIS SCRIPT + METHODS
// (was too long for grepper)
void LateUpdate()
{
// Get the position of the constrained object
Vector3 newPosition = transform.position;
parentHalfWidth = parentRenderer.bounds.extents.x;
parentHalfHeight = parentRenderer.bounds.extents.y;
thisHalfWidth = thisRenderer.bounds.extents.x;
thisHalfHeight = thisRenderer.bounds.extents.y;
// Constraints are based off the parent's bounds
float leftBound = parent.position.x - parentHalfWidth;
float rightBound = parent.position.x + parentHalfWidth;
float bottomBound = parent.position.y - parentHalfHeight;
float topBound = parent.position.y + parentHalfHeight;
// Adjust the bounds to account for the marker sprite's size
// depending on where we want it to lie on the outermost extents of its limits
if ((inner & constraintType) == constraintType)
{
leftBound += thisHalfWidth;
rightBound -= thisHalfWidth;
bottomBound += thisHalfHeight;
topBound -= thisHalfHeight;
}
else
{
leftBound -= thisHalfWidth;
rightBound += thisHalfWidth;
bottomBound -= thisHalfHeight;
topBound += thisHalfHeight;
}
// Are we out of bounds?
if ((radial & constraintType) == constraintType)
{
isOutside = Vector3.Distance(parent.position, newPosition) > Mathf.Min(rightBound, topBound);
}
else
{
isOutside = newPosition.x < leftBound || newPosition.x > rightBound || newPosition.y < bottomBound || newPosition.y > topBound;
}
// Adjust our position based on selected limiting behavior
switch (constraintBehavior)
{
case ConstraintBehavior.Projection:
newPosition = ProjectionConstraint(newPosition, leftBound, rightBound, topBound, bottomBound);
break;
case ConstraintBehavior.Lerp:
newPosition = LerpConstraint(parent.position, newPosition, leftBound, rightBound, topBound, bottomBound);
break;
}
// If a radial constraint is selected and necessary, we need to addiitonally confine ourselves to a max radius
if ((isOutside && (radial & constraintType) == constraintType) ||
((border & radial) & constraintType) == constraintType)
{
if ((inner & constraintType) == constraintType)
newPosition = newPosition.normalized * Mathf.Min(parentHalfWidth + thisHalfWidth, parentHalfHeight - Mathf.Min(thisHalfWidth, thisHalfHeight));
else
newPosition = newPosition.normalized * Mathf.Min(parentHalfWidth + thisHalfWidth, parentHalfHeight + Mathf.Min(thisHalfWidth, thisHalfHeight));
}
// Set the position of the constrained object
transform.position = newPosition;
}
xxxxxxxxxx
using System;
using UnityEngine;
// PART 1/3
// SEE MY OTHER GREPPER ANSWER UNDER "Unity constrain object to bounds" SEARCH
// FOR THE PROJECTIONCONSTRAINT AND LERPCONSTRAINT FUNCTIONS
// (script was too long for grepper)
[ExecuteAlways]
public class ConstrainToBounds : MonoBehaviour
{
[Flags]
protected enum ConstraintBoundary
{
Inside = 1 << 0, // Anywhere inside the bounds
AllowJustOutside = 1 << 1, // Anywhere inside the bounds + as far as the exterior edge
InsideBorder = 1 << 2, // Always touching the inside border
OutsideBorder = 1 << 3, // Always touching the outside border
RadialInside = 1 << 4, // Keep within constant distance from center
RadialAllowJustOutside = 1 << 5,
RadialInsideBorder = 1 << 6,
RadialOutsideBorder = 1 << 7,
}
protected enum ConstraintBehavior
{
Projection, // Project onto appropriate edge when outside the boundary (angle between original and adjusted may differ)
Lerp // Linearly interpolate to place on appropriate edge (angle between original and adjusted is ==)
}
[SerializeField] private Transform parent;
[SerializeField, SingleEnumFlagSelect(EnumType = typeof(ConstraintBoundary))] private ConstraintBoundary constraintType;
[SerializeField] private ConstraintBehavior constraintBehavior;
private float parentHalfWidth;
private float parentHalfHeight;
private float thisHalfWidth; // Half width of the constrained object
private float thisHalfHeight; // Half height of the constrained object
bool isOutside;
SpriteRenderer parentRenderer, thisRenderer;
// Ease of access, bitmasking makes IF checks shorter
private readonly ConstraintBoundary box = ConstraintBoundary.Inside | ConstraintBoundary.AllowJustOutside | ConstraintBoundary.InsideBorder | ConstraintBoundary.OutsideBorder;
private readonly ConstraintBoundary radial = ConstraintBoundary.RadialInside | ConstraintBoundary.RadialAllowJustOutside | ConstraintBoundary.RadialInsideBorder | ConstraintBoundary.RadialOutsideBorder;
private readonly ConstraintBoundary area = ConstraintBoundary.Inside | ConstraintBoundary.AllowJustOutside | ConstraintBoundary.RadialInside | ConstraintBoundary.RadialAllowJustOutside;
private readonly ConstraintBoundary border = ConstraintBoundary.InsideBorder | ConstraintBoundary.OutsideBorder | ConstraintBoundary.RadialInsideBorder | ConstraintBoundary.RadialOutsideBorder;
private readonly ConstraintBoundary inner = ConstraintBoundary.Inside | ConstraintBoundary.InsideBorder | ConstraintBoundary.RadialInside | ConstraintBoundary.RadialInsideBorder;
private readonly ConstraintBoundary outter = ConstraintBoundary.AllowJustOutside | ConstraintBoundary.OutsideBorder | ConstraintBoundary.RadialAllowJustOutside | ConstraintBoundary.RadialOutsideBorder;
void Start()
{
// Get the size of the parent square sprite
parentRenderer = parent.GetComponent<SpriteRenderer>();
// Get the size of the constrained object sprite
thisRenderer = GetComponent<SpriteRenderer>();
}
// SEE MY OTHER ANSWERS UNDER "Unity constrain to bounds"
// FOR THE LATEUPDATE() IMPLEMENTATION + HELPER METHODS
// (script was too long for Grepper)
xxxxxxxxxx
// PART 2/2
// SEE MY OTHER GREPPER ANSWER UNDER "Unity constrain object to bounds" SEARCH
// FOR THE MONOBEHAVIOR SCRIPT
private Vector3 ProjectionConstraint(Vector3 position, float leftBound, float rightBound, float topBound, float bottomBound)
{
Vector3 altered = position;
if ((area & constraintType) == constraintType || isOutside)
{
altered.x = Mathf.Clamp(altered.x, leftBound, rightBound);
altered.y = Mathf.Clamp(altered.y, bottomBound, topBound);
return altered;
}
else
{
return LerpConstraint(parent.position, position, leftBound, rightBound, topBound, bottomBound);
}
}
private Vector3 LerpConstraint(Vector3 parentCenter, Vector3 unalteredPos, float leftBound, float rightBound, float topBound, float bottomBound)
{
// Calculate direction from child to parent center
Vector3 direction = (unalteredPos - parentCenter).normalized;
Vector3 intersectionPoint = Vector3.zero;
if ((area & constraintType) == constraintType && !isOutside)
{
return unalteredPos;
}
else
{
float halfWidth = (rightBound - leftBound) / 2f;
float halfHeight = (topBound - bottomBound) / 2f;
// Calculate the intersection point with the parent's bounds
if (Mathf.Abs(direction.x) * halfHeight > Mathf.Abs(direction.y) * halfWidth)
{
// Intersection with left or right side
intersectionPoint = new Vector3(direction.x > 0 ? halfWidth : -halfWidth, direction.y * halfWidth / Mathf.Abs(direction.x), 0);
}
else
{
// Intersection with top or bottom side
intersectionPoint = new Vector3(direction.x * halfHeight / Mathf.Abs(direction.y), direction.y > 0 ? halfHeight : -halfHeight, 0);
}
// Adjust the intersection point back to world coordinates
intersectionPoint += parent.position;
Vector3 altered = new(intersectionPoint.x, intersectionPoint.y, transform.position.z);
return altered;
}
}
}