添加插件

This commit is contained in:
2025-11-10 00:08:26 +08:00
parent 4059c207c0
commit 76f80db694
2814 changed files with 436400 additions and 178 deletions

View File

@@ -0,0 +1,155 @@
using UnityEngine;
namespace FIMSpace
{
/// <summary> V1.3.5
/// FM: Base class to hold calculations on colliders for fimpossible packages
/// </summary>
public abstract class FImp_ColliderData_Base
{
public Transform Transform { get; protected set; }
public Collider Collider { get; protected set; }
public Collider2D Collider2D { get; protected set; }
public bool Is2D = false;
public bool IsStatic { get; private set; }
public enum EFColliderType { Box, Sphere, Capsule, Mesh, Terrain }
public EFColliderType ColliderType { get; protected set; }
protected Vector3 previousPosition = Vector3.zero;
protected Quaternion previousRotation = Quaternion.identity;
protected Vector3 previousScale = Vector3.one;
/// <summary>
/// Generating class for given collider
/// </summary>
public static FImp_ColliderData_Base GetColliderDataFor(Collider collider)
{
SphereCollider s = collider as SphereCollider;
if (s)
return new FImp_ColliderData_Sphere(s);
else
{
CapsuleCollider c = collider as CapsuleCollider;
if (c)
return new FImp_ColliderData_Capsule(c);
else
{
BoxCollider b = collider as BoxCollider;
if (b)
return new FImp_ColliderData_Box(b);
else
{
MeshCollider m = collider as MeshCollider;
if (m)
return new FImp_ColliderData_Mesh(m);
else
{
TerrainCollider t = collider as TerrainCollider;
if (t)
return new FImp_ColliderData_Terrain(t);
else
{
CharacterController ch = collider as CharacterController;
if (ch)
return new FImp_ColliderData_CharacterCapsule(ch);
}
}
}
}
}
return null;
}
/// <summary>
/// Generating class for given collider
/// </summary>
public static FImp_ColliderData_Base GetColliderDataFor(Collider2D collider)
{
CircleCollider2D s = collider as CircleCollider2D;
if (s)
return new FImp_ColliderData_Sphere(s);
else
{
CapsuleCollider2D c = collider as CapsuleCollider2D;
if (c)
return new FImp_ColliderData_Capsule(c);
else
{
BoxCollider2D b = collider as BoxCollider2D;
if (b)
return new FImp_ColliderData_Box(b);
else
{
PolygonCollider2D m = collider as PolygonCollider2D;
if (m)
return new FImp_ColliderData_Mesh(m);
//else
//{
// EdgeCollider2D e = collider as EdgeCollider2D;
// if (e)
// return new FImp_ColliderData_Mesh(e);
// else
// {
// TilemapCollider2D t = collider as TilemapCollider2D;
// if (t)
// return new FImp_ColliderData_Mesh(t);
// else
// {
// CompositeCollider2D cps = collider as CompositeCollider2D;
// if (cps)
// return new FImp_ColliderData_Mesh(cps);
// }
// }
//}
}
}
}
return null;
}
/// <summary>
/// When collider moves / rotates / scales this method should be called
/// </summary>
public virtual void RefreshColliderData()
{
if (Transform.gameObject.isStatic) IsStatic = true; else IsStatic = false;
}
/// <summary>
/// Detecting if given point (sphere) is inside collider or colliding with (for mesh collider)
/// and projecting it onto collider's surface
/// </summary>
/// <param name="point"> Position of colliding sphere which will be pushed out </param>
/// <param name="pointRadius"> Radius of colliding sphere </param>
/// <param name="pointOffset"> Offset in position of colliding sphere </param>
/// <returns></returns>
public virtual bool PushIfInside(ref Vector3 point, float pointRadius, Vector3 pointOffset)
{
if ( Collider as SphereCollider )
Debug.Log("It shouldn't appear");
return false;
}
/// <summary>
/// If not implemented 3D algorithm will be applied
/// </summary>
public virtual bool PushIfInside2D(ref Vector3 point, float pointRadius, Vector3 pointOffset)
{
return PushIfInside(ref point, pointRadius, pointOffset);
}
public static bool VIsSame(Vector3 vec1, Vector3 vec2)
{
if (vec1.x != vec2.x) return false; if (vec1.y != vec2.y) return false; if (vec1.z != vec2.z) return false; return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2eae3be7652c13f4badbace952b305ea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,719 @@
using UnityEngine;
namespace FIMSpace
{
public class FImp_ColliderData_Box : FImp_ColliderData_Base
{
public BoxCollider Box { get; private set; }
public BoxCollider2D Box2D { get; private set; }
private Vector3 boxCenter;
private Vector3 right;
private Vector3 up;
private Vector3 forward;
private Vector3 rightN;
private Vector3 upN;
private Vector3 forwardN;
private Vector3 scales;
// For 3D
public FImp_ColliderData_Box(BoxCollider collider)
{
Is2D = false;
Collider = collider;
Transform = collider.transform;
Box = collider;
ColliderType = EFColliderType.Box;
RefreshColliderData();
previousPosition = Transform.position + Vector3.forward * Mathf.Epsilon;
}
// For 2D
public FImp_ColliderData_Box(BoxCollider2D collider2D)
{
Is2D = true;
Collider2D = collider2D;
Transform = collider2D.transform;
Box2D = collider2D;
ColliderType = EFColliderType.Box;
RefreshColliderData();
previousPosition = Transform.position + Vector3.forward * Mathf.Epsilon;
}
#region Refreshing Data
public override void RefreshColliderData()
{
if (IsStatic) return; // No need to refresh collider data if it is static
if (Collider2D == null) // 3D Refresh
{
bool diff = false;
if (!FEngineering.VIsSame(Transform.position, previousPosition)) diff = true;
else
if (!FEngineering.QIsSame(Transform.rotation, previousRotation)) diff = true;
if (diff)
{
right = Box.transform.TransformVector((Vector3.right / 2f) * Box.size.x);
up = Box.transform.TransformVector((Vector3.up / 2f) * Box.size.y);
forward = Box.transform.TransformVector((Vector3.forward / 2f) * Box.size.z);
rightN = right.normalized;
upN = up.normalized;
forwardN = forward.normalized;
boxCenter = GetBoxCenter(Box);
scales = Vector3.Scale(Box.size, Box.transform.lossyScale);
scales.Normalize();
}
}
else // 2D Refresh
{
bool diff = false;
if (Vector2.Distance(Transform.position, previousPosition) > Mathf.Epsilon) { diff = true; }
else
if (!FEngineering.QIsSame(Transform.rotation, previousRotation)) { diff = true; }
if (diff)
{
right = Box2D.transform.TransformVector((Vector3.right / 2f) * Box2D.size.x);
up = Box2D.transform.TransformVector((Vector3.up / 2f) * Box2D.size.y);
rightN = right.normalized;
upN = up.normalized;
boxCenter = GetBoxCenter(Box2D);
boxCenter.z = 0f;
Vector3 scale = Transform.lossyScale; scale.z = 1f;
scales = Vector3.Scale(Box2D.size, scale);
scales.Normalize();
}
}
base.RefreshColliderData();
previousPosition = Transform.position;
previousRotation = Transform.rotation;
}
#endregion
public override bool PushIfInside(ref Vector3 segmentPosition, float segmentRadius, Vector3 segmentOffset)
{
int inOrInt = 0;
Vector3 interPlane = Vector3.zero;
Vector3 segmentOffsetted = segmentPosition + segmentOffset;
float planeDistance = PlaneDistance(boxCenter + up, upN, segmentOffsetted);
if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = up; }
planeDistance = PlaneDistance(boxCenter - up, -upN, segmentOffsetted);
if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = -up; }
planeDistance = PlaneDistance(boxCenter - right, -rightN, segmentOffsetted);
if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = -right; }
planeDistance = PlaneDistance(boxCenter + right, rightN, segmentOffsetted);
if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = right; }
bool insideOrIntersects = false;
if (Collider2D == null)
{
planeDistance = PlaneDistance(boxCenter + forward, forwardN, segmentOffsetted);
if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = forward; }
planeDistance = PlaneDistance(boxCenter - forward, -forwardN, segmentOffsetted);
if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = -forward; }
if (inOrInt == 6) insideOrIntersects = true;
}
else if (inOrInt == 4) insideOrIntersects = true;
if (insideOrIntersects)
{
bool inside = false;
//Vector3 rayDirection;
if (interPlane.sqrMagnitude == 0f) // sphere is inside the box
{
//if ( Collider2D == null)
// interPlane = -GetTargetPlaneNormal(Box, segmentOffsetted, right, up, forward, scales);
//else
// interPlane = -GetTargetPlaneNormal(Box2D, segmentOffsetted, right, up, scales);
inside = true;
//rayDirection = (interPlane).normalized; // poprawić przy przeskalowanych boxach
}
else // sphere is intersecting box
{
//rayDirection = (segmentOffsetted - boxCenter).normalized;
if (Collider2D == null)
{ if (IsInsideBoxCollider(Box, segmentOffsetted)) inside = true; }
else if (IsInsideBoxCollider(Box2D, segmentOffsetted)) inside = true;
}
Vector3 pointOnPlane = GetNearestPoint(segmentOffsetted);
Vector3 toNormal = pointOnPlane - segmentOffsetted;
if (inside) toNormal += toNormal.normalized * segmentRadius; else toNormal -= toNormal.normalized * segmentRadius;
//Debug.DrawRay(pointOnPlane, toNormal);
if (inside)
{
segmentPosition = segmentPosition + toNormal;
}
else
if (toNormal.sqrMagnitude > 0) segmentPosition = segmentPosition + toNormal;
return true;
}
return false;
}
public static void PushOutFromBoxCollider(BoxCollider box, Collision collision, float segmentColliderRadius, ref Vector3 segmentPosition, bool is2D = false)
{
Vector3 right = box.transform.TransformVector((Vector3.right / 2f) * box.size.x + box.center.x * Vector3.right);
Vector3 up = box.transform.TransformVector((Vector3.up / 2f) * box.size.y + box.center.y * Vector3.up);
Vector3 forward = box.transform.TransformVector((Vector3.forward / 2f) * box.size.z + box.center.z * Vector3.forward);
Vector3 scales = Vector3.Scale(box.size, box.transform.lossyScale);
scales.Normalize();
PushOutFromBoxCollider(box, collision, segmentColliderRadius, ref segmentPosition, right, up, forward, scales, is2D);
}
public static void PushOutFromBoxCollider(BoxCollider box, float segmentColliderRadius, ref Vector3 segmentPosition, bool is2D = false)
{
Vector3 right = box.transform.TransformVector((Vector3.right / 2f) * box.size.x + box.center.x * Vector3.right);
Vector3 up = box.transform.TransformVector((Vector3.up / 2f) * box.size.y + box.center.y * Vector3.up);
Vector3 forward = box.transform.TransformVector((Vector3.forward / 2f) * box.size.z + box.center.z * Vector3.forward);
Vector3 scales = Vector3.Scale(box.size, box.transform.lossyScale);
scales.Normalize();
Vector3 boxCenter = GetBoxCenter(box);
float pointRadius = segmentColliderRadius;
Vector3 upN = up.normalized; Vector3 rightN = right.normalized; Vector3 forwardN = forward.normalized;
int inOrInt = 0;
Vector3 interPlane = Vector3.zero;
float planeDistance = PlaneDistance(boxCenter + up, upN, segmentPosition);
if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = up; }
planeDistance = PlaneDistance(boxCenter - up, -upN, segmentPosition);
if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = -up; }
planeDistance = PlaneDistance(boxCenter - right, -rightN, segmentPosition);
if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = -right; }
planeDistance = PlaneDistance(boxCenter + right, rightN, segmentPosition);
if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = right; }
planeDistance = PlaneDistance(boxCenter + forward, forwardN, segmentPosition);
if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = forward; }
planeDistance = PlaneDistance(boxCenter - forward, -forwardN, segmentPosition);
if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = -forward; }
// Collision occured - sphere intersecting box shape volume or is inside of it
if (inOrInt == 6)
{
bool inside = false;
//Vector3 rayDirection;
if (interPlane.sqrMagnitude == 0f) // sphere is inside the box
{
//interPlane = -GetTargetPlaneNormal(box, segmentPosition, right, up, forward, scales, is2D);
inside = true;
//rayDirection = (interPlane).normalized; // poprawić przy przeskalowanych boxach
}
else // sphere is intersecting box
{
//rayDirection = (segmentPosition - boxCenter).normalized;
if (IsInsideBoxCollider(box, segmentPosition)) inside = true;
}
Vector3 pointOnPlane = GetNearestPoint(segmentPosition, boxCenter, right, up, forward, is2D);
Vector3 toNormal = pointOnPlane - segmentPosition;
if (inside) toNormal += toNormal.normalized * pointRadius * 1.01f; else toNormal -= toNormal.normalized * pointRadius * 1.01f;
if (inside)
{
segmentPosition = segmentPosition + toNormal;
}
else
if (toNormal.sqrMagnitude > 0)
{
segmentPosition = segmentPosition + toNormal;
}
}
}
public static void PushOutFromBoxCollider(BoxCollider box, Collision collision, float segmentColliderRadius, ref Vector3 pos, Vector3 right, Vector3 up, Vector3 forward, Vector3 scales, bool is2D = false)
{
Vector3 collisionPoint = collision.contacts[0].point;
Vector3 pushNormal = pos - collisionPoint;
Vector3 boxCenter = GetBoxCenter(box);
if (pushNormal.sqrMagnitude == 0f) pushNormal = pos - boxCenter;
float insideMul = 1f;
if (IsInsideBoxCollider(box, pos))
{
// Finding intersection point on the box from the inside
float castFactor = GetBoxAverageScale(box);
Vector3 fittingNormal = GetTargetPlaneNormal(box, pos, right, up, forward, scales);
Vector3 fittingNormalNorm = fittingNormal.normalized;
RaycastHit info;
// Doing cheap boxCollider's raycast from outside to hit surface
if (box.Raycast(new Ray(pos - fittingNormalNorm * castFactor * 3f, fittingNormalNorm), out info, castFactor * 4))
{
collisionPoint = info.point;
}
else
collisionPoint = GetIntersectOnBoxFromInside(box, boxCenter, pos, fittingNormal);
pushNormal = collisionPoint - pos;
insideMul = 100f;
}
Vector3 toNormal = pos - ((pushNormal / insideMul + pushNormal.normalized * 1.15f) / 2f) * (segmentColliderRadius);
toNormal = collisionPoint - toNormal;
float pushMagn = toNormal.sqrMagnitude;
if (pushMagn > 0 && pushMagn < segmentColliderRadius * segmentColliderRadius * insideMul) pos = pos + toNormal;
}
#region Push out from box 2D
public static void PushOutFromBoxCollider(BoxCollider2D box2D, float segmentColliderRadius, ref Vector3 segmentPosition)
{
Vector2 right = box2D.transform.TransformVector((Vector3.right / 2f) * box2D.size.x + box2D.offset.x * Vector3.right);
Vector2 up = box2D.transform.TransformVector((Vector3.up / 2f) * box2D.size.y + box2D.offset.y * Vector3.up);
Vector3 scale2D = box2D.transform.lossyScale; scale2D.z = 1f;
Vector2 scales = Vector3.Scale(box2D.size, scale2D);
scales.Normalize();
Vector2 boxCenter = GetBoxCenter(box2D);
float pointRadius = segmentColliderRadius;
Vector2 upN = up.normalized; Vector2 rightN = right.normalized;
int inOrInt = 0;
Vector3 interPlane = Vector3.zero;
float planeDistance = PlaneDistance(boxCenter + up, upN, segmentPosition);
if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = up; }
planeDistance = PlaneDistance(boxCenter - up, -upN, segmentPosition);
if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = -up; }
planeDistance = PlaneDistance(boxCenter - right, -rightN, segmentPosition);
if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = -right; }
planeDistance = PlaneDistance(boxCenter + right, rightN, segmentPosition);
if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = right; }
// Collision occured - sphere intersecting box shape volume or is inside of it
if (inOrInt == 4)
{
bool inside = false;
if (interPlane.sqrMagnitude == 0f) // sphere is inside the box
{
//interPlane = -GetTargetPlaneNormal(box2D, segmentPosition, right, up, scales);
inside = true;
}
else // sphere is intersecting box
{
if (IsInsideBoxCollider(box2D, segmentPosition)) inside = true;
}
Vector3 pointOnPlane = GetNearestPoint2D(segmentPosition, boxCenter, right, up);
Vector3 toNormal = pointOnPlane - segmentPosition;
if (inside) toNormal += toNormal.normalized * pointRadius * 1.01f; else toNormal -= toNormal.normalized * pointRadius * 1.01f;
if (inside)
segmentPosition = segmentPosition + toNormal;
else
if (toNormal.sqrMagnitude > 0) segmentPosition = segmentPosition + toNormal;
}
}
#endregion
#region Box Calculations Helpers
/// <summary>
/// Getting nearest plane normal fitting to given point position
/// </summary>
private Vector3 GetNearestPoint(Vector3 point)
{
Vector3 pointOnBox = point;
Vector3 distancesPositive = Vector3.one;
distancesPositive.x = PlaneDistance(boxCenter + right, rightN, point);
distancesPositive.y = PlaneDistance(boxCenter + up, upN, point);
if (Collider2D == null) distancesPositive.z = PlaneDistance(boxCenter + forward, forwardN, point);
Vector3 distancesNegative = Vector3.one;
distancesNegative.x = PlaneDistance(boxCenter - right, -rightN, point);
distancesNegative.y = PlaneDistance(boxCenter - up, -upN, point);
if (Collider2D == null) distancesNegative.z = PlaneDistance(boxCenter - forward, -forwardN, point);
float nearestX, nearestY, nearestZ;
float negX = 1f, negY = 1f, negZ = 1f;
if (distancesPositive.x > distancesNegative.x) { nearestX = distancesPositive.x; negX = -1f; } else { nearestX = distancesNegative.x; negX = 1f; }
if (distancesPositive.y > distancesNegative.y) { nearestY = distancesPositive.y; negY = -1f; } else { nearestY = distancesNegative.y; negY = 1f; }
if (Collider2D == null)
{
if (distancesPositive.z > distancesNegative.z) { nearestZ = distancesPositive.z; negZ = -1f; } else { nearestZ = distancesNegative.z; negZ = 1f; }
if (nearestX > nearestZ)
{
if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
else
pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
}
else
{
if (nearestZ > nearestY) { pointOnBox = ProjectPointOnPlane(forward * negZ, point, nearestZ); }
else
pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
}
}
else
{
if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
else
pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
}
return pointOnBox;
}
/// <summary>
/// Getting nearest plane normal fitting to given point position
/// </summary>
private static Vector3 GetNearestPoint(Vector3 point, Vector3 boxCenter, Vector3 right, Vector3 up, Vector3 forward, bool is2D = false)
{
Vector3 pointOnBox = point;
Vector3 distancesPositive = Vector3.one;
distancesPositive.x = PlaneDistance(boxCenter + right, right.normalized, point);
distancesPositive.y = PlaneDistance(boxCenter + up, up.normalized, point);
if (is2D == false) distancesPositive.z = PlaneDistance(boxCenter + forward, forward.normalized, point);
Vector3 distancesNegative = Vector3.one;
distancesNegative.x = PlaneDistance(boxCenter - right, -right.normalized, point);
distancesNegative.y = PlaneDistance(boxCenter - up, -up.normalized, point);
if (is2D == false) distancesNegative.z = PlaneDistance(boxCenter - forward, -forward.normalized, point);
float nearestX, nearestY, nearestZ;
float negX = 1f, negY = 1f, negZ = 1f;
if (distancesPositive.x > distancesNegative.x) { nearestX = distancesPositive.x; negX = -1f; } else { nearestX = distancesNegative.x; negX = 1f; }
if (distancesPositive.y > distancesNegative.y) { nearestY = distancesPositive.y; negY = -1f; } else { nearestY = distancesNegative.y; negY = 1f; }
if (is2D == false)
{
if (distancesPositive.z > distancesNegative.z) { nearestZ = distancesPositive.z; negZ = -1f; } else { nearestZ = distancesNegative.z; negZ = 1f; }
if (nearestX > nearestZ)
{
if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
else
pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
}
else
{
if (nearestZ > nearestY) { pointOnBox = ProjectPointOnPlane(forward * negZ, point, nearestZ); }
else
pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
}
}
else
{
if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
else
pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
}
return pointOnBox;
}
/// <summary>
/// Getting nearest plane normal fitting to given point position
/// </summary>
private static Vector3 GetNearestPoint2D(Vector2 point, Vector2 boxCenter, Vector2 right, Vector2 up)
{
Vector3 pointOnBox = point;
Vector3 distancesPositive = Vector3.one;
distancesPositive.x = PlaneDistance(boxCenter + right, right.normalized, point);
distancesPositive.y = PlaneDistance(boxCenter + up, up.normalized, point);
Vector3 distancesNegative = Vector3.one;
distancesNegative.x = PlaneDistance(boxCenter - right, -right.normalized, point);
distancesNegative.y = PlaneDistance(boxCenter - up, -up.normalized, point);
float nearestX, nearestY;
float negX = 1f, negY = 1f;
if (distancesPositive.x > distancesNegative.x) { nearestX = distancesPositive.x; negX = -1f; } else { nearestX = distancesNegative.x; negX = 1f; }
if (distancesPositive.y > distancesNegative.y) { nearestY = distancesPositive.y; negY = -1f; } else { nearestY = distancesNegative.y; negY = 1f; }
if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
else
pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
return pointOnBox;
}
/// <summary>
/// Getting nearest plane point on box collider
/// </summary>
public static Vector3 GetNearestPointOnBox(BoxCollider boxCollider, Vector3 point, bool is2D = false)
{
Vector3 right = boxCollider.transform.TransformVector(Vector3.right / 2f);
Vector3 up = boxCollider.transform.TransformVector(Vector3.up / 2f);
Vector3 forward = Vector3.forward; if (is2D == false) forward = boxCollider.transform.TransformVector(Vector3.forward / 2f);
Vector3 pointOnBox = point;
Vector3 center = GetBoxCenter(boxCollider);
Vector3 rightN = right.normalized;
Vector3 upN = up.normalized;
Vector3 forwardN = forward.normalized;
Vector3 distancesPositive = Vector3.one;
distancesPositive.x = PlaneDistance(center + right, rightN, point);
distancesPositive.y = PlaneDistance(center + up, upN, point);
if (is2D == false) distancesPositive.z = PlaneDistance(center + forward, forwardN, point);
Vector3 distancesNegative = Vector3.one;
distancesNegative.x = PlaneDistance(center - right, -rightN, point);
distancesNegative.y = PlaneDistance(center - up, -upN, point);
if (is2D == false) distancesNegative.z = PlaneDistance(center - forward, -forwardN, point);
float nearestX, nearestY, nearestZ;
float negX = 1f, negY = 1f, negZ = 1f;
if (distancesPositive.x > distancesNegative.x) { nearestX = distancesPositive.x; negX = -1f; } else { nearestX = distancesNegative.x; negX = 1f; }
if (distancesPositive.y > distancesNegative.y) { nearestY = distancesPositive.y; negY = -1f; } else { nearestY = distancesNegative.y; negY = 1f; }
if (is2D == false)
{
if (distancesPositive.z > distancesNegative.z) { nearestZ = distancesPositive.z; negZ = -1f; } else { nearestZ = distancesNegative.z; negZ = 1f; }
if (nearestX > nearestZ)
{
if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
else
pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
}
else
{
if (nearestZ > nearestY) { pointOnBox = ProjectPointOnPlane(forward * negZ, point, nearestZ); }
else
pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
}
}
else
{
if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
else
pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
}
return pointOnBox;
}
private static float PlaneDistance(Vector3 planeCenter, Vector3 planeNormal, Vector3 point)
{
return Vector3.Dot(point - planeCenter, planeNormal);
}
private static Vector3 ProjectPointOnPlane(Vector3 planeNormal, Vector3 point, float distance)
{
Vector3 translationVector = planeNormal.normalized * distance;
return point + translationVector;
}
private static bool SphereInsidePlane(float planeDistance, float pointRadius) { return -planeDistance > pointRadius; }
private static bool SphereOutsidePlane(float planeDistance, float pointRadius) { return planeDistance > pointRadius; }
private static bool SphereIntersectsPlane(float planeDistance, float pointRadius) { return Mathf.Abs(planeDistance) <= pointRadius; }
public static bool IsInsideBoxCollider(BoxCollider collider, Vector3 point, bool is2D = false)
{
point = collider.transform.InverseTransformPoint(point) - collider.center;
float xExtend = (collider.size.x * 0.5f);
float yExtend = (collider.size.y * 0.5f);
float zExtend = (collider.size.z * 0.5f);
return (point.x < xExtend && point.x > -xExtend && point.y < yExtend && point.y > -yExtend && point.z < zExtend && point.z > -zExtend);
}
// 2D Version
public static bool IsInsideBoxCollider(BoxCollider2D collider, Vector3 point)
{
point = (Vector2)collider.transform.InverseTransformPoint(point) - collider.offset;
float xExtend = (collider.size.x * 0.5f);
float yExtend = (collider.size.y * 0.5f);
return (point.x < xExtend && point.x > -xExtend && point.y < yExtend && point.y > -yExtend);
}
/// <summary>
/// Getting average scale of box's dimensions
/// </summary>
protected static float GetBoxAverageScale(BoxCollider box)
{
Vector3 scales = box.transform.lossyScale;
scales = Vector3.Scale(scales, box.size);
return (scales.x + scales.y + scales.z) / 3f;
}
protected static Vector3 GetBoxCenter(BoxCollider box)
{
return box.transform.position + box.transform.TransformVector(box.center);
}
protected static Vector3 GetBoxCenter(BoxCollider2D box)
{
return box.transform.position + box.transform.TransformVector(box.offset);
}
protected static Vector3 GetTargetPlaneNormal(BoxCollider boxCollider, Vector3 point, bool is2D = false)
{
Vector3 right = boxCollider.transform.TransformVector((Vector3.right / 2f) * boxCollider.size.x);
Vector3 up = boxCollider.transform.TransformVector((Vector3.up / 2f) * boxCollider.size.y);
Vector3 forward = Vector3.forward; if (is2D == false) forward = boxCollider.transform.TransformVector((Vector3.forward / 2f) * boxCollider.size.z);
Vector3 scales = Vector3.Scale(boxCollider.size, boxCollider.transform.lossyScale);
scales.Normalize();
return GetTargetPlaneNormal(boxCollider, point, right, up, forward, scales, is2D);
}
/// <summary>
/// Getting nearest plane normal fitting to given point position
/// </summary>
protected static Vector3 GetTargetPlaneNormal(BoxCollider boxCollider, Vector3 point, Vector3 right, Vector3 up, Vector3 forward, Vector3 scales, bool is2D = false)
{
Vector3 rayDirection = (GetBoxCenter(boxCollider) - point).normalized;
// Finding proper box's plane
Vector3 dots;
dots.x = Vector3.Dot(rayDirection, right.normalized);
dots.y = Vector3.Dot(rayDirection, up.normalized);
dots.x = dots.x * scales.y * scales.z;
dots.y = dots.y * scales.x * scales.z;
if (is2D == false)
{
dots.z = Vector3.Dot(rayDirection, forward.normalized);
dots.z = dots.z * scales.y * scales.x;
}
else dots.z = 0;
dots.Normalize();
Vector3 dotsAbs = dots;
if (dots.x < 0) dotsAbs.x = -dots.x;
if (dots.y < 0) dotsAbs.y = -dots.y;
if (dots.z < 0) dotsAbs.z = -dots.z;
Vector3 planeNormal;
if (dotsAbs.x > dotsAbs.y)
{
if (dotsAbs.x > dotsAbs.z || is2D) planeNormal = right * Mathf.Sign(dots.x); else planeNormal = forward * Mathf.Sign(dots.z);
}
else
{
if (dotsAbs.y > dotsAbs.z || is2D) planeNormal = up * Mathf.Sign(dots.y); else planeNormal = forward * Mathf.Sign(dots.z);
}
return planeNormal;
}
// 2D Version
protected static Vector3 GetTargetPlaneNormal(BoxCollider2D boxCollider, Vector2 point, Vector2 right, Vector2 up, Vector2 scales)
{
Vector2 rayDirection = ((Vector2)GetBoxCenter(boxCollider) - point).normalized;
// Finding proper box's plane
Vector2 dots;
dots.x = Vector3.Dot(rayDirection, right.normalized);
dots.y = Vector3.Dot(rayDirection, up.normalized);
dots.x = dots.x * scales.y;
dots.y = dots.y * scales.x;
dots.Normalize();
Vector2 dotsAbs = dots;
if (dots.x < 0) dotsAbs.x = -dots.x;
if (dots.y < 0) dotsAbs.y = -dots.y;
Vector3 planeNormal;
if (dotsAbs.x > dotsAbs.y) planeNormal = right * Mathf.Sign(dots.x);
else
planeNormal = up * Mathf.Sign(dots.y);
return planeNormal;
}
/// <summary>
/// Calculating cheap ray on box plane to detect position from inside
/// </summary>
protected static Vector3 GetIntersectOnBoxFromInside(BoxCollider boxCollider, Vector3 from, Vector3 to, Vector3 planeNormal)
{
Vector3 rayDirection = (to - from);
// Creating box's plane and casting cheap ray on it to detect intersection position
Plane plane = new Plane(-planeNormal, GetBoxCenter(boxCollider) + planeNormal);
Vector3 intersectionPoint = to;
float enter = 0f;
Ray ray = new Ray(from, rayDirection);
if (plane.Raycast(ray, out enter)) intersectionPoint = ray.GetPoint(enter);
return intersectionPoint;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2d88eaa8955b2dd4fa35f5005531a210
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,241 @@
using UnityEngine;
namespace FIMSpace
{
public class FImp_ColliderData_Capsule : FImp_ColliderData_Base
{
public CapsuleCollider Capsule { get; private set; }
public CapsuleCollider2D Capsule2D { get; private set; }
private Vector3 Top;
private Vector3 Bottom;
private Vector3 Direction;
private float radius;
private float scaleFactor;
private float preRadius;
public FImp_ColliderData_Capsule(CapsuleCollider collider)
{
Is2D = false;
Transform = collider.transform;
Collider = collider;
Transform = collider.transform;
Capsule = collider;
ColliderType = EFColliderType.Capsule;
CalculateCapsuleParameters(Capsule, ref Direction, ref radius, ref scaleFactor);
RefreshColliderData();
}
public FImp_ColliderData_Capsule(CapsuleCollider2D collider)
{
Is2D = true;
Transform = collider.transform;
Collider2D = collider;
Transform = collider.transform;
Capsule2D = collider;
ColliderType = EFColliderType.Capsule;
CalculateCapsuleParameters(Capsule2D, ref Direction, ref radius, ref scaleFactor);
RefreshColliderData();
}
public override void RefreshColliderData()
{
if (IsStatic) return; // No need to refresh collider data if it is static
bool diff = false;
if (!FEngineering.VIsSame(previousPosition, Transform.position)) diff = true;
else
if (!FEngineering.QIsSame(Transform.rotation, previousRotation)) diff = true;
else
{
if (Is2D == false)
{
if (preRadius != Capsule.radius || !FEngineering.VIsSame(previousScale, Transform.lossyScale))
CalculateCapsuleParameters(Capsule, ref Direction, ref radius, ref scaleFactor);
}
else
{
if (preRadius != GetCapsule2DRadius(Capsule2D) || !FEngineering.VIsSame(previousScale, Transform.lossyScale))
CalculateCapsuleParameters(Capsule2D, ref Direction, ref radius, ref scaleFactor);
}
}
if (diff)
{
if (Is2D == false)
GetCapsuleHeadsPositions(Capsule, ref Top, ref Bottom, Direction, radius, scaleFactor);
else
GetCapsuleHeadsPositions(Capsule2D, ref Top, ref Bottom, Direction, radius, scaleFactor);
}
base.RefreshColliderData();
previousPosition = Transform.position;
previousRotation = Transform.rotation;
previousScale = Transform.lossyScale;
if (Is2D == false) preRadius = Capsule.radius; else preRadius = GetCapsule2DRadius(Capsule2D);
}
public override bool PushIfInside(ref Vector3 point, float pointRadius, Vector3 pointOffset)
{
return PushOutFromCapsuleCollider(pointRadius, ref point, Top, Bottom, radius, pointOffset, Is2D);
}
public static bool PushOutFromCapsuleCollider(CapsuleCollider capsule, float segmentColliderRadius, ref Vector3 pos, Vector3 segmentOffset)
{
Vector3 direction = Vector3.zero; float capsuleRadius = capsule.radius, scalerFactor = 1f;
CalculateCapsuleParameters(capsule, ref direction, ref capsuleRadius, ref scalerFactor);
Vector3 up = Vector3.zero, bottom = Vector3.zero;
GetCapsuleHeadsPositions(capsule, ref up, ref bottom, direction, capsuleRadius, scalerFactor);
return PushOutFromCapsuleCollider(segmentColliderRadius, ref pos, up, bottom, capsuleRadius, segmentOffset);
}
public static bool PushOutFromCapsuleCollider(float segmentColliderRadius, ref Vector3 segmentPos, Vector3 capSphereCenter1, Vector3 capSphereCenter2, float capsuleRadius, Vector3 segmentOffset, bool is2D = false)
{
float radius = capsuleRadius + segmentColliderRadius;
Vector3 capsuleUp = capSphereCenter2 - capSphereCenter1;
Vector3 fromCenter = (segmentPos + segmentOffset) - capSphereCenter1;
if (is2D)
{
capsuleUp.z = 0;
fromCenter.z = 0;
}
float orientationDot = Vector3.Dot(fromCenter, capsuleUp);
if (orientationDot <= 0) // Main Sphere Cap
{
float sphereRefDistMagn = fromCenter.sqrMagnitude;
if (sphereRefDistMagn > 0 && sphereRefDistMagn < radius * radius)
{
segmentPos = capSphereCenter1 - segmentOffset + fromCenter * (radius / Mathf.Sqrt(sphereRefDistMagn));
return true;
}
}
else
{
float upRefMagn = capsuleUp.sqrMagnitude;
if (orientationDot >= upRefMagn) // Counter Sphere Cap
{
fromCenter = (segmentPos + segmentOffset) - capSphereCenter2;
float sphereRefDistMagn = fromCenter.sqrMagnitude;
if (sphereRefDistMagn > 0 && sphereRefDistMagn < radius * radius)
{
segmentPos = capSphereCenter2 - segmentOffset + fromCenter * (radius / Mathf.Sqrt(sphereRefDistMagn));
return true;
}
}
else if (upRefMagn > 0) // Cylinder Volume
{
fromCenter -= capsuleUp * (orientationDot / upRefMagn);
float sphericalRefDistMagn = fromCenter.sqrMagnitude;
if (sphericalRefDistMagn > 0 && sphericalRefDistMagn < radius * radius)
{
float projectedDistance = Mathf.Sqrt(sphericalRefDistMagn);
segmentPos += fromCenter * ((radius - projectedDistance) / projectedDistance);
return true;
}
}
}
return false;
}
#region Capsule Calculations Helpers
/// <summary>
/// Calculating capsule's centers of up and down sphere which are fitting unity capsule collider with all collider's transformations
/// </summary>
protected static void CalculateCapsuleParameters(CapsuleCollider capsule, ref Vector3 direction, ref float trueRadius, ref float scalerFactor)
{
Transform cTransform = capsule.transform;
float radiusScaler;
if (capsule.direction == 1)
{ /* Y */
direction = Vector3.up; scalerFactor = cTransform.lossyScale.y;
radiusScaler = cTransform.lossyScale.x > cTransform.lossyScale.z ? cTransform.lossyScale.x : cTransform.lossyScale.z;
}
else if (capsule.direction == 0)
{ /* X */
direction = Vector3.right; scalerFactor = cTransform.lossyScale.x;
radiusScaler = cTransform.lossyScale.y > cTransform.lossyScale.z ? cTransform.lossyScale.y : cTransform.lossyScale.z;
}
else
{ /* Z */
direction = Vector3.forward; scalerFactor = cTransform.lossyScale.z;
radiusScaler = cTransform.lossyScale.y > cTransform.lossyScale.x ? cTransform.lossyScale.y : cTransform.lossyScale.x;
}
trueRadius = capsule.radius * radiusScaler;
}
private static float GetCapsule2DRadius(CapsuleCollider2D capsule)
{
if (capsule.direction == CapsuleDirection2D.Vertical)
return capsule.size.x / 2f;
else
return capsule.size.y / 2f;
}
private static float GetCapsule2DHeight(CapsuleCollider2D capsule)
{
if (capsule.direction == CapsuleDirection2D.Vertical)
return capsule.size.y / 2f;
else
return capsule.size.x / 2f;
}
protected static void CalculateCapsuleParameters(CapsuleCollider2D capsule, ref Vector3 direction, ref float trueRadius, ref float scalerFactor)
{
Transform cTransform = capsule.transform;
float radiusScaler;
if (capsule.direction == CapsuleDirection2D.Vertical)
{ /* Y */
direction = Vector3.up; scalerFactor = cTransform.lossyScale.y;
radiusScaler = cTransform.lossyScale.x > cTransform.lossyScale.z ? cTransform.lossyScale.x : cTransform.lossyScale.z;
trueRadius = (capsule.size.x / 2f) * radiusScaler;
}
else if (capsule.direction == CapsuleDirection2D.Horizontal)
{ /* X */
direction = Vector3.right; scalerFactor = cTransform.lossyScale.x;
radiusScaler = cTransform.lossyScale.y > cTransform.lossyScale.z ? cTransform.lossyScale.y : cTransform.lossyScale.z;
trueRadius = (capsule.size.y / 2f) * radiusScaler;
}
}
protected static void GetCapsuleHeadsPositions(CapsuleCollider capsule, ref Vector3 upper, ref Vector3 bottom, Vector3 direction, float radius, float scalerFactor)
{
Vector3 upCapCenter = direction * ((capsule.height / 2) * scalerFactor - radius); // Local Space Position
upper = capsule.transform.position + capsule.transform.TransformDirection(upCapCenter) + capsule.transform.TransformVector(capsule.center); // World Space
Vector3 downCapCenter = -direction * ((capsule.height / 2) * scalerFactor - radius);
bottom = capsule.transform.position + capsule.transform.TransformDirection(downCapCenter) + capsule.transform.TransformVector(capsule.center);
}
protected static void GetCapsuleHeadsPositions(CapsuleCollider2D capsule, ref Vector3 upper, ref Vector3 bottom, Vector3 direction, float radius, float scalerFactor)
{
Vector3 upCapCenter = direction * (GetCapsule2DHeight(capsule) * scalerFactor - radius); // Local Space Position
upper = capsule.transform.position + capsule.transform.TransformDirection(upCapCenter) + capsule.transform.TransformVector(capsule.offset); // World Space
upper.z = 0f;
Vector3 downCapCenter = -direction * (GetCapsule2DHeight(capsule) * scalerFactor - radius);
bottom = capsule.transform.position + capsule.transform.TransformDirection(downCapCenter) + capsule.transform.TransformVector(capsule.offset);
bottom.z = 0f;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3ffcc9ee773aad94b9214d78942d8fd4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,141 @@
using UnityEngine;
namespace FIMSpace
{
public class FImp_ColliderData_CharacterCapsule : FImp_ColliderData_Base
{
public CharacterController Capsule { get; private set; }
private Vector3 Top;
private Vector3 Bottom;
private Vector3 Direction;
private float radius;
private float scaleFactor;
private float preRadius;
public FImp_ColliderData_CharacterCapsule(CharacterController collider)
{
Is2D = false;
Transform = collider.transform;
Collider = collider;
Transform = collider.transform;
Capsule = collider;
ColliderType = EFColliderType.Capsule;
CalculateCapsuleParameters(Capsule, ref Direction, ref radius, ref scaleFactor);
RefreshColliderData();
}
public override void RefreshColliderData()
{
if (IsStatic) return; // No need to refresh collider data if it is static
bool diff = false;
if (!FEngineering.VIsSame(previousPosition, Transform.position)) diff = true;
else
if (!FEngineering.QIsSame(Transform.rotation, previousRotation)) diff = true;
else
{
if (preRadius != Capsule.radius || !FEngineering.VIsSame(previousScale, Transform.lossyScale))
CalculateCapsuleParameters(Capsule, ref Direction, ref radius, ref scaleFactor);
}
if (diff)
{
GetCapsuleHeadsPositions(Capsule, ref Top, ref Bottom, Direction, radius, scaleFactor);
}
base.RefreshColliderData();
previousPosition = Transform.position;
previousRotation = Transform.rotation;
previousScale = Transform.lossyScale;
preRadius = Capsule.radius;
}
public override bool PushIfInside(ref Vector3 point, float pointRadius, Vector3 pointOffset)
{
return PushOutFromCapsuleCollider(pointRadius, ref point, Top, Bottom, radius, pointOffset, false);
}
public static bool PushOutFromCapsuleCollider(float segmentColliderRadius, ref Vector3 segmentPos, Vector3 capSphereCenter1, Vector3 capSphereCenter2, float capsuleRadius, Vector3 segmentOffset, bool is2D = false)
{
float radius = capsuleRadius + segmentColliderRadius;
Vector3 capsuleUp = capSphereCenter2 - capSphereCenter1;
Vector3 fromCenter = (segmentPos + segmentOffset) - capSphereCenter1;
float orientationDot = Vector3.Dot(fromCenter, capsuleUp);
if (orientationDot <= 0) // Main Sphere Cap
{
float sphereRefDistMagn = fromCenter.sqrMagnitude;
if (sphereRefDistMagn > 0 && sphereRefDistMagn < radius * radius)
{
segmentPos = capSphereCenter1 - segmentOffset + fromCenter * (radius / Mathf.Sqrt(sphereRefDistMagn));
return true;
}
}
else
{
float upRefMagn = capsuleUp.sqrMagnitude;
if (orientationDot >= upRefMagn) // Counter Sphere Cap
{
fromCenter = (segmentPos + segmentOffset) - capSphereCenter2;
float sphereRefDistMagn = fromCenter.sqrMagnitude;
if (sphereRefDistMagn > 0 && sphereRefDistMagn < radius * radius)
{
segmentPos = capSphereCenter2 - segmentOffset + fromCenter * (radius / Mathf.Sqrt(sphereRefDistMagn));
return true;
}
}
else if (upRefMagn > 0) // Cylinder Volume
{
fromCenter -= capsuleUp * (orientationDot / upRefMagn);
float sphericalRefDistMagn = fromCenter.sqrMagnitude;
if (sphericalRefDistMagn > 0 && sphericalRefDistMagn < radius * radius)
{
float projectedDistance = Mathf.Sqrt(sphericalRefDistMagn);
segmentPos += fromCenter * ((radius - projectedDistance) / projectedDistance);
return true;
}
}
}
return false;
}
#region Capsule Calculations Helpers
/// <summary>
/// Calculating capsule's centers of up and down sphere which are fitting unity capsule collider with all collider's transformations
/// </summary>
protected static void CalculateCapsuleParameters(CharacterController capsule, ref Vector3 direction, ref float trueRadius, ref float scalerFactor)
{
Transform cTransform = capsule.transform;
float radiusScaler;
direction = Vector3.up; scalerFactor = cTransform.lossyScale.y;
radiusScaler = cTransform.lossyScale.x > cTransform.lossyScale.z ? cTransform.lossyScale.x : cTransform.lossyScale.z;
trueRadius = capsule.radius * radiusScaler;
}
protected static void GetCapsuleHeadsPositions(CharacterController capsule, ref Vector3 upper, ref Vector3 bottom, Vector3 direction, float radius, float scalerFactor)
{
Vector3 upCapCenter = direction * ((capsule.height / 2) * scalerFactor - radius); // Local Space Position
upper = capsule.transform.position + capsule.transform.TransformDirection(upCapCenter) + capsule.transform.TransformVector(capsule.center); // World Space
Vector3 downCapCenter = -direction * ((capsule.height / 2) * scalerFactor - radius);
bottom = capsule.transform.position + capsule.transform.TransformDirection(downCapCenter) + capsule.transform.TransformVector(capsule.center);
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c29c49f32c3d59546973844bb3f495d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,235 @@
using UnityEngine;
namespace FIMSpace
{
public class FImp_ColliderData_Mesh : FImp_ColliderData_Base
{
public MeshCollider Mesh { get; private set; }
public PolygonCollider2D Poly2D { get; private set; }
private ContactFilter2D filter;
public FImp_ColliderData_Mesh(MeshCollider collider)
{
Is2D = false;
Transform = collider.transform;
Collider = collider;
Mesh = collider;
ColliderType = EFColliderType.Mesh;
}
public FImp_ColliderData_Mesh(PolygonCollider2D collider)
{
Is2D = true;
Transform = collider.transform;
Poly2D = collider;
Collider2D = collider;
ColliderType = EFColliderType.Mesh;
filter = new ContactFilter2D();
filter.useTriggers = false;
filter.useDepth = false;
r = new RaycastHit2D[1];
}
private RaycastHit2D[] r;
public override bool PushIfInside(ref Vector3 segmentPosition, float segmentRadius, Vector3 segmentOffset)
{
if (Is2D == false)
{
if (Mesh.convex)
{
Vector3 closest;
Vector3 positionOffsetted = segmentPosition + segmentOffset;
float castMul = 1f;
closest = Physics.ClosestPoint(positionOffsetted, Mesh, Mesh.transform.position, Mesh.transform.rotation);
if (Vector3.Distance(closest, positionOffsetted) > segmentRadius * 1.01f) return false;
Vector3 dir = (closest - positionOffsetted);
if (dir == Vector3.zero) return false;
RaycastHit meshHit;
Mesh.Raycast(new Ray(positionOffsetted, dir.normalized), out meshHit, segmentRadius * castMul);
if (meshHit.transform)
{
segmentPosition = meshHit.point + meshHit.normal * segmentRadius;
return true;
}
}
else
{
Vector3 closest;
float plus = 0f;
Vector3 positionOffsetted = segmentPosition + segmentOffset;
closest = Mesh.ClosestPointOnBounds(positionOffsetted);
plus = (closest - Mesh.transform.position).magnitude;
bool inside = false;
float insideMul = 1f;
if (closest == positionOffsetted)
{
inside = true;
insideMul = 7f;
closest = Mesh.transform.position;
}
Vector3 targeting = closest - positionOffsetted;
Vector3 rayDirection = targeting.normalized;
Vector3 rayOrigin = positionOffsetted - rayDirection * (segmentRadius * 2f + Mesh.bounds.extents.magnitude);
float rayDistance = targeting.magnitude + segmentRadius * 2f + plus + Mesh.bounds.extents.magnitude;
if ((positionOffsetted - closest).magnitude < segmentRadius * insideMul)
{
Ray ray = new Ray(rayOrigin, rayDirection);
RaycastHit hit;
if (Mesh.Raycast(ray, out hit, rayDistance))
{
float hitToPointDist = (positionOffsetted - hit.point).magnitude;
if (hitToPointDist < segmentRadius * insideMul)
{
Vector3 toNormal = hit.point - positionOffsetted;
Vector3 pushNormal;
if (inside) pushNormal = toNormal + toNormal.normalized * segmentRadius; else pushNormal = toNormal - toNormal.normalized * segmentRadius;
float dot = Vector3.Dot((hit.point - positionOffsetted).normalized, rayDirection);
if (inside && dot > 0f) pushNormal = toNormal - toNormal.normalized * segmentRadius;
segmentPosition = segmentPosition + pushNormal;
return true;
}
}
}
return false;
}
}
else
{
#if UNITY_2019_1_OR_NEWER
Vector2 positionOffsetted = segmentPosition + segmentOffset;
Vector2 closest;
if (Poly2D.OverlapPoint(positionOffsetted))
{
// Collider inside polygon collider!
Vector3 indir = Poly2D.bounds.center - (Vector3)positionOffsetted; indir.z = 0f;
Ray r = new Ray(Poly2D.bounds.center - indir * Poly2D.bounds.max.magnitude, indir);
float dist = 0f;
Poly2D.bounds.IntersectRay(r, out dist); // We've got partially correct point
if (dist > 0f)
closest = Poly2D.ClosestPoint(r.GetPoint(dist));
else
closest = Poly2D.ClosestPoint(positionOffsetted);
}
else
closest = Poly2D.ClosestPoint(positionOffsetted);
Vector2 dir = (closest - positionOffsetted).normalized;
int hits = Physics2D.Raycast(positionOffsetted, dir, filter, r, segmentRadius);
if (hits > 0)
{
if (r[0].transform == Transform)
{
segmentPosition = closest + r[0].normal * segmentRadius;
return true;
}
}
#else
return false;
#endif
}
return false;
}
public static void PushOutFromMeshCollider(MeshCollider mesh, Collision collision, float segmentColliderRadius, ref Vector3 pos)
{
Vector3 collisionPoint = collision.contacts[0].point;
Vector3 pushNormal = collision.contacts[0].normal;
RaycastHit info;
// Doing cheap mesh raycast from outside to hit surface
if (mesh.Raycast(new Ray(pos + pushNormal * segmentColliderRadius * 2f, -pushNormal), out info, segmentColliderRadius * 5))
{
pushNormal = info.point - pos;
float pushMagn = pushNormal.sqrMagnitude;
if (pushMagn > 0 && pushMagn < segmentColliderRadius * segmentColliderRadius) pos = info.point - pushNormal * (segmentColliderRadius / Mathf.Sqrt(pushMagn)) * 0.9f;
}
else
{
pushNormal = collisionPoint - pos;
float pushMagn = pushNormal.sqrMagnitude;
if (pushMagn > 0 && pushMagn < segmentColliderRadius * segmentColliderRadius) pos = collisionPoint - pushNormal * (segmentColliderRadius / Mathf.Sqrt(pushMagn)) * 0.9f;
}
}
public static void PushOutFromMesh(MeshCollider mesh, Collision collision, float pointRadius, ref Vector3 point)
{
Vector3 closest;
float plus = 0f;
closest = mesh.ClosestPointOnBounds(point);
plus = (closest - mesh.transform.position).magnitude;
bool inside = false;
float insideMul = 1f;
if (closest == point)
{
inside = true;
insideMul = 7f;
closest = mesh.transform.position;
}
Vector3 targeting = closest - point;
Vector3 rayDirection = targeting.normalized;
Vector3 rayOrigin = point - rayDirection * (pointRadius * 2f + mesh.bounds.extents.magnitude);
float rayDistance = targeting.magnitude + pointRadius * 2f + plus + mesh.bounds.extents.magnitude;
if ((point - closest).magnitude < pointRadius * insideMul)
{
Vector3 collisionPoint;
if (!inside)
collisionPoint = collision.contacts[0].point;
else
{
Ray ray = new Ray(rayOrigin, rayDirection);
RaycastHit hit;
if (mesh.Raycast(ray, out hit, rayDistance)) collisionPoint = hit.point; else collisionPoint = collision.contacts[0].point;
}
float hitToPointDist = (point - collisionPoint).magnitude;
if (hitToPointDist < pointRadius * insideMul)
{
Vector3 toNormal = collisionPoint - point;
Vector3 pushNormal;
if (inside) pushNormal = toNormal + toNormal.normalized * pointRadius; else pushNormal = toNormal - toNormal.normalized * pointRadius;
float dot = Vector3.Dot((collisionPoint - point).normalized, rayDirection);
if (inside && dot > 0f) pushNormal = toNormal - toNormal.normalized * pointRadius;
point = point + pushNormal;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bde60ae57f06f434ebd27fc9589b8ff7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,138 @@
using UnityEngine;
namespace FIMSpace
{
public class FImp_ColliderData_Sphere : FImp_ColliderData_Base
{
public SphereCollider Sphere { get; private set; }
public CircleCollider2D Sphere2D { get; private set; }
private float SphereRadius;
public FImp_ColliderData_Sphere(SphereCollider collider)
{
Is2D = false;
Transform = collider.transform;
Collider = collider;
Sphere = collider;
ColliderType = EFColliderType.Sphere;
RefreshColliderData();
}
public FImp_ColliderData_Sphere(CircleCollider2D collider)
{
Is2D = true;
Transform = collider.transform;
Collider2D = collider;
Sphere2D = collider;
ColliderType = EFColliderType.Sphere;
RefreshColliderData();
}
public override void RefreshColliderData()
{
if (IsStatic) return; // No need to refresh collider data if it is static
if (Sphere2D == null)
{
SphereRadius = CalculateTrueRadiusOfSphereCollider(Sphere.transform, Sphere.radius);
base.RefreshColliderData();
}
else
{
SphereRadius = CalculateTrueRadiusOfSphereCollider(Sphere2D.transform, Sphere2D.radius);
base.RefreshColliderData();
}
}
public override bool PushIfInside(ref Vector3 point, float pointRadius, Vector3 pointOffset)
{
if ( Is2D == false)
return PushOutFromSphereCollider(Sphere, pointRadius, ref point, SphereRadius, pointOffset);
else
return PushOutFromSphereCollider(Sphere2D, pointRadius, ref point, SphereRadius, pointOffset);
}
public static bool PushOutFromSphereCollider(SphereCollider sphere, float segmentColliderRadius, ref Vector3 segmentPos, Vector3 segmentOffset)
{
return PushOutFromSphereCollider(sphere, segmentColliderRadius, ref segmentPos, CalculateTrueRadiusOfSphereCollider(sphere), segmentOffset);
}
public static bool PushOutFromSphereCollider(SphereCollider sphere, float segmentColliderRadius, ref Vector3 segmentPos, float collidingSphereRadius, Vector3 segmentOffset)
{
Vector3 sphereCenter = sphere.transform.position + sphere.transform.TransformVector(sphere.center);
float radius = collidingSphereRadius + segmentColliderRadius;
Vector3 pushNormal = (segmentPos + segmentOffset) - sphereCenter;
float squaredPushMagn = pushNormal.sqrMagnitude;
if (squaredPushMagn > 0 && squaredPushMagn < radius * radius)
{
segmentPos = sphereCenter - segmentOffset + pushNormal * (radius / Mathf.Sqrt(squaredPushMagn));
return true;
}
return false;
}
public static bool PushOutFromSphereCollider(CircleCollider2D sphere, float segmentColliderRadius, ref Vector3 segmentPos, float collidingSphereRadius, Vector3 segmentOffset)
{
Vector3 sphereCenter = sphere.transform.position + sphere.transform.TransformVector(sphere.offset);
sphereCenter.z = 0f;
float radius = collidingSphereRadius + segmentColliderRadius;
Vector3 pos2D = segmentPos; pos2D.z = 0f;
Vector3 pushNormal = (pos2D + segmentOffset) - sphereCenter;
float squaredPushMagn = pushNormal.sqrMagnitude;
if (squaredPushMagn > 0 && squaredPushMagn < radius * radius)
{
segmentPos = sphereCenter - segmentOffset + pushNormal * (radius / Mathf.Sqrt(squaredPushMagn));
return true;
}
return false;
}
#region Sphere Calculation Helpers
/// <summary>
/// Calculating radius of sphere collider including sphere collider's transform scalling
/// </summary>
public static float CalculateTrueRadiusOfSphereCollider(SphereCollider sphere)
{
return CalculateTrueRadiusOfSphereCollider(sphere.transform, sphere.radius);
}
public static float CalculateTrueRadiusOfSphereCollider(CircleCollider2D sphere)
{
return CalculateTrueRadiusOfSphereCollider(sphere.transform, sphere.radius);
}
/// <summary>
/// Calculating radius of sphere collider including sphere collider's transform scalling
/// </summary>
public static float CalculateTrueRadiusOfSphereCollider(Transform transform, float componentRadius)
{
float radius = componentRadius;
if (transform.lossyScale.x > transform.lossyScale.y)
{
if (transform.lossyScale.x > transform.lossyScale.z) radius *= transform.lossyScale.x;
else
radius *= transform.lossyScale.z;
}
else
{
if (transform.lossyScale.y > transform.lossyScale.z) radius *= transform.lossyScale.y;
else
radius *= transform.lossyScale.z;
}
return radius;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bba586e4c6fd54349ad44a2c387d49bf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,94 @@
using UnityEngine;
namespace FIMSpace
{
public class FImp_ColliderData_Terrain : FImp_ColliderData_Base
{
public TerrainCollider TerrCollider { get; private set; }
public Terrain TerrainComponent { get; private set; }
public FImp_ColliderData_Terrain(TerrainCollider collider)
{
Collider = collider;
Transform = collider.transform;
TerrCollider = collider;
ColliderType = EFColliderType.Terrain;
TerrainComponent = collider.GetComponent<Terrain>();
}
public override bool PushIfInside(ref Vector3 segmentPosition, float segmentRadius, Vector3 segmentOffset)
{
// Checking if segment is inside box shape of terrain
if (segmentPosition.x + segmentRadius < TerrainComponent.GetPosition().x - segmentRadius || segmentPosition.x > TerrainComponent.GetPosition().x + TerrainComponent.terrainData.size.x ||
segmentPosition.z + segmentRadius < TerrainComponent.GetPosition().z - segmentRadius || segmentPosition.z > TerrainComponent.GetPosition().z + TerrainComponent.terrainData.size.z)
return false;
Vector3 offsettedPosition = segmentPosition + segmentOffset;
Vector3 terrPoint = offsettedPosition;
terrPoint.y = TerrCollider.transform.position.y + TerrainComponent.SampleHeight(offsettedPosition);
float hitToPointDist = (offsettedPosition - terrPoint).magnitude;
float underMul = 1f;
if (offsettedPosition.y < terrPoint.y)
{
underMul = 4f;
}
else
if (offsettedPosition.y + segmentRadius * 2f < terrPoint.y)
{
underMul = 8f;
}
if (hitToPointDist < segmentRadius * underMul)
{
Vector3 toNormal = terrPoint - offsettedPosition;
Vector3 pushNormal;
if (underMul > 1f) pushNormal = toNormal + toNormal.normalized * segmentRadius; else pushNormal = toNormal - toNormal.normalized * segmentRadius;
segmentPosition = segmentPosition + pushNormal;
return true;
}
return false;
}
public static void PushOutFromTerrain(TerrainCollider terrainCollider, float segmentRadius, ref Vector3 point)
{
Terrain terrain = terrainCollider.GetComponent<Terrain>();
Vector3 rayOrigin = point;
rayOrigin.y = terrainCollider.transform.position.y + terrain.SampleHeight(point) + segmentRadius;
Ray ray = new Ray(rayOrigin, Vector3.down);
RaycastHit hit;
if (terrainCollider.Raycast(ray, out hit, segmentRadius * 2f))
{
float hitToPointDist = (point - hit.point).magnitude;
float underMul = 1f;
if (hit.point.y > point.y + segmentRadius * 0.9f)
{
underMul = 8f;
}
else
if (hit.point.y > point.y)
{
underMul = 4f;
}
if (hitToPointDist < segmentRadius * underMul)
{
Vector3 toNormal = hit.point - point;
Vector3 pushNormal;
if (underMul > 1f) pushNormal = toNormal + toNormal.normalized * segmentRadius; else pushNormal = toNormal - toNormal.normalized * segmentRadius;
point = point + pushNormal;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f194fa206da32744ab55e530d336095a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
userData:
assetBundleName:
assetBundleVariant: