OctoCore 0.0.1
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.Components
|
||||
{
|
||||
public class OctoCharacterAnimation : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Animator animator;
|
||||
[SerializeField] private float walkSpeed = 8;
|
||||
[SerializeField] private float runSpeed = 15;
|
||||
[SerializeField, Range(1, 10)] private int sampling = 5;
|
||||
|
||||
private bool backward;
|
||||
private float backwardSmooth;
|
||||
private float sideSmooth;
|
||||
private float smoothSpeed;
|
||||
private Vector4[] positions;
|
||||
private Vector3 lastStep;
|
||||
private Vector3 direction;
|
||||
|
||||
private float step = .1f;
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.color = Color.cyan;
|
||||
Gizmos.DrawRay(transform.position + Vector3.up, transform.forward);
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawRay(transform.position + Vector3.up, direction);
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
positions = new Vector4[sampling + 1];
|
||||
for (int i = 0; i < sampling; i++)
|
||||
{
|
||||
positions[i] = transform.position;
|
||||
positions[i].z = .002f;
|
||||
}
|
||||
|
||||
direction = transform.forward;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (lastStep != transform.position && Vector3.Distance(lastStep, transform.position) > step)
|
||||
{
|
||||
Vector3 offset = (lastStep - transform.position).normalized * step;
|
||||
lastStep = transform.position + offset;
|
||||
}
|
||||
|
||||
direction = Vector3.Lerp(direction, (transform.position - lastStep).normalized, Time.deltaTime * 10);
|
||||
|
||||
float speed = GetSpeed();
|
||||
smoothSpeed = Mathf.Lerp(smoothSpeed, speed, Time.deltaTime * 10);
|
||||
|
||||
float move = Mathf.Clamp01(smoothSpeed / walkSpeed);
|
||||
float run = Mathf.Clamp01((smoothSpeed - walkSpeed) / (runSpeed - walkSpeed));
|
||||
|
||||
float dot = Vector3.Dot(transform.forward, direction.normalized);
|
||||
Vector3 crs = Vector3.Cross(transform.forward, direction.normalized);
|
||||
|
||||
backward = dot < 0;
|
||||
backwardSmooth = Mathf.Lerp(backwardSmooth, backward ? 1 : 0, Time.deltaTime * 10);
|
||||
|
||||
sideSmooth = Mathf.Lerp(sideSmooth, (1 - Mathf.Abs(dot)) * Mathf.Sign(transform.InverseTransformDirection(crs).y) * direction.magnitude, Time.deltaTime * 20);
|
||||
|
||||
run *= 1 - backwardSmooth;
|
||||
run *= 1 - Mathf.Abs(sideSmooth);
|
||||
|
||||
//Debug.Log(dot);
|
||||
|
||||
animator.SetFloat("move", Mathf.Sqrt(move));
|
||||
animator.SetFloat("run", run);
|
||||
animator.SetFloat("backward", backwardSmooth);
|
||||
animator.SetFloat("side", sideSmooth);
|
||||
}
|
||||
|
||||
float GetSpeed()
|
||||
{
|
||||
float offset = 0;
|
||||
float delta = 0;
|
||||
|
||||
for (int i = 0; i < positions.Length - 1; i++)
|
||||
{
|
||||
offset += Vector3.Distance(positions[i], positions[i + 1]);
|
||||
delta += positions[i].w;
|
||||
}
|
||||
|
||||
for (int i = positions.Length - 1; i > 0; i--)
|
||||
positions[i] = positions[i - 1];
|
||||
|
||||
positions[0] = transform.position;
|
||||
positions[0].w = Time.deltaTime;
|
||||
|
||||
if (offset > 0 && delta > 0)
|
||||
return offset / (delta / 3.6f);
|
||||
else return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4b0dbb024f42dc4c8c80d40a271d6d3
|
||||
@@ -0,0 +1,205 @@
|
||||
using UnityEngine;
|
||||
using static UnityEngine.GraphicsBuffer;
|
||||
|
||||
public class OctoIkArms : MonoBehaviour
|
||||
{
|
||||
private class RaycastInfos
|
||||
{
|
||||
public bool HasHit;
|
||||
public float Distance;
|
||||
public float MaxDistance;
|
||||
public Vector3 Position;
|
||||
public Vector3 Normal;
|
||||
public Transform Transform;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class RaycastRig
|
||||
{
|
||||
public Transform Root;
|
||||
public float Distance = 1;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class ArmRig
|
||||
{
|
||||
public bool Enabled;
|
||||
public OctoIkLimb Arm;
|
||||
public Vector3 RotationOffset;
|
||||
public RaycastRig[] Raycasts;
|
||||
|
||||
[HideInInspector] public Vector3 TargetOriginPos;
|
||||
[HideInInspector] public Quaternion TargetOriginRot;
|
||||
[HideInInspector] public Vector3 PoleOriginPos;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
if (Arm)
|
||||
{
|
||||
if (Arm.Target)
|
||||
{
|
||||
TargetOriginPos = Arm.Target.localPosition;
|
||||
TargetOriginRot = Arm.Target.localRotation;
|
||||
}
|
||||
|
||||
if (Arm.Pole)
|
||||
{
|
||||
PoleOriginPos = Arm.Pole.localPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class Settings
|
||||
{
|
||||
public LayerMask LayerMask;
|
||||
}
|
||||
|
||||
[SerializeField] private ArmRig _leftArm;
|
||||
[SerializeField] private ArmRig _rightArm;
|
||||
[SerializeField] private Settings _settings;
|
||||
|
||||
private ArmRig[] _arms;
|
||||
private RaycastInfos[][] _raycasts = new RaycastInfos[2][];
|
||||
private RaycastInfos[] _nearHitRaycasts = new RaycastInfos[2];
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_arms = new ArmRig[2] { _leftArm, _rightArm };
|
||||
foreach (ArmRig armRig in _arms)
|
||||
armRig.Init();
|
||||
|
||||
_raycasts = new RaycastInfos[_arms.Length][];
|
||||
for (int i = 0; i < _arms.Length; i++)
|
||||
{
|
||||
_raycasts[i] = new RaycastInfos[_arms[i].Raycasts.Length];
|
||||
for (int u = 0; u < _raycasts[i].Length; u++)
|
||||
_raycasts[i][u] = new RaycastInfos() { MaxDistance = 1 };
|
||||
}
|
||||
|
||||
_nearHitRaycasts = new RaycastInfos[_arms.Length];
|
||||
for (int i = 0; i < _nearHitRaycasts.Length; i++)
|
||||
_nearHitRaycasts[i] = new RaycastInfos() { MaxDistance = 1 };
|
||||
}
|
||||
|
||||
void OnDrawGizmos()//Selected()
|
||||
{
|
||||
if (Application.isPlaying || !enabled) return;
|
||||
|
||||
foreach (ArmRig armRig in new ArmRig[2] { _leftArm, _rightArm })
|
||||
{
|
||||
for (int i = 0; i < armRig.Raycasts.Length; i++)
|
||||
{
|
||||
RaycastRig raycastRig = armRig.Raycasts[i];
|
||||
Debug.DrawRay(raycastRig.Root.position, raycastRig.Root.TransformDirection(Vector3.forward) * raycastRig.Distance, Color.red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Get raycats infos
|
||||
|
||||
for (int i = 0; i < _arms.Length; i++)
|
||||
{
|
||||
ArmRig armRig = _arms[i];
|
||||
|
||||
if (!armRig.Enabled)
|
||||
continue;
|
||||
|
||||
for (int u = 0; u < armRig.Raycasts.Length; u++)
|
||||
{
|
||||
RaycastRig raycastRig = armRig.Raycasts[u];
|
||||
RaycastInfos raycastInfos = _raycasts[i][u];
|
||||
|
||||
RaycastHit hit;
|
||||
|
||||
if (Physics.Raycast(raycastRig.Root.position, raycastRig.Root.TransformDirection(Vector3.forward), out hit, raycastRig.Distance, _settings.LayerMask))
|
||||
{
|
||||
Debug.DrawRay(raycastRig.Root.position, raycastRig.Root.TransformDirection(Vector3.forward) * hit.distance, Color.green);
|
||||
|
||||
raycastInfos.HasHit = true;
|
||||
raycastInfos.Distance = hit.distance;
|
||||
raycastInfos.MaxDistance = raycastRig.Distance;
|
||||
raycastInfos.Position = hit.point;
|
||||
raycastInfos.Normal = hit.normal;
|
||||
raycastInfos.Transform = hit.transform;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.DrawRay(raycastRig.Root.position, raycastRig.Root.TransformDirection(Vector3.forward) * raycastRig.Distance, Color.red);
|
||||
|
||||
raycastInfos.HasHit = false;
|
||||
raycastInfos.Distance = 1;
|
||||
raycastInfos.MaxDistance = 1;
|
||||
raycastInfos.Position = Vector3.zero;
|
||||
raycastInfos.Normal = Vector3.zero;
|
||||
raycastInfos.Transform = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate near hit
|
||||
|
||||
for (int i = 0; i < _arms.Length; i++)
|
||||
{
|
||||
ArmRig armRig = _arms[i];
|
||||
_nearHitRaycasts[i].HasHit = false;
|
||||
|
||||
for (int u = 0; u < armRig.Raycasts.Length; u++)
|
||||
{
|
||||
RaycastInfos raycastInfos = _raycasts[i][u];
|
||||
|
||||
if (raycastInfos.HasHit)
|
||||
{
|
||||
_nearHitRaycasts[i].HasHit = raycastInfos.HasHit;
|
||||
_nearHitRaycasts[i].Distance = _raycasts[i][u].Distance;
|
||||
_nearHitRaycasts[i].MaxDistance = _raycasts[i][u].MaxDistance;
|
||||
_nearHitRaycasts[i].Position = _raycasts[i][u].Position;
|
||||
_nearHitRaycasts[i].Normal = _raycasts[i][u].Normal;
|
||||
_nearHitRaycasts[i].Transform = _raycasts[i][u].Transform;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move hands
|
||||
|
||||
for (int i = 0; i < _arms.Length; i++)
|
||||
{
|
||||
ArmRig armRig = _arms[i];
|
||||
RaycastInfos raycastInfos = _nearHitRaycasts[i];
|
||||
|
||||
Vector3 targetPos = armRig.TargetOriginPos;
|
||||
Quaternion targetRot = armRig.TargetOriginRot;
|
||||
|
||||
float sticknessPos = 0;
|
||||
float sticknessRot = 0;
|
||||
|
||||
if (raycastInfos.HasHit)
|
||||
{
|
||||
float doorForward = transform.InverseTransformDirection(raycastInfos.Transform.forward).z;
|
||||
bool isGoodArm = i == 0 ? (doorForward < 0) : (doorForward > 0);
|
||||
|
||||
if (isGoodArm)
|
||||
{
|
||||
targetPos = armRig.Arm.Target.parent.InverseTransformPoint(raycastInfos.Position);
|
||||
targetRot = Quaternion.LookRotation(-armRig.Arm.Target.parent.InverseTransformDirection(raycastInfos.Normal), transform.up) * Quaternion.Euler(armRig.RotationOffset);
|
||||
|
||||
float t = 1 - Mathf.Clamp01(raycastInfos.Distance / raycastInfos.MaxDistance);
|
||||
|
||||
sticknessPos = Mathf.SmoothStep(0, .7f, t);
|
||||
sticknessRot = Mathf.SmoothStep(.5f, .9f, t);
|
||||
}
|
||||
}
|
||||
|
||||
float tPos = Mathf.SmoothStep(Time.deltaTime * 3, 1, sticknessPos);
|
||||
float tRot = Mathf.SmoothStep(Time.deltaTime * 5, 1, sticknessRot);
|
||||
|
||||
armRig.Arm.Target.localPosition = Vector3.Lerp(armRig.Arm.Target.localPosition, targetPos, tPos);
|
||||
armRig.Arm.Target.localRotation = Quaternion.Lerp(armRig.Arm.Target.localRotation, targetRot, tRot);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 015ed493fd8775f479bf25c92aa04e57
|
||||
@@ -0,0 +1,303 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Two-bone IK solver for a single limb (arm or leg).
|
||||
/// Works with or without an Animator.
|
||||
/// Assumes a 3-bone chain: start -> mid -> end.
|
||||
/// Bones are assumed to point along a configurable local primary axis,
|
||||
/// with a configurable local secondary axis used as "bend up".
|
||||
/// </summary>
|
||||
public class OctoIkLimb : MonoBehaviour
|
||||
{
|
||||
public enum Axis
|
||||
{
|
||||
XPlus,
|
||||
XMinus,
|
||||
YPlus,
|
||||
YMinus,
|
||||
ZPlus,
|
||||
ZMinus
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class Joints
|
||||
{
|
||||
[Tooltip("start joint of the limb (e.g. shoulder or hip).")]
|
||||
public Transform Start;
|
||||
|
||||
[Tooltip("Middle joint of the limb (e.g. elbow or knee).")]
|
||||
public Transform Mid;
|
||||
|
||||
[Tooltip("End joint of the limb (e.g. wrist or foot).")]
|
||||
public Transform End;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class Controllers
|
||||
{
|
||||
[Tooltip("Target the end joint should try to reach.")]
|
||||
public Transform Target;
|
||||
|
||||
[Tooltip("Optional pole to control the bending direction of the limb (e.g. elbow or knee direction).")]
|
||||
public Transform Pole;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class Settings
|
||||
{
|
||||
[Tooltip("Local primary axis pointing toward the next bone.")]
|
||||
public Axis PrimaryAxis = Axis.YPlus;
|
||||
|
||||
[Tooltip("Local secondary axis defining the bend 'up' direction.")]
|
||||
public Axis SecondaryAxis = Axis.XMinus;
|
||||
|
||||
[Header("Settings")]
|
||||
|
||||
[Tooltip("Global IK blend weight (0 = no IK, 1 = full IK).")]
|
||||
[Range(0f, 1f)]
|
||||
public float Weight = 1;
|
||||
|
||||
[Tooltip("Apply the target rotation to the end joint.")]
|
||||
public bool OrientEnd = true;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class VisualDebug
|
||||
{
|
||||
[Tooltip("Enable or disable IK debug gizmos.")]
|
||||
public bool Gizmos = true;
|
||||
|
||||
[Tooltip("Scale of the axis gizmos drawn at each joint.")]
|
||||
public float Size = 0.1f;
|
||||
}
|
||||
|
||||
[SerializeField] private Joints _joints;
|
||||
[SerializeField] private Controllers _controllers;
|
||||
[SerializeField] private Settings _settings;
|
||||
[SerializeField] private VisualDebug _debug;
|
||||
|
||||
public Transform Target => _controllers.Target;
|
||||
public Transform Pole => _controllers.Pole;
|
||||
|
||||
private float _upperLength;
|
||||
private float _lowerLength;
|
||||
private float _maxReach;
|
||||
|
||||
private Quaternion _axesCorrection = Quaternion.identity;
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnValidate()
|
||||
{
|
||||
RecalculateLengths();
|
||||
RecalculateAxesCorrection();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Awake()
|
||||
{
|
||||
RecalculateLengths();
|
||||
RecalculateAxesCorrection();
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
Solve();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recomputes bone lengths and max reach.
|
||||
/// </summary>
|
||||
private void RecalculateLengths()
|
||||
{
|
||||
if (_joints.Start && _joints.Mid && _joints.End)
|
||||
{
|
||||
_upperLength = Vector3.Distance(_joints.Start.position, _joints.Mid.position);
|
||||
_lowerLength = Vector3.Distance(_joints.Mid.position, _joints.End.position);
|
||||
_maxReach = Mathf.Max(0f, _upperLength + _lowerLength - 0.0001f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Precomputes a local correction rotation so that:
|
||||
/// - local primary axis is treated as +Z (forward)
|
||||
/// - local secondary axis is treated as +Y (up)
|
||||
/// </summary>
|
||||
private void RecalculateAxesCorrection()
|
||||
{
|
||||
Vector3 pLocal = AxisToVector(_settings.PrimaryAxis).normalized;
|
||||
Vector3 sLocal = AxisToVector(_settings.SecondaryAxis).normalized;
|
||||
|
||||
// Step 1: rotate primary axis to +Z
|
||||
Quaternion qPrimary = Quaternion.FromToRotation(pLocal, Vector3.forward);
|
||||
|
||||
// Step 2: after this, rotate around Z so that secondary goes to +Y
|
||||
Vector3 s1 = qPrimary * sLocal;
|
||||
Vector3 s1Proj = Vector3.ProjectOnPlane(s1, Vector3.forward);
|
||||
|
||||
if (s1Proj.sqrMagnitude < 0.000001f)
|
||||
{
|
||||
_axesCorrection = qPrimary;
|
||||
return;
|
||||
}
|
||||
|
||||
s1Proj.Normalize();
|
||||
Quaternion qTwist = Quaternion.FromToRotation(s1Proj, Vector3.up);
|
||||
|
||||
// This maps (primary, secondary) -> (Z+, Y+)
|
||||
_axesCorrection = qTwist * qPrimary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Solves IK for the current limb configuration.
|
||||
/// Can be called manually if autoSolve is disabled.
|
||||
/// </summary>
|
||||
public void Solve()
|
||||
{
|
||||
if (_settings.Weight <= 0f)
|
||||
return;
|
||||
|
||||
if (!_joints.Start || !_joints.Mid || !_joints.End || !_controllers.Target)
|
||||
return;
|
||||
|
||||
if (_upperLength <= 0f || _lowerLength <= 0f)
|
||||
RecalculateLengths();
|
||||
|
||||
Vector3 startPos = _joints.Start.position;
|
||||
Vector3 midPos = _joints.Mid.position;
|
||||
Vector3 endPos = _joints.End.position;
|
||||
|
||||
Vector3 startToTarget = _controllers.Target.position - startPos;
|
||||
float dist = startToTarget.magnitude;
|
||||
if (dist < 0.0001f)
|
||||
return;
|
||||
|
||||
dist = Mathf.Min(dist, _maxReach);
|
||||
Vector3 dirToTarget = startToTarget.normalized;
|
||||
|
||||
Vector3 bendNormal;
|
||||
|
||||
if (_controllers.Pole)
|
||||
{
|
||||
Vector3 startToPole = (_controllers.Pole.position - startPos);
|
||||
Vector3 side = Vector3.ProjectOnPlane(startToPole, dirToTarget);
|
||||
if (side.sqrMagnitude < 0.000001f)
|
||||
{
|
||||
// Fallback if pole is collinear with forward
|
||||
side = Vector3.right;
|
||||
}
|
||||
side.Normalize();
|
||||
|
||||
// Bend normal is perpendicular to forward and to that side
|
||||
bendNormal = Vector3.Cross(dirToTarget, side);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: use start.up to define a side, then build a normal
|
||||
Vector3 side = Vector3.ProjectOnPlane(_joints.Start.up, dirToTarget);
|
||||
if (side.sqrMagnitude < 0.000001f)
|
||||
side = Vector3.right;
|
||||
side.Normalize();
|
||||
|
||||
bendNormal = Vector3.Cross(dirToTarget, side);
|
||||
}
|
||||
|
||||
if (bendNormal.sqrMagnitude < 0.000001f)
|
||||
return;
|
||||
|
||||
bendNormal.Normalize();
|
||||
|
||||
// Bend direction lies in the plane defined by dirToTarget and bendNormal
|
||||
Vector3 bendDir = Vector3.Cross(bendNormal, dirToTarget).normalized;
|
||||
|
||||
float a = _upperLength;
|
||||
float b = _lowerLength;
|
||||
float c = dist;
|
||||
|
||||
// Law of cosines to compute start angle
|
||||
float cos0 = Mathf.Clamp((a * a + c * c - b * b) / (2f * a * c), -1f, 1f);
|
||||
float angle0 = Mathf.Acos(cos0);
|
||||
|
||||
float along = Mathf.Cos(angle0) * a;
|
||||
float height = Mathf.Sin(angle0) * a;
|
||||
|
||||
Vector3 desiredMid = startPos + dirToTarget * along + bendDir * height;
|
||||
Vector3 desiredEnd = _controllers.Target.position;
|
||||
|
||||
// Canonical solver rotations assuming +Z forward, +Y up
|
||||
Quaternion startVirtual = Quaternion.LookRotation(desiredMid - startPos, bendNormal);
|
||||
Quaternion midVirtual = Quaternion.LookRotation(desiredEnd - desiredMid, bendNormal);
|
||||
|
||||
// Map canonical frame to bone-local frame using axesCorrection
|
||||
// (we expect bones to point along primaryAxis and bend using secondaryAxis)
|
||||
Quaternion startDesired = startVirtual * _axesCorrection;
|
||||
Quaternion midDesired = midVirtual * _axesCorrection;
|
||||
|
||||
_joints.Start.rotation = Quaternion.Slerp(_joints.Start.rotation, startDesired, _settings.Weight);
|
||||
_joints.Mid.rotation = Quaternion.Slerp(_joints.Mid.rotation, midDesired, _settings.Weight);
|
||||
|
||||
if (_settings.OrientEnd)
|
||||
{
|
||||
_joints.End.rotation = Quaternion.Slerp(_joints.End.rotation, _controllers.Target.rotation, _settings.Weight);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a LocalAxis6 enum to a unit Vector3.
|
||||
/// </summary>
|
||||
private Vector3 AxisToVector(Axis axis)
|
||||
{
|
||||
switch (axis)
|
||||
{
|
||||
default: return Vector3.forward;
|
||||
case Axis.XPlus: return Vector3.right;
|
||||
case Axis.XMinus: return Vector3.left;
|
||||
case Axis.YPlus: return Vector3.up;
|
||||
case Axis.YMinus: return Vector3.down;
|
||||
case Axis.ZMinus: return Vector3.back;
|
||||
}
|
||||
}
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
if (!_debug.Gizmos)
|
||||
return;
|
||||
|
||||
if (!_joints.Start || !_joints.Mid || !_joints.End)
|
||||
return;
|
||||
|
||||
// Bones to Controllers
|
||||
Gizmos.color = Color.yellow;
|
||||
if (_controllers.Target)
|
||||
Gizmos.DrawLine(_joints.End.position, _controllers.Target.position);
|
||||
if (_controllers.Pole)
|
||||
Gizmos.DrawLine(_joints.Mid.position, _controllers.Pole.position);
|
||||
|
||||
// Bones
|
||||
Gizmos.color = Color.white;
|
||||
Gizmos.DrawLine(_joints.Start.position, _joints.Mid.position);
|
||||
Gizmos.DrawLine(_joints.Mid.position, _joints.End.position);
|
||||
Gizmos.matrix = _joints.Start.localToWorldMatrix;
|
||||
Gizmos.DrawWireSphere(Vector3.zero, _debug.Size * .15f);
|
||||
Gizmos.matrix = _joints.Mid.localToWorldMatrix;
|
||||
Gizmos.DrawWireSphere(Vector3.zero, _debug.Size * .15f);
|
||||
Gizmos.matrix = _joints.End.localToWorldMatrix;
|
||||
Gizmos.DrawWireSphere(Vector3.zero, _debug.Size * .15f);
|
||||
|
||||
// Target
|
||||
if (_controllers.Target)
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.matrix = _controllers.Target.localToWorldMatrix;
|
||||
Gizmos.DrawWireCube(Vector3.zero, Vector3.one * _debug.Size);
|
||||
}
|
||||
|
||||
// Pole
|
||||
if (_controllers.Pole)
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.matrix = _controllers.Pole.localToWorldMatrix;
|
||||
Gizmos.DrawWireCube(Vector3.zero, Vector3.one * _debug.Size * .5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5a9786856021274fbe10be8b0cef721
|
||||
@@ -0,0 +1,49 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class OctoIkRaycast : MonoBehaviour
|
||||
{
|
||||
public float _distance = 1;
|
||||
public Vector3 rotationOffset;
|
||||
public Transform _target;
|
||||
public LayerMask _layerMask;
|
||||
|
||||
Vector3 originPos;
|
||||
Vector3 targetPos;
|
||||
Quaternion originRot;
|
||||
Quaternion targetRot;
|
||||
|
||||
void Start()
|
||||
{
|
||||
originPos = targetPos = _target.localPosition;
|
||||
originRot = targetRot = _target.localRotation;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
float deltaPos = Time.deltaTime * 3f;
|
||||
float deltaRot = Time.deltaTime * 3f;
|
||||
|
||||
RaycastHit hit;
|
||||
|
||||
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, _distance, _layerMask))
|
||||
{
|
||||
Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * hit.distance, Color.yellow);
|
||||
|
||||
targetPos = transform.InverseTransformPoint(hit.point);
|
||||
targetRot = Quaternion.LookRotation(-transform.InverseTransformDirection(hit.normal), transform.up) * Quaternion.Euler(rotationOffset);
|
||||
|
||||
deltaPos = Mathf.Lerp(1, deltaPos, Mathf.Clamp01(hit.distance / _distance));
|
||||
deltaRot = Mathf.Lerp(.1f, deltaRot, Mathf.Clamp01(hit.distance / _distance));
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * _distance, Color.white);
|
||||
|
||||
targetPos = originPos;
|
||||
targetRot = originRot;
|
||||
}
|
||||
|
||||
_target.localPosition = Vector3.Lerp(_target.localPosition, targetPos, deltaPos);
|
||||
_target.localRotation = Quaternion.Lerp(_target.localRotation, targetRot, deltaRot);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99a9ae539a68f554cbab92ca6eb4e7e5
|
||||
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore
|
||||
{
|
||||
[DefaultExecutionOrder(-102)]
|
||||
public class OctoLink : MonoBehaviour
|
||||
{
|
||||
[SerializeField] Object _octoCore;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (!OctoCore.Instance && _octoCore)
|
||||
Instantiate(_octoCore);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aca1ddad5b073a9488d37617a5fd8d9a
|
||||
@@ -0,0 +1,297 @@
|
||||
using OctoCore.Inputs;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.Components
|
||||
{
|
||||
public class OctoPlayer : MonoBehaviour
|
||||
{
|
||||
public static OctoPlayer Instance { get; private set; }
|
||||
|
||||
public enum PlayerModes { FirstPerson, ThirdPerson }
|
||||
public enum Orientations { World, Camera }
|
||||
|
||||
[System.Serializable]
|
||||
private class References
|
||||
{
|
||||
public CharacterController Controller;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class Settings
|
||||
{
|
||||
public PlayerModes Mode = PlayerModes.FirstPerson;
|
||||
public Orientations Orientation = Orientations.Camera;
|
||||
|
||||
[Tooltip("Walk speed (km/h).")]
|
||||
public float WalkSpeed = 10;
|
||||
|
||||
[Tooltip("Run speed (km/h).")]
|
||||
public float RunSpeed = 20;
|
||||
|
||||
[Tooltip("Jump duration (seconds).")]
|
||||
public float JumpDuration = .4f;
|
||||
|
||||
[Tooltip("Maximum jump height reached at the apex (meters).")]
|
||||
public float JumpHeight = .4f;
|
||||
|
||||
[Tooltip("Downward acceleration applied to the player (m/s²).")]
|
||||
public float Gravity = 9.8f;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class Mapping
|
||||
{
|
||||
public OctoActions MoveAction;
|
||||
public OctoActions LookAction;
|
||||
public OctoActions RunAction;
|
||||
public OctoActions JumpAction;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class FirstPerson
|
||||
{
|
||||
[Header("References")]
|
||||
|
||||
public Camera Camera;
|
||||
|
||||
[Header("Settings")]
|
||||
|
||||
[Tooltip("Horizontal sensitivity (Yaw).")]
|
||||
public float SensitivityX = 0.1f;
|
||||
|
||||
[Tooltip("Vertical sensitivity (Pitch).")]
|
||||
public float SensitivityY = 0.1f;
|
||||
|
||||
[Tooltip("Minimum pitch (looking down).")]
|
||||
public float MinPitch = -80f;
|
||||
|
||||
[Tooltip("Maximum pitch (looking up).")]
|
||||
public float MaxPitch = 80f;
|
||||
}
|
||||
|
||||
[SerializeField] private References _references;
|
||||
[SerializeField] private Settings _settings;
|
||||
[SerializeField] private Mapping _mapping;
|
||||
[SerializeField] private FirstPerson _firstPerson;
|
||||
|
||||
private bool _isPaused;
|
||||
private bool _jumpInput;
|
||||
private bool _jumpping;
|
||||
private bool _runInput;
|
||||
private float _runInertia;
|
||||
private float _yaw;
|
||||
private float _pitch;
|
||||
private float _jumpLerp;
|
||||
private float _jumpTime;
|
||||
private float _jumpAltitude;
|
||||
private Vector2 _moveInput;
|
||||
private Vector2 _lookInput;
|
||||
private Vector3 _moveInertia;
|
||||
private Vector3 _moveDirection;
|
||||
|
||||
public bool IsPaused => _isPaused;
|
||||
public float Radius => _references.Controller ? _references.Controller.radius : 0;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (!Instance) Instance = this;
|
||||
else Destroy(gameObject);
|
||||
|
||||
OctoCore.Instance.Inputs.SubscribeAction(_mapping.MoveAction, Move);
|
||||
OctoCore.Instance.Inputs.SubscribeAction(_mapping.LookAction, Look);
|
||||
OctoCore.Instance.Inputs.SubscribeAction(_mapping.RunAction, Run);
|
||||
OctoCore.Instance.Inputs.SubscribeAction(_mapping.JumpAction, Jump);
|
||||
|
||||
_yaw = transform.eulerAngles.y;
|
||||
|
||||
Pause(_isPaused);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
OctoCore.Instance.Inputs.UnsubscribeAction(_mapping.MoveAction, Move);
|
||||
OctoCore.Instance.Inputs.UnsubscribeAction(_mapping.RunAction, Run);
|
||||
OctoCore.Instance.Inputs.UnsubscribeAction(_mapping.JumpAction, Jump);
|
||||
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
_moveInput = _isPaused ? Vector2.zero : Vector2.ClampMagnitude(_moveInput, 1);
|
||||
Camera cam = (_firstPerson.Camera && _firstPerson.Camera.enabled && _firstPerson.Camera.gameObject.activeInHierarchy) ? _firstPerson.Camera : Camera.main;
|
||||
|
||||
bool accelerating = _moveInput.magnitude > .1f;
|
||||
bool isGrounded = _references.Controller ? _references.Controller.isGrounded : true;
|
||||
float t = Time.deltaTime / 3.6f;
|
||||
|
||||
// Move
|
||||
|
||||
Vector3 move = new Vector3(_moveInput.x, 0, _moveInput.y);
|
||||
|
||||
if (_settings.Orientation == Orientations.Camera && cam)
|
||||
{
|
||||
Vector3 camForward = cam.transform.forward;
|
||||
camForward.y = 0;
|
||||
camForward.Normalize();
|
||||
|
||||
Vector3 camRight = cam.transform.right;
|
||||
camRight.y = 0;
|
||||
camRight.Normalize();
|
||||
|
||||
move = camRight * move.x + camForward * move.z;
|
||||
}
|
||||
|
||||
float deltaSmooth = t * (accelerating ? 30 : 15);
|
||||
_moveDirection = Vector3.Lerp(_moveDirection, move, deltaSmooth * 1.5f);
|
||||
|
||||
deltaSmooth *= 1 - Vector3.Cross(_moveInertia, _moveDirection).magnitude;
|
||||
_moveInertia = Vector3.Lerp(_moveInertia, move, deltaSmooth);
|
||||
|
||||
if (!accelerating && _moveInertia.magnitude < .01f) _moveInertia = Vector3.zero;
|
||||
|
||||
_runInertia = Mathf.Lerp(_runInertia, _runInput ? 1 : 0, t * (accelerating ? 5 : 3));
|
||||
|
||||
Vector3 moveDelta = _moveInertia * t * Mathf.Lerp(_settings.WalkSpeed, _settings.RunSpeed, _runInertia);
|
||||
|
||||
if (isGrounded && _jumpInput && !_jumpping)
|
||||
{
|
||||
_jumpInput = false;
|
||||
_jumpping = true;
|
||||
_jumpLerp = 0;
|
||||
_jumpTime = Time.timeSinceLevelLoad;
|
||||
_jumpAltitude = transform.position.y;
|
||||
}
|
||||
|
||||
float jumpOffset = 0;
|
||||
|
||||
if (_jumpping)
|
||||
{
|
||||
_jumpLerp = (Time.timeSinceLevelLoad - _jumpTime) / _settings.JumpDuration;
|
||||
|
||||
if (_jumpLerp >= 1 || (_jumpLerp > .3f && isGrounded))
|
||||
{
|
||||
_jumpping = false;
|
||||
_jumpLerp = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
float x = _jumpLerp;
|
||||
x = x * 2 - 1f;
|
||||
|
||||
float y;
|
||||
if (x < 0) y = Mathf.Sqrt(1f - x * x);
|
||||
else y = Mathf.Cos(x * .5f * Mathf.PI);
|
||||
y = _jumpAltitude + y * _settings.JumpHeight;
|
||||
|
||||
jumpOffset = y - transform.position.y;
|
||||
}
|
||||
}
|
||||
|
||||
if (_jumpping)
|
||||
moveDelta.y = jumpOffset;
|
||||
else
|
||||
moveDelta.y -= _settings.Gravity * Time.deltaTime;
|
||||
|
||||
if (_references.Controller)
|
||||
_references.Controller.Move(moveDelta);
|
||||
else
|
||||
transform.position += moveDelta;
|
||||
|
||||
// Rotate
|
||||
|
||||
switch (_settings.Mode)
|
||||
{
|
||||
case PlayerModes.FirstPerson:
|
||||
if (cam && !_isPaused)
|
||||
{
|
||||
Vector2 delta = _lookInput;
|
||||
|
||||
float mouseX = delta.x * _firstPerson.SensitivityX;
|
||||
float mouseY = delta.y * _firstPerson.SensitivityY * -1;
|
||||
|
||||
_yaw += mouseX;
|
||||
_pitch = Mathf.Clamp(_pitch + mouseY, _firstPerson.MinPitch, _firstPerson.MaxPitch);
|
||||
|
||||
transform.rotation = Quaternion.Euler(0, _yaw, 0);
|
||||
cam.transform.localRotation = Quaternion.Euler(_pitch, 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case PlayerModes.ThirdPerson:
|
||||
{
|
||||
Quaternion targetRot = transform.rotation;
|
||||
if (_moveInertia.magnitude > .002f)
|
||||
{
|
||||
Vector3 offset = _moveInertia - _moveDirection;
|
||||
offset *= _moveInertia.magnitude * _runInertia;
|
||||
offset = Vector3.ClampMagnitude(offset * 1f, 1f);
|
||||
Vector3 up = (Vector3.up - offset).normalized;
|
||||
Quaternion lookRot = Quaternion.LookRotation(_moveInertia, up);
|
||||
targetRot = Quaternion.Lerp(targetRot, lookRot, t * 30);
|
||||
}
|
||||
transform.rotation = targetRot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset
|
||||
|
||||
_moveInput = Vector2.zero;
|
||||
_lookInput = Vector2.zero;
|
||||
_runInput = false;
|
||||
}
|
||||
|
||||
public void Teleport(Vector3 position, Quaternion rotation)
|
||||
{
|
||||
_isPaused = _jumpInput = _jumpping = _runInput = false;
|
||||
_runInertia = _jumpLerp = _jumpTime = _jumpAltitude = 0;
|
||||
_moveInput = _lookInput = Vector2.zero;
|
||||
_moveInertia = _moveDirection = Vector3.zero;
|
||||
_yaw = rotation.eulerAngles.y;
|
||||
_pitch = 0;
|
||||
|
||||
if (_references.Controller)
|
||||
_references.Controller.enabled = false;
|
||||
|
||||
transform.position = position;
|
||||
transform.rotation = rotation;
|
||||
|
||||
if (_references.Controller)
|
||||
_references.Controller.enabled = true;
|
||||
}
|
||||
|
||||
public void Pause(bool pause)
|
||||
{
|
||||
_isPaused = pause;
|
||||
|
||||
if (OctoCore.Instance)
|
||||
OctoCore.Instance.UI.SetCursor();
|
||||
}
|
||||
|
||||
private void Move(Vector2 value) { _moveInput = value; }
|
||||
private void Look(Vector2 value) { _lookInput = value; }
|
||||
private void Run() { _runInput = true; }
|
||||
private void Jump() { _jumpInput = true; }
|
||||
|
||||
private void SetMode()
|
||||
{
|
||||
switch (_settings.Mode)
|
||||
{
|
||||
case PlayerModes.FirstPerson:
|
||||
// Activate First Person Camera
|
||||
break;
|
||||
|
||||
case PlayerModes.ThirdPerson:
|
||||
// Activate Third Person Camera
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*public static float Arc(float x)
|
||||
{
|
||||
x = Mathf.Clamp01(x) * 2 - 1f;
|
||||
return Mathf.Sqrt(1f - x * x);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c85c0434d95406f4da8daa149ba90838
|
||||
@@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using OctoCore.Save.Data;
|
||||
|
||||
namespace OctoCore.Components
|
||||
{
|
||||
public class OctoSaveEvent : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private OctoData data;
|
||||
|
||||
[SerializeField] private bool invertValue;
|
||||
|
||||
[SerializeField] private UnityEvent<bool> onInitBool;
|
||||
[SerializeField] private UnityEvent<int> onInitInt;
|
||||
[SerializeField] private UnityEvent<float> onInitFloat;
|
||||
[SerializeField] private UnityEvent<string> onInitString;
|
||||
[SerializeField] private UnityEvent<Vector4> onInitVector;
|
||||
|
||||
[SerializeField] private UnityEvent<bool> onChangeBool;
|
||||
[SerializeField] private UnityEvent<int> onChangeInt;
|
||||
[SerializeField] private UnityEvent<float> onChangeFloat;
|
||||
[SerializeField] private UnityEvent<string> onChangeString;
|
||||
[SerializeField] private UnityEvent<Vector4> onChangeVector;
|
||||
|
||||
private Action<bool> onValueChangedBool;
|
||||
private Action<int> onValueChangedInt;
|
||||
private Action<float> onValueChangedFloat;
|
||||
private Action<string> onValueChangedString;
|
||||
private Action<Vector4> onValueChangedVector;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (!OctoCore.Instance) return;
|
||||
|
||||
if (data)
|
||||
{
|
||||
switch (data)
|
||||
{
|
||||
case global::OctoCore.Save.Data.OctoDataBool:
|
||||
OnValueInit(OctoCore.Instance.Save.GetBool(data.Id));
|
||||
OctoCore.Instance.Save.Subscribe(data, onValueChangedBool = OnValueChanged);
|
||||
break;
|
||||
|
||||
case global::OctoCore.Save.Data.OctoDataInt:
|
||||
OnValueInit(OctoCore.Instance.Save.GetInt(data.Id));
|
||||
OctoCore.Instance.Save.Subscribe(data, onValueChangedInt = OnValueChanged);
|
||||
break;
|
||||
|
||||
case global::OctoCore.Save.Data.OctoDataFloat:
|
||||
OnValueInit(OctoCore.Instance.Save.GetFloat(data.Id));
|
||||
OctoCore.Instance.Save.Subscribe(data, onValueChangedFloat = OnValueChanged);
|
||||
break;
|
||||
|
||||
case global::OctoCore.Save.Data.OctoDataString:
|
||||
OnValueInit(OctoCore.Instance.Save.GetString(data.Id));
|
||||
OctoCore.Instance.Save.Subscribe(data, onValueChangedString = OnValueChanged);
|
||||
break;
|
||||
|
||||
case global::OctoCore.Save.Data.OctoDataVector:
|
||||
OnValueInit(OctoCore.Instance.Save.GetVector(data.Id));
|
||||
OctoCore.Instance.Save.Subscribe(data, onValueChangedVector = OnValueChanged);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (OctoCore.Instance.Development.Log)
|
||||
Debug.Log($"Unsupported data: {data.Id}");
|
||||
break;
|
||||
}
|
||||
|
||||
if (OctoCore.Instance.Development.Log && data)
|
||||
Debug.Log($"{name} subscribed on: {data.Id}");
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log && data)
|
||||
{
|
||||
Debug.Log($"Data is null");
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (!OctoCore.Instance) return;
|
||||
|
||||
if (data)
|
||||
{
|
||||
if (onValueChangedBool != null)
|
||||
{
|
||||
OctoCore.Instance.Save.Unsubscribe(data, onValueChangedBool);
|
||||
onValueChangedBool = null;
|
||||
}
|
||||
|
||||
if (onValueChangedInt != null)
|
||||
{
|
||||
OctoCore.Instance.Save.Unsubscribe(data, onValueChangedInt);
|
||||
onValueChangedInt = null;
|
||||
}
|
||||
|
||||
if (onValueChangedFloat != null)
|
||||
{
|
||||
OctoCore.Instance.Save.Unsubscribe(data, onValueChangedFloat);
|
||||
onValueChangedFloat = null;
|
||||
}
|
||||
|
||||
if (onValueChangedString != null)
|
||||
{
|
||||
OctoCore.Instance.Save.Unsubscribe(data, onValueChangedString);
|
||||
onValueChangedString = null;
|
||||
}
|
||||
|
||||
if (onValueChangedVector != null)
|
||||
{
|
||||
OctoCore.Instance.Save.Unsubscribe(data, onValueChangedVector);
|
||||
onValueChangedVector = null;
|
||||
}
|
||||
|
||||
if (OctoCore.Instance.Development.Log && data)
|
||||
Debug.Log($"{name} unsubscribed on: {data.Id}");
|
||||
}
|
||||
}
|
||||
|
||||
void OnValueInit()
|
||||
{
|
||||
if (OctoCore.Instance.Development.Log && data)
|
||||
Debug.Log($"Value initialized on: {data.Id}");
|
||||
}
|
||||
|
||||
void OnValueInit(bool value)
|
||||
{
|
||||
onInitBool?.Invoke(invertValue ? !value : value);
|
||||
OnValueInit();
|
||||
}
|
||||
|
||||
void OnValueInit(int value)
|
||||
{
|
||||
onInitInt?.Invoke(value);
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
void OnValueInit(float value)
|
||||
{
|
||||
onInitFloat?.Invoke(value);
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
void OnValueInit(string value)
|
||||
{
|
||||
onInitString?.Invoke(value);
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
void OnValueInit(Vector4 value)
|
||||
{
|
||||
onInitVector?.Invoke(value);
|
||||
OnValueInit();
|
||||
}
|
||||
|
||||
void OnValueChanged()
|
||||
{
|
||||
if (OctoCore.Instance.Development.Log && data)
|
||||
Debug.Log($"Value changed on: {data.Id}");
|
||||
}
|
||||
|
||||
void OnValueChanged(bool value)
|
||||
{
|
||||
onChangeBool?.Invoke(invertValue ? !value : value);
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
void OnValueChanged(int value)
|
||||
{
|
||||
onChangeInt?.Invoke(value);
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
void OnValueChanged(float value)
|
||||
{
|
||||
onChangeFloat?.Invoke(value);
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
void OnValueChanged(string value)
|
||||
{
|
||||
onChangeString?.Invoke(value);
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
void OnValueChanged(Vector4 value)
|
||||
{
|
||||
onChangeVector?.Invoke(value);
|
||||
OnValueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2978f4ffc9fdd0f4387d6b5e41746646
|
||||
@@ -0,0 +1,42 @@
|
||||
using UnityEngine;
|
||||
using OctoCore.Save.Data;
|
||||
|
||||
namespace OctoCore.Components
|
||||
{
|
||||
public class OctoSaveProxy : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private OctoData data;
|
||||
|
||||
public void SetData(OctoData data)
|
||||
{
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void SetBool(bool value)
|
||||
{
|
||||
if (OctoCore.Instance)
|
||||
OctoCore.Instance.Save.Set(data as global::OctoCore.Save.Data.OctoDataBool, value);
|
||||
}
|
||||
public void SetInt(int value)
|
||||
{
|
||||
if (OctoCore.Instance)
|
||||
OctoCore.Instance.Save.Set(data as global::OctoCore.Save.Data.OctoDataInt, value);
|
||||
}
|
||||
public void SetFloat(float value)
|
||||
{
|
||||
if (OctoCore.Instance)
|
||||
OctoCore.Instance.Save.Set(data as global::OctoCore.Save.Data.OctoDataFloat, value);
|
||||
}
|
||||
public void SetString(string value)
|
||||
{
|
||||
if (OctoCore.Instance)
|
||||
OctoCore.Instance.Save.Set(data as global::OctoCore.Save.Data.OctoDataString, value);
|
||||
}
|
||||
public void SetVector(Vector4 value)
|
||||
{
|
||||
if (OctoCore.Instance)
|
||||
OctoCore.Instance.Save.Set(data as global::OctoCore.Save.Data.OctoDataVector, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1b0281cf6e469a43ad8ef7171913dad
|
||||
@@ -0,0 +1,201 @@
|
||||
using OctoCore.Inputs;
|
||||
using OctoCore.Utilities;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace OctoCore.Components
|
||||
{
|
||||
public class OctoWorldEvent : MonoBehaviour
|
||||
{
|
||||
public enum Conditions { None, Player, Tags, Targets }
|
||||
|
||||
//[SerializeField] private InputActionAsset _actionAsset;
|
||||
//[SerializeField] private InputActionReference _actionReference;
|
||||
//[Space(10)]
|
||||
|
||||
[SerializeField] private Utilities.OctoEvents _trigger;
|
||||
[SerializeField] private OctoActions _action;
|
||||
[SerializeField] private Conditions _condition;
|
||||
[SerializeField] private string[] _tags;
|
||||
[SerializeField] private GameObject[] _targets;
|
||||
[SerializeField] private UnityEvent _onTrigger;
|
||||
|
||||
private bool _playerInside;
|
||||
private bool[] _tagsInside;
|
||||
private bool[] _targetsInside;
|
||||
|
||||
private const string PlayerTag = "Player";
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_tagsInside = new bool[_tags.Length];
|
||||
_targetsInside = new bool[_targets.Length];
|
||||
|
||||
switch (_trigger)
|
||||
{
|
||||
case Utilities.OctoEvents.Awake:
|
||||
SetTrigger();
|
||||
break;
|
||||
|
||||
case Utilities.OctoEvents.Action:
|
||||
OctoCore.Instance.Inputs.SubscribeAction(_action, SetTrigger);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (_trigger == Utilities.OctoEvents.OnEnable)
|
||||
SetTrigger();
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (_trigger == Utilities.OctoEvents.Start)
|
||||
SetTrigger();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_trigger == Utilities.OctoEvents.Update)
|
||||
SetTrigger();
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (_trigger == Utilities.OctoEvents.LateUpdate)
|
||||
SetTrigger();
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
if (_trigger == Utilities.OctoEvents.FixedUpdate)
|
||||
SetTrigger();
|
||||
}
|
||||
void OnDisable()
|
||||
{
|
||||
if (_trigger == Utilities.OctoEvents.OnDisable)
|
||||
SetTrigger();
|
||||
|
||||
_playerInside = false;
|
||||
_tagsInside = new bool[_tags.Length];
|
||||
_targetsInside = new bool[_targets.Length];
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
switch (_trigger)
|
||||
{
|
||||
case Utilities.OctoEvents.OnDestroy:
|
||||
SetTrigger();
|
||||
break;
|
||||
|
||||
case Utilities.OctoEvents.Action:
|
||||
OctoCore.Instance?.Inputs.UnsubscribeAction(_action, SetTrigger);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnTriggerEnter(Collider col)
|
||||
{
|
||||
if (_trigger == Utilities.OctoEvents.OnTriggerEnter)
|
||||
{
|
||||
EvaluateTrigger(col);
|
||||
SetTrigger();
|
||||
}
|
||||
}
|
||||
|
||||
void OnTriggerStay(Collider col)
|
||||
{
|
||||
EvaluateTrigger(col);
|
||||
if (_trigger == Utilities.OctoEvents.OnTriggerStay)
|
||||
SetTrigger();
|
||||
}
|
||||
|
||||
void OnTriggerExit(Collider col)
|
||||
{
|
||||
if (_trigger == Utilities.OctoEvents.OnTriggerExit)
|
||||
SetTrigger();
|
||||
EvaluateTrigger(col, false);
|
||||
}
|
||||
|
||||
public void SetTrigger()
|
||||
{
|
||||
switch (_condition)
|
||||
{
|
||||
case Conditions.None:
|
||||
_onTrigger?.Invoke();
|
||||
break;
|
||||
|
||||
case Conditions.Player:
|
||||
if (_playerInside)
|
||||
_onTrigger?.Invoke();
|
||||
break;
|
||||
|
||||
case Conditions.Tags:
|
||||
for (int i = 0; i < _tagsInside.Length; i++)
|
||||
{
|
||||
if (_tagsInside[i])
|
||||
{
|
||||
_onTrigger?.Invoke();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Conditions.Targets:
|
||||
for (int i = 0; i < _targetsInside.Length; i++)
|
||||
{
|
||||
if (_targetsInside[i])
|
||||
{
|
||||
_onTrigger?.Invoke();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EvaluateTrigger(Collider col, bool inside = true)
|
||||
{
|
||||
switch (_condition)
|
||||
{
|
||||
case Conditions.Player:
|
||||
if (col.tag == PlayerTag)
|
||||
_playerInside = inside;
|
||||
break;
|
||||
|
||||
case Conditions.Tags:
|
||||
if (_tags.Contains(col.tag))
|
||||
{
|
||||
for (int i = 0; i < _tags.Length; i++)
|
||||
{
|
||||
bool tagMatch = col.tag == _tags[i];
|
||||
if (tagMatch)
|
||||
{
|
||||
_tagsInside[i] = inside ? tagMatch : !tagMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Conditions.Targets:
|
||||
if (_targets.Contains(col.gameObject))
|
||||
{
|
||||
for (int i = 0; i < _targets.Length; i++)
|
||||
{
|
||||
bool targetMatch = col.gameObject == _targets[i];
|
||||
if (targetMatch)
|
||||
{
|
||||
_targetsInside[i] = inside ? targetMatch : !targetMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5170627695bd877419928fa9ca37865d
|
||||
Reference in New Issue
Block a user