diff --git a/Assets/Scripts/Units/EnvironmentObserver.cs b/Assets/Scripts/Units/EnvironmentObserver.cs new file mode 100644 index 0000000..13b7398 --- /dev/null +++ b/Assets/Scripts/Units/EnvironmentObserver.cs @@ -0,0 +1,300 @@ +using System; +using System.Collections.Generic; +using Drawing; +using Sirenix.OdinInspector; +using Unity.Mathematics; +using UnityEngine; + +[Serializable] +public class EnvironmentObserver{ + enum LabelDrawingLocation{ + PlayerOffset, + HitLocation, + IntersectingLength, + } + + enum ObserverGizmoDrawingCondition{ + Always, + OnlyActive, + Never + } + + public enum CastType{ + Ray, + BoxOverlap, + SphereOverlap, + BoxCast, + SphereCast + } + + [PropertySpace(0, 5), LabelWidth(60)] + public string label; + [PropertySpace(0, 10), LabelWidth(60)] + public CastType castType; + + [Button(ButtonSizes.Large), GUIColor("@GetObserverStatusColorStatic(active, hit)"), PropertyOrder(-1), PropertySpace(5, 5)] + public void Active(){ + active = !active; + } + + [HideInInspector] + public bool active; + + // Parameters for Cast cast types + [FoldoutGroup("Settings")] [HideIf("@castType == CastType.BoxOverlap || castType == CastType.SphereOverlap")] + public float length; + [FoldoutGroup("Settings")] public Vector3 direction; + [FoldoutGroup("Settings")] public Vector3 offset; + [PropertySpace(0, 5), FoldoutGroup("Settings")] public LayerMask ignoreLayers = ~0; + + [FoldoutGroup("Settings")] [ShowIf("@castType == CastType.BoxOverlap || castType == CastType.SphereOverlap")] + public List ignoreObjects = new List(); + + [FoldoutGroup("Settings")] [ShowIf("@castType == CastType.BoxOverlap || castType == CastType.SphereOverlap")] + public bool dontIgnoreSelf; + + [ShowIfGroup("Settings/SpheresOnly", VisibleIf = "@castType == CastType.SphereCast || castType == CastType.SphereOverlap")] + [FoldoutGroup("Settings")] public float width; + + // Parameters for Overlap cast types + [FoldoutGroup("Settings")] + [ShowIfGroup("Settings/BoxesOnly", VisibleIf = "@castType == CastType.BoxCast || castType == CastType.BoxOverlap")] + public Vector3 size; + + [ShowIfGroup("Settings/BoxesOnly")] + public Vector3 rotation; + + [HideInInspector] + public RaycastHit hit; + + [HideInInspector] + public Collider[] overlapHits; + + [FoldoutGroup("Text")] + [BoxGroup("Text/Label")] public bool drawLabel; + [ShowInInspector, SerializeField] [BoxGroup("Text/Label")] LabelDrawingLocation labelTextLocation; + [BoxGroup("Text/Label")] public float labelSize; + [BoxGroup("Text/Label")] public Vector3 labelLocationOffset; + [BoxGroup("Text/Label")] public Vector3 labelRotationOffset; + + [BoxGroup("Text/Hit")] public bool drawHitName; + [ShowInInspector, SerializeField] [BoxGroup("Text/Hit")] LabelDrawingLocation hitTextLocation; + [BoxGroup("Text/Hit")] public float hitTextSize; + [BoxGroup("Text/Hit")] public Vector3 hitLocationOffset; + [BoxGroup("Text/Hit")] public Vector3 hitRotationOffset; + [FoldoutGroup("Text"), SerializeField, ShowInInspector] ObserverGizmoDrawingCondition gizmoDrawingCondition; + + [SerializeReference, PropertySpace(5, 5)] + public List children; + + // NOTE: I had a ref for a RaycastHit here that would correspond to hit but idk if it's needed. + public bool Evaluate(GameObject source){ + if (active) { + // Remove player's layer from LayerMask. + // ignoreLayers <<= source.layer; // TODO: Rework + + // Set some of the variables used later during casting + Vector3 relativeStart = source.transform.position + offset; + Vector3 relativeStartWithRotation = source.transform.position + source.transform.rotation * offset ; + + switch (castType) { + case CastType.Ray: + Physics.Raycast(relativeStart, source.transform.rotation * direction, out hit, length, ignoreLayers); + break; + case CastType.BoxOverlap: + // Create original box overlap + Collider[] originalOverlap = Physics.OverlapBox(relativeStartWithRotation, size / 2f, + source.transform.rotation * Quaternion.Euler(rotation), ignoreLayers); + + // Convert to a list for editing + List collidersAsList = new List(); + collidersAsList.AddRange(originalOverlap); + + // Remove any specifically specified objects + foreach (Collider ignoredObject in ignoreObjects) { + if (collidersAsList.Contains(ignoredObject)) { + collidersAsList.Remove(ignoredObject); + } + } + + // Remove the source but only if requested + if (!dontIgnoreSelf) { + if (collidersAsList.Contains(source.GetComponent())) { + collidersAsList.Remove(source.GetComponent()); + } + } + + // Send back to an array and done + overlapHits = collidersAsList.ToArray(); + + if (overlapHits.Length > 0) { + return true; + }; + + break; + case CastType.SphereOverlap: + break; + case CastType.BoxCast: + // TODO: Make this not an if statement. Check that it works with NodeCanvas first + if (Physics.BoxCast(relativeStartWithRotation, size / 2f, + source.transform.rotation * Quaternion.Euler(rotation) * direction, + out hit, source.transform.rotation * Quaternion.Euler(rotation), length, + ignoreLayers) + ) { + }; + break; + case CastType.SphereCast: + // TODO: Make this not an if statement. Check that it works with NodeCanvas first + if (Physics.SphereCast(relativeStartWithRotation, width / 2f, + source.transform.rotation * Quaternion.Euler(rotation) * direction, + out hit, length, + ignoreLayers) + ) { + }; + break; + } + + if (hit.transform != null) { + IInteractable interactable = hit.transform.GetComponent(); + if (interactable != null && interactable.CanInteract()) { + hit.transform.GetComponent().OnObserverDetected(this); + } + return true; + } + } + return false; + } + + public void DrawObserverGizmo(GameObject source, bool drawAnyways = false){ + if (!drawAnyways){ + if (gizmoDrawingCondition == ObserverGizmoDrawingCondition.Never || (gizmoDrawingCondition == ObserverGizmoDrawingCondition.OnlyActive ! & active)) { + return; + } + } + + Vector3 relativeStart = source.transform.position + offset; + Vector3 relativeStartWithRotation = source.transform.position + source.transform.rotation * (offset); + + // Setup the variables for boxcast, spherecast, etc + // Create an offset start point for the center of the wirebox, since gizmos are drawn with their pivot in the center. + Vector3 offsetWithRotationAndLength; + if (direction == Vector3.zero) { + offsetWithRotationAndLength = Quaternion.Euler(rotation) * (Vector3.forward * (length / 2)); + } else { + offsetWithRotationAndLength = Quaternion.LookRotation(direction) * Quaternion.Euler(rotation) * (Vector3.forward * (length / 2)); + } + + Vector3 offsetFromCenter = relativeStartWithRotation + source.transform.rotation * offsetWithRotationAndLength; + + // Also create a rotation for use with the gizmos. Mainly just to shorten the lines + Quaternion gizmosRotation; + + if (direction == Vector3.zero) { + gizmosRotation = source.transform.rotation * Quaternion.Euler(rotation); + } else { + gizmosRotation = source.transform.rotation * Quaternion.LookRotation(direction) * Quaternion.Euler(rotation); + } + + Color gizmoColor = Evaluate(source) ? Color.green : Color.red; + gizmoColor = active ? gizmoColor : Color.gray; + + using (Draw.ingame.WithColor(gizmoColor)){ + switch (castType) { + case CastType.Ray: + Draw.ingame.Line(relativeStart, relativeStart + (source.transform.rotation * direction.normalized) * length); + break; + case CastType.BoxOverlap: + Draw.ingame.WireBox(relativeStartWithRotation, source.transform.rotation * Quaternion.Euler(rotation), size); + break; + case CastType.SphereCast: + Draw.ingame.SolidCircle(relativeStartWithRotation, relativeStartWithRotation - Camera.main.transform.position, width * 1, gizmoColor.Alpha(.5f)); + Draw.ingame.WireCapsule(relativeStartWithRotation, relativeStartWithRotation + gizmosRotation * (Vector3.forward * (length - width / 2)), width); + break; + case CastType.BoxCast: + // Draw the gizmos for the boxcast + Draw.ingame.WireBox(offsetFromCenter, gizmosRotation, new float3(size.x, size.y, length)); + Draw.ingame.SolidBox(relativeStartWithRotation, gizmosRotation, size, gizmoColor.Alpha(.1f)); + + Draw.ingame.WireBox(relativeStartWithRotation, gizmosRotation, size); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + Draw.ingame.SolidCircle(relativeStartWithRotation, relativeStartWithRotation - Camera.main.transform.position, .4f); + Draw.ingame.SolidCircle(hit.point, hit.point - Camera.main.transform.position, .4f); + + // Set up variables for label (not hit name) + Vector3 labelStartPos = Vector3.zero; + switch (labelTextLocation) { + case LabelDrawingLocation.PlayerOffset: + labelStartPos = source.transform.position; + break; + case LabelDrawingLocation.IntersectingLength: + labelStartPos = offsetFromCenter; + break; + case LabelDrawingLocation.HitLocation:{ + if (hit.transform != null) { + labelStartPos = hit.point; + } + + break; + } + } + + // Draw label + if (drawLabel) { + Draw.ingame.Label3D( + labelStartPos + labelLocationOffset, + gizmosRotation * Quaternion.Euler(labelRotationOffset), + label, + labelSize, + LabelAlignment.MiddleLeft, + gizmoColor + ); + } + + // Set up variables for hit name + // Since the label is already drawn just use the previous startPos + switch (labelTextLocation) { + case LabelDrawingLocation.PlayerOffset: + labelStartPos = source.transform.position; + break; + case LabelDrawingLocation.IntersectingLength: + labelStartPos = offsetFromCenter; + break; + case LabelDrawingLocation.HitLocation:{ + if (hit.transform != null) { + labelStartPos = hit.point; + } + + break; + } + } + + // Draw hitname + if (drawLabel) { + Draw.ingame.Label3D( + labelStartPos + labelLocationOffset, + gizmosRotation * Quaternion.Euler(labelRotationOffset), + label, + hitTextSize, + LabelAlignment.MiddleLeft, + gizmoColor + ); + } + } + } + + static Color GetObserverStatusColorStatic(bool active, RaycastHit hit){ + if (active) { + if (hit.Equals(default(RaycastHit))) { + return Color.green; + } + + return Color.red; + } + + return Color.gray; + } +} \ No newline at end of file diff --git a/Assets/Scripts/Units/EnvironmentObserver.cs.meta b/Assets/Scripts/Units/EnvironmentObserver.cs.meta new file mode 100644 index 0000000..e356499 --- /dev/null +++ b/Assets/Scripts/Units/EnvironmentObserver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0aad4dcbee894497b63c2954e0961e7b +timeCreated: 1765311249 \ No newline at end of file diff --git a/Assets/Scripts/Units/PlayerEnvironmentManager.cs b/Assets/Scripts/Units/PlayerEnvironmentManager.cs index 867ef79..66adbaf 100644 --- a/Assets/Scripts/Units/PlayerEnvironmentManager.cs +++ b/Assets/Scripts/Units/PlayerEnvironmentManager.cs @@ -1,306 +1,8 @@ -using System; using System.Collections.Generic; using UnityEngine; -using Drawing; -using Sirenix.OdinInspector; using Sirenix.Serialization; -using Unity.Mathematics; using UnityEngine.Serialization; -[Serializable] -public class EnvironmentObserver{ - enum LabelDrawingLocation{ - PlayerOffset, - HitLocation, - IntersectingLength, - } - - enum ObserverGizmoDrawingCondition{ - Always, - OnlyActive, - Never - } - - public enum CastType{ - Ray, - BoxOverlap, - SphereOverlap, - BoxCast, - SphereCast - } - - [PropertySpace(0, 5), LabelWidth(60)] - public string label; - [PropertySpace(0, 10), LabelWidth(60)] - public CastType castType; - - [Button(ButtonSizes.Large), GUIColor("@GetObserverStatusColorStatic(active, hit)"), PropertyOrder(-1), PropertySpace(5, 5)] - public void Active(){ - active = !active; - } - - [HideInInspector] - public bool active; - - // Parameters for Cast cast types - [FoldoutGroup("Settings")] [HideIf("@castType == CastType.BoxOverlap || castType == CastType.SphereOverlap")] - public float length; - [FoldoutGroup("Settings")] public Vector3 direction; - [FoldoutGroup("Settings")] public Vector3 offset; - [PropertySpace(0, 5), FoldoutGroup("Settings")] public LayerMask ignoreLayers = ~0; - - [FoldoutGroup("Settings")] [ShowIf("@castType == CastType.BoxOverlap || castType == CastType.SphereOverlap")] - public List ignoreObjects = new List(); - - [FoldoutGroup("Settings")] [ShowIf("@castType == CastType.BoxOverlap || castType == CastType.SphereOverlap")] - public bool dontIgnoreSelf; - - [ShowIfGroup("Settings/SpheresOnly", VisibleIf = "@castType == CastType.SphereCast || castType == CastType.SphereOverlap")] - [FoldoutGroup("Settings")] public float width; - - // Parameters for Overlap cast types - [FoldoutGroup("Settings")] - [ShowIfGroup("Settings/BoxesOnly", VisibleIf = "@castType == CastType.BoxCast || castType == CastType.BoxOverlap")] - public Vector3 size; - - [ShowIfGroup("Settings/BoxesOnly")] - public Vector3 rotation; - - [HideInInspector] - public RaycastHit hit; - - [HideInInspector] - public Collider[] overlapHits; - - [FoldoutGroup("Text")] - [BoxGroup("Text/Label")] public bool drawLabel; - [ShowInInspector, SerializeField] [BoxGroup("Text/Label")] LabelDrawingLocation labelTextLocation; - [BoxGroup("Text/Label")] public float labelSize; - [BoxGroup("Text/Label")] public Vector3 labelLocationOffset; - [BoxGroup("Text/Label")] public Vector3 labelRotationOffset; - - [BoxGroup("Text/Hit")] public bool drawHitName; - [ShowInInspector, SerializeField] [BoxGroup("Text/Hit")] LabelDrawingLocation hitTextLocation; - [BoxGroup("Text/Hit")] public float hitTextSize; - [BoxGroup("Text/Hit")] public Vector3 hitLocationOffset; - [BoxGroup("Text/Hit")] public Vector3 hitRotationOffset; - [FoldoutGroup("Text"), SerializeField, ShowInInspector] ObserverGizmoDrawingCondition gizmoDrawingCondition; - - [SerializeReference, PropertySpace(5, 5)] - public List children; - - // NOTE: I had a ref for a RaycastHit here that would correspond to hit but idk if it's needed. - public bool Evaluate(GameObject source){ - if (active) { - // Remove player's layer from LayerMask. - // ignoreLayers <<= source.layer; // TODO: Rework - - // Set some of the variables used later during casting - Vector3 relativeStart = source.transform.position + offset; - Vector3 relativeStartWithRotation = source.transform.position + source.transform.rotation * offset ; - - switch (castType) { - case CastType.Ray: - Physics.Raycast(relativeStart, source.transform.rotation * direction, out hit, length, ignoreLayers); - break; - case CastType.BoxOverlap: - // Create original box overlap - Collider[] originalOverlap = Physics.OverlapBox(relativeStartWithRotation, size / 2f, - source.transform.rotation * Quaternion.Euler(rotation), ignoreLayers); - - // Convert to a list for editing - List collidersAsList = new List(); - collidersAsList.AddRange(originalOverlap); - - // Remove any specifically specified objects - foreach (Collider ignoredObject in ignoreObjects) { - if (collidersAsList.Contains(ignoredObject)) { - collidersAsList.Remove(ignoredObject); - } - } - - // Remove the source but only if requested - if (!dontIgnoreSelf) { - if (collidersAsList.Contains(source.GetComponent())) { - collidersAsList.Remove(source.GetComponent()); - } - } - - // Send back to an array and done - overlapHits = collidersAsList.ToArray(); - - if (overlapHits.Length > 0) { - return true; - }; - - break; - case CastType.SphereOverlap: - break; - case CastType.BoxCast: - // TODO: Make this not an if statement. Check that it works with NodeCanvas first - if (Physics.BoxCast(relativeStartWithRotation, size / 2f, - source.transform.rotation * Quaternion.Euler(rotation) * direction, - out hit, source.transform.rotation * Quaternion.Euler(rotation), length, - ignoreLayers) - ) { - }; - break; - case CastType.SphereCast: - // TODO: Make this not an if statement. Check that it works with NodeCanvas first - if (Physics.SphereCast(relativeStartWithRotation, width / 2f, - source.transform.rotation * Quaternion.Euler(rotation) * direction, - out hit, length, - ignoreLayers) - ) { - }; - break; - } - - if (hit.transform != null) { - IInteractable interactable = hit.transform.GetComponent(); - if (interactable != null && interactable.CanInteract()) { - hit.transform.GetComponent().OnObserverDetected(this); - } - return true; - } - } - return false; - } - - public void DrawObserverGizmo(GameObject source, bool drawAnyways = false){ - if (!drawAnyways){ - if (gizmoDrawingCondition == ObserverGizmoDrawingCondition.Never || (gizmoDrawingCondition == ObserverGizmoDrawingCondition.OnlyActive ! & active)) { - return; - } - } - - Vector3 relativeStart = source.transform.position + offset; - Vector3 relativeStartWithRotation = source.transform.position + source.transform.rotation * (offset); - - // Setup the variables for boxcast, spherecast, etc - // Create an offset start point for the center of the wirebox, since gizmos are drawn with their pivot in the center. - Vector3 offsetWithRotationAndLength; - if (direction == Vector3.zero) { - offsetWithRotationAndLength = Quaternion.Euler(rotation) * (Vector3.forward * (length / 2)); - } else { - offsetWithRotationAndLength = Quaternion.LookRotation(direction) * Quaternion.Euler(rotation) * (Vector3.forward * (length / 2)); - } - - Vector3 offsetFromCenter = relativeStartWithRotation + source.transform.rotation * offsetWithRotationAndLength; - - // Also create a rotation for use with the gizmos. Mainly just to shorten the lines - Quaternion gizmosRotation; - - if (direction == Vector3.zero) { - gizmosRotation = source.transform.rotation * Quaternion.Euler(rotation); - } else { - gizmosRotation = source.transform.rotation * Quaternion.LookRotation(direction) * Quaternion.Euler(rotation); - } - - Color gizmoColor = Evaluate(source) ? Color.green : Color.red; - gizmoColor = active ? gizmoColor : Color.gray; - - using (Draw.ingame.WithColor(gizmoColor)){ - switch (castType) { - case CastType.Ray: - Draw.ingame.Line(relativeStart, relativeStart + (source.transform.rotation * direction.normalized) * length); - break; - case CastType.BoxOverlap: - Draw.ingame.WireBox(relativeStartWithRotation, source.transform.rotation * Quaternion.Euler(rotation), size); - break; - case CastType.SphereCast: - Draw.ingame.SolidCircle(relativeStartWithRotation, relativeStartWithRotation - Camera.main.transform.position, width * 1, gizmoColor.Alpha(.5f)); - Draw.ingame.WireCapsule(relativeStartWithRotation, relativeStartWithRotation + gizmosRotation * (Vector3.forward * (length - width / 2)), width); - break; - case CastType.BoxCast: - // Draw the gizmos for the boxcast - Draw.ingame.WireBox(offsetFromCenter, gizmosRotation, new float3(size.x, size.y, length)); - Draw.ingame.SolidBox(relativeStartWithRotation, gizmosRotation, size, gizmoColor.Alpha(.1f)); - - Draw.ingame.WireBox(relativeStartWithRotation, gizmosRotation, size); - break; - default: - throw new ArgumentOutOfRangeException(); - } - - Draw.ingame.SolidCircle(relativeStartWithRotation, relativeStartWithRotation - Camera.main.transform.position, .4f); - Draw.ingame.SolidCircle(hit.point, hit.point - Camera.main.transform.position, .4f); - - // Set up variables for label (not hit name) - Vector3 labelStartPos = Vector3.zero; - switch (labelTextLocation) { - case LabelDrawingLocation.PlayerOffset: - labelStartPos = source.transform.position; - break; - case LabelDrawingLocation.IntersectingLength: - labelStartPos = offsetFromCenter; - break; - case LabelDrawingLocation.HitLocation:{ - if (hit.transform != null) { - labelStartPos = hit.point; - } - - break; - } - } - - // Draw label - if (drawLabel) { - Draw.ingame.Label3D( - labelStartPos + labelLocationOffset, - gizmosRotation * Quaternion.Euler(labelRotationOffset), - label, - labelSize, - LabelAlignment.MiddleLeft, - gizmoColor - ); - } - - // Set up variables for hit name - // Since the label is already drawn just use the previous startPos - switch (labelTextLocation) { - case LabelDrawingLocation.PlayerOffset: - labelStartPos = source.transform.position; - break; - case LabelDrawingLocation.IntersectingLength: - labelStartPos = offsetFromCenter; - break; - case LabelDrawingLocation.HitLocation:{ - if (hit.transform != null) { - labelStartPos = hit.point; - } - - break; - } - } - - // Draw hitname - if (drawLabel) { - Draw.ingame.Label3D( - labelStartPos + labelLocationOffset, - gizmosRotation * Quaternion.Euler(labelRotationOffset), - label, - hitTextSize, - LabelAlignment.MiddleLeft, - gizmoColor - ); - } - } - } - - static Color GetObserverStatusColorStatic(bool active, RaycastHit hit){ - if (active) { - if (hit.Equals(default(RaycastHit))) { - return Color.green; - } - - return Color.red; - } - - return Color.gray; - } -} - public class PlayerEnvironmentManager : MonoBehaviour{ [OdinSerialize] public List observers;