移除ECM2

This commit is contained in:
2025-05-11 21:42:51 +08:00
parent aadd564c38
commit a7bf033ca9
726 changed files with 0 additions and 138648 deletions

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 602ac0bae88fa1545bdf9f8e0ae8b15e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: f4cf32970eac4c9498a96ba8d86aad38
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: b5de5e9cf3765bc478e60446e12f8604
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,263 +0,0 @@
using UnityEngine;
namespace ECM2
{
public static class Extensions
{
/// <summary>
/// Return the square of the given value.
/// </summary>
public static int square(this int value)
{
return value * value;
}
/// <summary>
/// Return the square of the given value.
/// </summary>
public static float square(this float value)
{
return value * value;
}
/// <summary>
/// Checks whether value is near to zero within a tolerance.
/// </summary>
public static bool isZero(this float value)
{
const float kTolerance = 0.0000000001f;
return Mathf.Abs(value) < kTolerance;
}
/// <summary>
/// Returns a copy of given vector with only X component of the vector.
/// </summary>
public static Vector3 onlyX(this Vector3 vector3)
{
vector3.y = 0.0f;
vector3.z = 0.0f;
return vector3;
}
/// <summary>
/// Returns a copy of given vector with only Y component of the vector.
/// </summary>
public static Vector3 onlyY(this Vector3 vector3)
{
vector3.x = 0.0f;
vector3.z = 0.0f;
return vector3;
}
/// <summary>
/// Returns a copy of given vector with only Z component of the vector.
/// </summary>
public static Vector3 onlyZ(this Vector3 vector3)
{
vector3.x = 0.0f;
vector3.y = 0.0f;
return vector3;
}
/// <summary>
/// Returns a copy of given vector with only X and Y components of the vector.
/// </summary>
public static Vector3 onlyXY(this Vector3 vector3)
{
vector3.z = 0.0f;
return vector3;
}
/// <summary>
/// Returns a copy of given vector with only X and Z components of the vector.
/// </summary>
public static Vector3 onlyXZ(this Vector3 vector3)
{
vector3.y = 0.0f;
return vector3;
}
/// <summary>
/// Checks whether vector is near to zero within a tolerance.
/// </summary>
public static bool isZero(this Vector2 vector2)
{
return vector2.sqrMagnitude < 9.99999943962493E-11;
}
/// <summary>
/// Checks whether vector is near to zero within a tolerance.
/// </summary>
public static bool isZero(this Vector3 vector3)
{
return vector3.sqrMagnitude < 9.99999943962493E-11;
}
/// <summary>
/// Checks whether vector is exceeding the magnitude within a small error tolerance.
/// </summary>
public static bool isExceeding(this Vector3 vector3, float magnitude)
{
// Allow 1% error tolerance, to account for numeric imprecision.
const float kErrorTolerance = 1.01f;
return vector3.sqrMagnitude > magnitude * magnitude * kErrorTolerance;
}
/// <summary>
/// Returns a copy of given vector with a magnitude of 1,
/// and outs its magnitude before normalization.
///
/// If the vector is too small to be normalized a zero vector will be returned.
/// </summary>
public static Vector3 normalized(this Vector3 vector3, out float magnitude)
{
magnitude = vector3.magnitude;
if (magnitude > 9.99999974737875E-06)
return vector3 / magnitude;
magnitude = 0.0f;
return Vector3.zero;
}
/// <summary>
/// Dot product of two vectors.
/// </summary>
public static float dot(this Vector3 vector3, Vector3 otherVector3)
{
return Vector3.Dot(vector3, otherVector3);
}
/// <summary>
/// Returns a copy of given vector projected onto normal vector.
/// </summary>
public static Vector3 projectedOn(this Vector3 thisVector, Vector3 normal)
{
return Vector3.Project(thisVector, normal);
}
/// <summary>
/// Returns a copy of given vector projected onto a plane defined by a normal orthogonal to the plane.
/// </summary>
public static Vector3 projectedOnPlane(this Vector3 thisVector, Vector3 planeNormal)
{
return Vector3.ProjectOnPlane(thisVector, planeNormal);
}
/// <summary>
/// Returns a copy of given vector with its magnitude clamped to maxLength.
/// </summary>
public static Vector3 clampedTo(this Vector3 vector3, float maxLength)
{
return Vector3.ClampMagnitude(vector3, maxLength);
}
/// <summary>
/// Returns a copy of given vector perpendicular to other vector.
/// </summary>
public static Vector3 perpendicularTo(this Vector3 thisVector, Vector3 otherVector)
{
return Vector3.Cross(thisVector, otherVector).normalized;
}
/// <summary>
/// Returns a copy of given vector adjusted to be tangent to a specified surface normal relatively to given up axis.
/// </summary>
public static Vector3 tangentTo(this Vector3 thisVector, Vector3 normal, Vector3 up)
{
Vector3 r = thisVector.perpendicularTo(up);
Vector3 t = normal.perpendicularTo(r);
return t * thisVector.magnitude;
}
/// <summary>
/// Transforms a vector to be relative to given transform.
/// If isPlanar == true, the transform will be applied on the plane defined by world up axis.
/// </summary>
public static Vector3 relativeTo(this Vector3 vector3, Transform relativeToThis, bool isPlanar = true)
{
Vector3 forward = relativeToThis.forward;
if (isPlanar)
{
Vector3 upAxis = Vector3.up;
forward = forward.projectedOnPlane(upAxis);
if (forward.isZero())
forward = Vector3.ProjectOnPlane(relativeToThis.up, upAxis);
}
Quaternion q = Quaternion.LookRotation(forward);
return q * vector3;
}
/// <summary>
/// Transforms a vector to be relative to given transform.
/// If isPlanar == true, the transform will be applied on the plane defined by upAxis.
/// </summary>
public static Vector3 relativeTo(this Vector3 vector3, Transform relativeToThis, Vector3 upAxis, bool isPlanar = true)
{
Vector3 forward = relativeToThis.forward;
if (isPlanar)
{
forward = Vector3.ProjectOnPlane(forward, upAxis);
if (forward.isZero())
forward = Vector3.ProjectOnPlane(relativeToThis.up, upAxis);
}
Quaternion q = Quaternion.LookRotation(forward, upAxis);
return q * vector3;
}
/// <summary>
/// Clamps the given quaternion pitch rotation between the given minPitchAngle and maxPitchAngle.
/// </summary>
public static Quaternion clampPitch(this Quaternion quaternion, float minPitchAngle, float maxPitchAngle)
{
quaternion.x /= quaternion.w;
quaternion.y /= quaternion.w;
quaternion.z /= quaternion.w;
quaternion.w = 1.0f;
float pitch = Mathf.Clamp(2.0f * Mathf.Rad2Deg * Mathf.Atan(quaternion.x), minPitchAngle, maxPitchAngle);
quaternion.x = Mathf.Tan(pitch * 0.5f * Mathf.Deg2Rad);
return quaternion;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 32f22b14e3a428e47a9449588ec9d78b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,174 +0,0 @@
using UnityEngine;
namespace ECM2
{
public static class MathLib
{
/// <summary>
/// Returns Value mapped from one range into another.
/// </summary>
public static float Remap(float inA, float inB, float outA, float outB, float value)
{
float t = Mathf.InverseLerp(inA, inB, value);
return Mathf.Lerp(outA, outB, t);
}
/// <summary>
/// Return the square of the given value.
/// </summary>
public static float Square(float value)
{
return value * value;
}
/// <summary>
/// Returns the direction adjusted to be tangent to a specified surface normal relatively to given up axis.
/// </summary>
public static Vector3 GetTangent(Vector3 direction, Vector3 normal, Vector3 up)
{
Vector3 right = direction.perpendicularTo(up);
return normal.perpendicularTo(right);
}
/// <summary>
/// Projects a given point onto the plane defined by plane origin and plane normal.
/// </summary>
public static Vector3 ProjectPointOnPlane(Vector3 point, Vector3 planeOrigin, Vector3 planeNormal)
{
Vector3 toPoint = point - planeOrigin;
Vector3 toPointProjected = Vector3.Project(toPoint, planeNormal);
return point - toPointProjected;
}
/// <summary>
/// Clamps given angle within min - max range.
/// </summary>
public static float ClampAngle(float a, float min, float max)
{
while (max < min)
max += 360.0f;
while (a > max)
a -= 360.0f;
while (a < min)
a += 360.0f;
return a > max ? a - (max + min) * 0.5f < 180.0f ? max : min : a;
}
/// <summary>
/// Returns Angle in the range (0, 360)
/// </summary>
public static float ClampAngle(float angle)
{
// returns angle in the range (-360, 360)
angle = angle % 360.0f;
if (angle < 0.0f)
{
// shift to (0, 360) range
angle += 360.0f;
}
return angle;
}
/// <summary>
/// Return angle in range -180 to 180
/// </summary>
public static float NormalizeAngle(float angle)
{
// returns angle in the range (0, 360)
angle = ClampAngle(angle);
if (angle > 180.0f)
{
// shift to (-180,180)
angle -= 360.0f;
}
return angle;
}
/// <summary>
/// Clamps the given angle into 0 - 360 degrees range.
/// </summary>
private static float Clamp0360(float eulerAngles)
{
float result = eulerAngles - Mathf.CeilToInt(eulerAngles / 360f) * 360f;
if (result < 0) result += 360f;
return result;
}
/// <summary>
/// Returns a new rotation angle (interpolated) clamped in the range (0.0f , 360.0f)
/// </summary>
public static float FixedTurn(float current, float target, float maxDegreesDelta)
{
if (maxDegreesDelta == 0.0f)
return Clamp0360(current);
if (maxDegreesDelta >= 360.0f)
return Clamp0360(target);
float result = Clamp0360(current);
current = result;
target = Clamp0360(target);
if (current > target)
{
if (current - target < 180.0f)
result -= Mathf.Min(current - target, Mathf.Abs(maxDegreesDelta));
else
result += Mathf.Min(target + 360.0f - current, Mathf.Abs(maxDegreesDelta));
}
else
{
if (target - current < 180.0f)
result += Mathf.Min(target - current, Mathf.Abs(maxDegreesDelta));
else
result -= Mathf.Min(current + 360.0f - target, Mathf.Abs(maxDegreesDelta));
}
return Clamp0360(result);
}
/// <summary>
/// Frame Rate Independent Damping.
/// Source: https://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
/// </summary>
public static float Damp(float a, float b, float lambda, float dt)
{
return Mathf.Lerp(a, b, 1.0f - Mathf.Exp(-lambda * dt));
}
/// <summary>
/// Frame Rate Independent Damping.
/// Source: https://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
/// </summary>
public static Vector3 Damp(Vector3 a, Vector3 b, float lambda, float dt)
{
return Vector3.Lerp(a, b, 1.0f - Mathf.Exp(-lambda * dt));
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: ff183616129658748b90dd05d0186c8d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: a2eecdf9af0466e479f87cb2d561ce94
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 8a5e05c5b0509214d911dd005a610d9a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,401 +0,0 @@
using UnityEngine;
using UnityEngine.AI;
namespace ECM2
{
/// <summary>
/// This component extends a Character (through composition) adding navigation capabilities using a NavMeshAgent.
/// This replaces the previous AgentCharacter class.
/// </summary>
[RequireComponent(typeof(Character)), RequireComponent(typeof(NavMeshAgent))]
public class NavMeshCharacter : MonoBehaviour
{
#region EDITOR EXPOSED FIELDS
[Space(15f)]
[Tooltip("Should the agent brake automatically to avoid overshooting the destination point? \n" +
"If true, the agent will brake automatically as it nears the destination.")]
[SerializeField]
private bool _autoBraking;
[Tooltip("Distance from target position to start braking.")]
[SerializeField]
private float _brakingDistance;
[Tooltip("Stop within this distance from the target position.")]
[SerializeField]
private float _stoppingDistance;
#endregion
#region FIELDS
private NavMeshAgent _agent;
private Character _character;
#endregion
#region PROPERTIES
/// <summary>
/// Cached NavMeshAgent component.
/// </summary>
public NavMeshAgent agent => _agent;
/// <summary>
/// Cached Character component.
/// </summary>
public Character character => _character;
/// <summary>
/// Should the agent brake automatically to avoid overshooting the destination point?
/// If this property is set to true, the agent will brake automatically as it nears the destination.
/// </summary>
public bool autoBraking
{
get => _autoBraking;
set
{
_autoBraking = value;
agent.autoBraking = _autoBraking;
}
}
/// <summary>
/// Distance from target position to start braking.
/// </summary>
public float brakingDistance
{
get => _brakingDistance;
set => _brakingDistance = Mathf.Max(0.0001f, value);
}
/// <summary>
/// The ratio (0 - 1 range) of the agent's remaining distance and the braking distance.
/// 1 If no auto braking or if agent's remaining distance is greater than brakingDistance.
/// less than 1, if agent's remaining distance is less than brakingDistance.
/// </summary>
public float brakingRatio
{
get
{
if (!autoBraking)
return 1f;
return agent.hasPath ? Mathf.InverseLerp(0.0f, brakingDistance, agent.remainingDistance) : 1.0f;
}
}
/// <summary>
/// Stop within this distance from the target position.
/// </summary>
public float stoppingDistance
{
get => _stoppingDistance;
set
{
_stoppingDistance = Mathf.Max(0.0f, value);
agent.stoppingDistance = _stoppingDistance;
}
}
#endregion
#region EVENTS
public delegate void DestinationReachedEventHandler();
/// <summary>
/// Event triggered when agent reaches its destination.
/// </summary>
public event DestinationReachedEventHandler DestinationReached;
/// <summary>
/// Trigger DestinationReached event.
/// Called when agent reaches its destination.
/// </summary>
public virtual void OnDestinationReached()
{
DestinationReached?.Invoke();
}
#endregion
#region METHODS
/// <summary>
/// Cache used components.
/// </summary>
protected virtual void CacheComponents()
{
_agent = GetComponent<NavMeshAgent>();
_character = GetComponent<Character>();
}
/// <summary>
/// Does the Agent currently has a path?
/// </summary>
public virtual bool HasPath()
{
return agent.hasPath;
}
/// <summary>
/// True if Agent is following a path, false otherwise.
/// </summary>
public virtual bool IsPathFollowing()
{
return agent.hasPath && !agent.isStopped;
}
/// <summary>
/// Returns the destination set for this agent.
/// If a destination is set but the path is not yet processed,
/// the returned position will be valid navmesh position that's closest to the previously set position.
/// If the agent has no path or requested path - returns the agents position on the navmesh.
/// If the agent is not mapped to the navmesh (e.g. Scene has no navmesh) - returns a position at infinity.
/// </summary>
public virtual Vector3 GetDestination()
{
return agent.destination;
}
/// <summary>
/// Requests the character to move to the valid navmesh position that's closest to the requested destination.
/// </summary>
public virtual void MoveToDestination(Vector3 destination)
{
Vector3 worldUp = -character.GetGravityDirection();
Vector3 toDestination2D = Vector3.ProjectOnPlane(destination - character.position, worldUp);
if (toDestination2D.sqrMagnitude >= MathLib.Square(stoppingDistance))
agent.SetDestination(destination);
}
/// <summary>
/// Pause / Resume Character path following movement.
/// If set to True, the character's movement will be stopped along its current path.
/// If set to False after the character has stopped, it will resume moving along its current path.
/// </summary>
public virtual void PauseMovement(bool pause)
{
agent.isStopped = pause;
character.SetMovementDirection(Vector3.zero);
}
/// <summary>
/// Halts Character's current path following movement.
/// This will clear agent's current path.
/// </summary>
public virtual void StopMovement()
{
agent.ResetPath();
character.SetMovementDirection(Vector3.zero);
}
/// <summary>
/// Computes the analog input modifier (0.0f to 1.0f) based on Character's max speed and given desired velocity.
/// </summary>
protected virtual float ComputeAnalogInputModifier(Vector3 desiredVelocity)
{
float maxSpeed = _character.GetMaxSpeed();
if (desiredVelocity.sqrMagnitude > 0.0f && maxSpeed > 0.00000001f)
return Mathf.Clamp01(desiredVelocity.magnitude / maxSpeed);
return 0.0f;
}
/// <summary>
/// Calculates Character movement direction from a given desired velocity factoring (if enabled) auto braking.
/// </summary>
protected virtual Vector3 CalcMovementDirection(Vector3 desiredVelocity)
{
Vector3 worldUp = -character.GetGravityDirection();
Vector3 desiredVelocity2D = Vector3.ProjectOnPlane(desiredVelocity, worldUp);
Vector3 scaledDesiredVelocity2D = desiredVelocity2D * brakingRatio;
float minAnalogSpeed = _character.GetMinAnalogSpeed();
if (scaledDesiredVelocity2D.sqrMagnitude < MathLib.Square(minAnalogSpeed))
scaledDesiredVelocity2D = scaledDesiredVelocity2D.normalized * minAnalogSpeed;
return Vector3.ClampMagnitude(scaledDesiredVelocity2D, ComputeAnalogInputModifier(scaledDesiredVelocity2D));
}
/// <summary>
/// Makes the character's follow Agent's path (if any).
/// Eg: Keep updating Character's movement direction vector to steer towards Agent's destination until reached.
/// </summary>
protected virtual void DoPathFollowing()
{
if (!IsPathFollowing())
return;
// Is destination reached ?
if (agent.remainingDistance <= stoppingDistance)
{
// Destination is reached, stop movement
StopMovement();
// Trigger event
OnDestinationReached();
}
else
{
// If destination not reached, request a Character to move towards agent's desired velocity direction
Vector3 movementDirection = CalcMovementDirection(agent.desiredVelocity);
character.SetMovementDirection(movementDirection);
}
}
/// <summary>
/// Synchronize the NavMeshAgent with Character (eg: speed, acceleration, velocity, etc) as we moves the Agent.
/// </summary>
protected virtual void SyncNavMeshAgent()
{
agent.angularSpeed = _character.rotationRate;
agent.speed = _character.GetMaxSpeed();
agent.acceleration = _character.GetMaxAcceleration();
agent.velocity = _character.GetVelocity();
agent.nextPosition = _character.GetPosition();
agent.radius = _character.radius;
agent.height = _character.height;
}
/// <summary>
/// On MovementMode change, stop agent movement if character is not walking or falling.
/// </summary>
protected virtual void OnMovementModeChanged(Character.MovementMode prevMovementMode, int prevCustomMovementMode)
{
if (!character.IsWalking() || !character.IsFalling())
{
StopMovement();
}
}
/// <summary>
/// While Character has a valid path, do path following.
/// </summary>
protected virtual void OnBeforeSimulationUpdated(float deltaTime)
{
DoPathFollowing();
}
#endregion
#region MONOBEHAVIOUR
/// <summary>
/// If overriden, base method MUST be called.
/// </summary>
private void Reset()
{
_autoBraking = true;
_brakingDistance = 2.0f;
_stoppingDistance = 1.0f;
}
/// <summary>
/// If overriden, base method MUST be called.
/// </summary>
private void OnValidate()
{
if (_agent == null)
_agent = GetComponent<NavMeshAgent>();
brakingDistance = _brakingDistance;
stoppingDistance = _stoppingDistance;
}
/// <summary>
/// If overriden, base method MUST be called.
/// </summary>
protected virtual void Awake()
{
// Cache used components
CacheComponents();
// Initialize NavMeshAgent
agent.autoBraking = autoBraking;
agent.stoppingDistance = stoppingDistance;
// Turn-off NavMeshAgent auto-control,
// we control it (see SyncNavMeshAgent method)
agent.updatePosition = false;
agent.updateRotation = false;
agent.updateUpAxis = false;
}
/// <summary>
/// If overriden, base method MUST be called.
/// </summary>
protected virtual void OnEnable()
{
// Subscribe to Character events
character.MovementModeChanged += OnMovementModeChanged;
character.BeforeSimulationUpdated += OnBeforeSimulationUpdated;
}
/// <summary>
/// If overriden, base method MUST be called.
/// </summary>
protected virtual void OnDisable()
{
// Un-Subscribe to Character events
character.MovementModeChanged -= OnMovementModeChanged;
character.BeforeSimulationUpdated -= OnBeforeSimulationUpdated;
}
/// <summary>
/// If overriden, base method MUST be called.
/// </summary>
protected virtual void LateUpdate()
{
SyncNavMeshAgent();
}
#endregion
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 0b8353732406ae7418b47f5928e333c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,142 +0,0 @@
using UnityEngine;
namespace ECM2
{
/// <summary>
/// Helper component used to define physics volumes like water, air, oil, etc.
/// Characters will react according to this settings when inside this volume.
/// </summary>
[RequireComponent(typeof(BoxCollider))]
public class PhysicsVolume : MonoBehaviour
{
#region EDITOR EXPOSED FIELDS
[Tooltip("Determines which PhysicsVolume takes precedence if they overlap (higher value == higher priority).")]
[SerializeField]
private int _priority;
[Tooltip("Determines the amount of friction applied by the volume as Character using CharacterMovement moves through it.\n" +
"The higher this value, the harder it will feel to move through the volume.")]
[SerializeField]
private float _friction;
[Tooltip("Determines the terminal velocity of Characters using CharacterMovement when falling.")]
[SerializeField]
private float _maxFallSpeed;
[Tooltip("Determines if the volume contains a fluid, like water.")]
[SerializeField]
private bool _waterVolume;
#endregion
#region FIELDS
private BoxCollider _collider;
#endregion
#region PROPERTIES
/// <summary>
/// This volume collider (trigger).
/// </summary>
public BoxCollider boxCollider
{
get
{
if (_collider == null)
_collider = GetComponent<BoxCollider>();
return _collider;
}
}
/// <summary>
/// Determines which PhysicsVolume takes precedence if they overlap (higher value == higher priority).
/// </summary>
public int priority
{
get => _priority;
set => _priority = value;
}
/// <summary>
/// Determines the amount of friction applied by the volume as Character's using CharacterMovement move through it.
/// The higher this value, the harder it will feel to move through the volume.
/// </summary>
public float friction
{
get => _friction;
set => _friction = Mathf.Max(0.0f, value);
}
/// <summary>
/// Determines the terminal velocity of Character's using CharacterMovement when falling.
/// </summary>
public float maxFallSpeed
{
get => _maxFallSpeed;
set => _maxFallSpeed = Mathf.Max(0.0f, value);
}
/// <summary>
/// Determines if the volume contains a fluid, like water.
/// </summary>
public bool waterVolume
{
get => _waterVolume;
set => _waterVolume = value;
}
#endregion
#region METHODS
protected virtual void OnReset()
{
priority = 0;
friction = 0.5f;
maxFallSpeed = 40.0f;
waterVolume = true;
}
protected virtual void OnOnValidate()
{
friction = _friction;
maxFallSpeed = _maxFallSpeed;
}
protected virtual void OnAwake()
{
boxCollider.isTrigger = true;
}
#endregion
#region MONOBEHAVIOUR
private void Reset()
{
OnReset();
}
private void OnValidate()
{
OnOnValidate();
}
private void Awake()
{
OnAwake();
}
#endregion
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 4a7a95050e56c7e4f976c906ecd1a941
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,113 +0,0 @@
using UnityEngine;
namespace ECM2
{
/// <summary>
/// The slope behaviour for attached collider.
/// </summary>
public enum SlopeBehaviour
{
Default,
/// <summary>
/// Sets the collider as walkable.
/// </summary>
Walkable,
/// <summary>
/// Sets the collider as not walkable.
/// </summary>
NotWalkable,
/// <summary>
/// Let you specify a custom slope limit value for collider.
/// </summary>
Override
}
/// <summary>
/// Overrides a CharacterMovement SlopeLimit property allowing to define per-object behaviour instead of per face.
/// This enable you to tweak what surfaces Characters can walk up. Perhaps a stair case is too steep or
/// maybe you want to enforce the "no walking on the grass" signs, these settings will enable you to do so.
/// </summary>
public sealed class SlopeLimitBehaviour : MonoBehaviour
{
#region EDITOR EXPOSED FIELDS
[Tooltip("The desired behaviour.")]
[SerializeField]
private SlopeBehaviour _slopeBehaviour = SlopeBehaviour.Default;
[SerializeField]
private float _slopeLimit;
#endregion
#region FIELDS
[SerializeField, HideInInspector]
private float _slopeLimitCos;
#endregion
#region PROPERTIES
/// <summary>
/// The current behaviour.
/// </summary>
public SlopeBehaviour walkableSlopeBehaviour
{
get => _slopeBehaviour;
set => _slopeBehaviour = value;
}
/// <summary>
/// The slope limit angle in degrees.
/// </summary>
public float slopeLimit
{
get => _slopeLimit;
set
{
_slopeLimit = Mathf.Clamp(value, 0.0f, 89.0f);
_slopeLimitCos = Mathf.Cos(_slopeLimit * Mathf.Deg2Rad);
}
}
/// <summary>
/// The cosine of slope angle (in radians), this is used to faster angle tests (e.g. dotProduct > slopeLimitCos)
/// </summary>
public float slopeLimitCos
{
get => _slopeLimitCos;
set
{
_slopeLimitCos = Mathf.Clamp01(value);
_slopeLimit = Mathf.Clamp(Mathf.Acos(_slopeLimitCos) * Mathf.Rad2Deg, 0.0f, 89.0f);
}
}
#endregion
#region MONOBEHAVIOUR
private void OnValidate()
{
slopeLimit = _slopeLimit;
}
#endregion
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 2843c82a9ca85424b925fc897391f62d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,14 +0,0 @@
{
"name": "ECM2",
"rootNamespace": "ECM2",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 659d7efc2734dfe4babc4144eff2294d
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 8be59010d2e089f4ab0b4354b30ee000
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,118 +0,0 @@
using UnityEngine;
namespace ECM2
{
/// <summary>
///
/// RootMotionController.
///
/// Helper component to get Animator root motion velocity vector (animRootMotionVelocity).
///
/// This must be attached to a game object with an Animator component.
/// </summary>
[RequireComponent(typeof(Animator))]
public class RootMotionController : MonoBehaviour
{
#region FIELDS
protected Animator _animator;
protected Vector3 _rootMotionDeltaPosition;
protected Quaternion _rootMotionDeltaRotation;
#endregion
#region METHOD
/// <summary>
/// Flush any accumulated deltas. This prevents accumulation while character is toggling root motion.
/// </summary>
public virtual void FlushAccumulatedDeltas()
{
_rootMotionDeltaPosition = Vector3.zero;
_rootMotionDeltaRotation = Quaternion.identity;
}
/// <summary>
/// Return current root motion rotation and clears accumulated delta rotation.
/// </summary>
public virtual Quaternion ConsumeRootMotionRotation()
{
Quaternion rootMotionRotation = _rootMotionDeltaRotation;
_rootMotionDeltaRotation = Quaternion.identity;
return rootMotionRotation;
}
/// <summary>
/// Get the calculated root motion velocity.
/// </summary>
public virtual Vector3 GetRootMotionVelocity(float deltaTime)
{
if (deltaTime == 0.0f)
return Vector3.zero;
Vector3 rootMotionVelocity = _rootMotionDeltaPosition / deltaTime;
return rootMotionVelocity;
}
/// <summary>
/// Return current root motion velocity and clears accumulated delta positions.
/// </summary>
public virtual Vector3 ConsumeRootMotionVelocity(float deltaTime)
{
Vector3 rootMotionVelocity = GetRootMotionVelocity(deltaTime);
_rootMotionDeltaPosition = Vector3.zero;
return rootMotionVelocity;
}
#endregion
#region MONOBEHAVIOUR
/// <summary>
/// If overriden, base method MUST be called.
/// </summary>
public virtual void Awake()
{
_animator = GetComponent<Animator>();
if (_animator == null)
{
Debug.LogError($"RootMotionController: There is no 'Animator' attached to the '{name}' game object.\n" +
$"Please attach a 'Animator' to the '{name}' game object");
}
}
/// <summary>
/// If overriden, base method MUST be called.
/// </summary>
public virtual void Start()
{
_rootMotionDeltaPosition = Vector3.zero;
_rootMotionDeltaRotation = Quaternion.identity;
}
/// <summary>
/// If overriden, base method MUST be called.
/// </summary>
public virtual void OnAnimatorMove()
{
// Accumulate root motion deltas between character updates
_rootMotionDeltaPosition += _animator.deltaPosition;
_rootMotionDeltaRotation = _animator.deltaRotation * _rootMotionDeltaRotation;
}
#endregion
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 838519e5d02343249e0d4ddd7578cba4
timeCreated: 1603243744

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 8990a943a41a4051a9e2b542066a7bd5
timeCreated: 1700619077

View File

@@ -1,14 +0,0 @@
using UnityEngine;
namespace ECM2
{
public interface IColliderFilter
{
/// <summary>
/// Determines if the given collider should be filtered (eg: ignored).
/// Return true if should be filtered, false otherwise.
/// </summary>
bool Filter(Collider otherCollider);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: ab476561401c4b644965e59c1c307e27
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 2140f7c214e8462448458ec61e2435dd
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,171 +0,0 @@
using System;
using UnityEngine;
namespace ECM2
{
/// <summary>
/// General purpose collision detection functions.
/// Lets you filter results implementing the IColliderFilter interface.
/// </summary>
public static class CollisionDetection
{
#region CONSTANTS
private const int kMaxHits = 8;
#endregion
#region FIELDS
private static readonly RaycastHit[] HitsBuffer = new RaycastHit[kMaxHits];
#endregion
#region METHODS
public static int Raycast(Vector3 origin, Vector3 direction, float distance, int layerMask,
QueryTriggerInteraction queryTriggerInteraction, out RaycastHit closestHit, RaycastHit[] hits,
IColliderFilter colliderFilter)
{
closestHit = default;
int rawHitCount = Physics.RaycastNonAlloc(origin, direction, HitsBuffer, distance, layerMask,
queryTriggerInteraction);
if (rawHitCount == 0)
return 0;
int filteredHitCount = 0;
float closestDistance = Mathf.Infinity;
Array.Clear(hits, 0, hits.Length);
for (int i = 0; i < rawHitCount; i++)
{
if (HitsBuffer[i].distance <= 0.0f ||
colliderFilter != null && colliderFilter.Filter(HitsBuffer[i].collider))
continue;
if (HitsBuffer[i].distance < closestDistance)
{
closestHit = HitsBuffer[i];
closestDistance = closestHit.distance;
}
hits[filteredHitCount++] = HitsBuffer[i];
}
return filteredHitCount;
}
public static int SphereCast(Vector3 origin, float radius, Vector3 direction, float distance, int layerMask,
QueryTriggerInteraction queryTriggerInteraction, out RaycastHit closestHit, RaycastHit[] hits,
IColliderFilter colliderFilter, float backStepDistance)
{
closestHit = default;
Vector3 optOrigin = origin - direction * backStepDistance;
float optDistance = distance + backStepDistance;
int rawHitCount = Physics.SphereCastNonAlloc(optOrigin, radius, direction, HitsBuffer, optDistance,
layerMask, queryTriggerInteraction);
if (rawHitCount == 0)
return 0;
int filteredHitCount = 0;
float closestDistance = Mathf.Infinity;
Array.Clear(hits, 0, hits.Length);
for (int i = 0; i < rawHitCount; i++)
{
if (HitsBuffer[i].distance <= 0.0f ||
colliderFilter != null && colliderFilter.Filter(HitsBuffer[i].collider))
continue;
HitsBuffer[i].distance -= backStepDistance;
if (HitsBuffer[i].distance < closestDistance)
{
closestHit = HitsBuffer[i];
closestDistance = closestHit.distance;
}
hits[filteredHitCount++] = HitsBuffer[i];
}
return filteredHitCount;
}
public static int CapsuleCast(Vector3 point1, Vector3 point2, float radius, Vector3 direction, float distance,
int layerMask, QueryTriggerInteraction queryTriggerInteraction, out RaycastHit closestHit,
RaycastHit[] hits, IColliderFilter colliderFilter, float backStepDistance)
{
closestHit = default;
Vector3 optPoint1 = point1 - direction * backStepDistance;
Vector3 optPoint2 = point2 - direction * backStepDistance;
float optDistance = distance + backStepDistance;
int rawHitCount = Physics.CapsuleCastNonAlloc(optPoint1, optPoint2, radius, direction, HitsBuffer,
optDistance, layerMask, queryTriggerInteraction);
if (rawHitCount == 0)
return 0;
int filteredHitCount = 0;
float closestDistance = Mathf.Infinity;
Array.Clear(hits, 0, hits.Length);
for (int i = 0; i < rawHitCount; i++)
{
if (HitsBuffer[i].distance <= 0.0f ||
colliderFilter != null && colliderFilter.Filter(HitsBuffer[i].collider))
continue;
HitsBuffer[i].distance -= backStepDistance;
if (HitsBuffer[i].distance < closestDistance)
{
closestHit = HitsBuffer[i];
closestDistance = closestHit.distance;
}
hits[filteredHitCount++] = HitsBuffer[i];
}
return filteredHitCount;
}
public static int OverlapCapsule(Vector3 point1, Vector3 point2, float radius, int layerMask,
QueryTriggerInteraction queryTriggerInteraction, Collider[] results, IColliderFilter colliderFilter)
{
int rawOverlapCount =
Physics.OverlapCapsuleNonAlloc(point1, point2, radius, results, layerMask, queryTriggerInteraction);
if (rawOverlapCount == 0)
return 0;
int filteredOverlapCount = rawOverlapCount;
for (int i = 0; i < rawOverlapCount; i++)
{
Collider overlappedCollider = results[i];
if (colliderFilter != null && !colliderFilter.Filter(overlappedCollider))
continue;
if (i < --filteredOverlapCount)
results[i] = results[filteredOverlapCount];
}
return filteredOverlapCount;
}
#endregion
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 3ea13ecaa42445519734922e43f938f2
timeCreated: 1700619165

View File

@@ -1,99 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace ECM2
{
public static class MeshUtility
{
private const int kMaxVertices = 1024;
private const int kMaxTriangles = kMaxVertices * 3;
private static readonly List<Vector3> _vertices = new List<Vector3>(kMaxVertices);
private static readonly List<ushort> _triangles16 = new List<ushort>(kMaxTriangles);
private static readonly List<int> _triangles32 = new List<int>();
private static readonly List<ushort> _scratchBuffer16 = new List<ushort>(kMaxTriangles);
private static readonly List<int> _scratchBuffer32 = new List<int>();
public static Vector3 FindMeshOpposingNormal(Mesh sharedMesh, ref RaycastHit inHit)
{
Vector3 v0, v1, v2;
if (sharedMesh.indexFormat == IndexFormat.UInt16)
{
_triangles16.Clear();
int subMeshCount = sharedMesh.subMeshCount;
if (subMeshCount == 1)
sharedMesh.GetTriangles(_triangles16, 0);
else
{
for (int i = 0; i < subMeshCount; i++)
{
sharedMesh.GetTriangles(_scratchBuffer16, i);
_triangles16.AddRange(_scratchBuffer16);
}
}
sharedMesh.GetVertices(_vertices);
v0 = _vertices[_triangles16[inHit.triangleIndex * 3 + 0]];
v1 = _vertices[_triangles16[inHit.triangleIndex * 3 + 1]];
v2 = _vertices[_triangles16[inHit.triangleIndex * 3 + 2]];
}
else
{
_triangles32.Clear();
int subMeshCount = sharedMesh.subMeshCount;
if (subMeshCount == 1)
sharedMesh.GetTriangles(_triangles32, 0);
else
{
for (int i = 0; i < subMeshCount; i++)
{
sharedMesh.GetTriangles(_scratchBuffer32, i);
_triangles32.AddRange(_scratchBuffer32);
}
}
sharedMesh.GetVertices(_vertices);
v0 = _vertices[_triangles32[inHit.triangleIndex * 3 + 0]];
v1 = _vertices[_triangles32[inHit.triangleIndex * 3 + 1]];
v2 = _vertices[_triangles32[inHit.triangleIndex * 3 + 2]];
}
Matrix4x4 mtx = inHit.transform.localToWorldMatrix;
Vector3 p0 = mtx.MultiplyPoint3x4(v0);
Vector3 p1 = mtx.MultiplyPoint3x4(v1);
Vector3 p2 = mtx.MultiplyPoint3x4(v2);
Vector3 u = p1 - p0;
Vector3 v = p2 - p0;
Vector3 worldNormal = Vector3.Cross(u, v).normalized;
if (Vector3.Dot(worldNormal, inHit.normal) < 0.0f)
worldNormal = Vector3.Cross(v, u).normalized;
return worldNormal;
}
public static void FlushBuffers()
{
_vertices.Clear();
_scratchBuffer16.Clear();
_scratchBuffer32.Clear();
_triangles16.Clear();
_triangles32.Clear();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 740062629b0d7924ca2d9b9f8ff3318c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: