changed: more detail to observers. gizmos fixed and editor layout cleaned up

This commit is contained in:
Chris
2025-07-27 14:16:58 -04:00
parent 7ee82db2cb
commit 1c27be3e2f
3 changed files with 143 additions and 78 deletions

View File

@@ -2,12 +2,13 @@ using NodeCanvas.Framework;
using ParadoxNotion.Design;
using UnityEngine;
namespace NodeCanvas.Tasks.Conditions {
[Category("Reset")]
public class CheckEnvironmentObserver : ConditionTask<PlayerEnvironmentManager>{
public BBParameter<string> observerLabel;
public BBParameter<RaycastHit> outputHitTo;
//Use for initialization. This is called only once in the lifetime of the task.
//Return null if init was successfull. Return an error string otherwise
protected override string OnInit(){
@@ -32,7 +33,22 @@ namespace NodeCanvas.Tasks.Conditions {
//Called once per frame while the condition is active.
//Return whether the condition is success or failure.
protected override bool OnCheck(){
return agent.EvaluateFromString(observerLabel.value);
if (agent.EvaluateFromString(observerLabel.value) == true) {
if (outputHitTo.isDefined) {
EnvironmentObserver hitObserver = agent.FindObserverFromString(observerLabel.value, agent.observers);
if (hitObserver.hit.Equals(default(RaycastHit))) {
Debug.LogError("You just tried to pull a RaycastHit for later use from an environment observer, but no RaycastHit is available. Don't forget that CastType.Box and CastType.Sphere CANNOT spit one out!");
} else {
outputHitTo.value = hitObserver.hit;
return true;
}
}
return true;
}
return false;
}
}
}

View File

@@ -5,12 +5,12 @@ using Drawing;
using Sirenix.OdinInspector;
using Sirenix.Serialization;
using Unity.Mathematics;
using UnityEngine.Serialization;
[Serializable]
public class EnvironmentObserver{
// TODO: Clean this ugly shit up. Custom inspector with Odin plz.
public string label;
public bool drawLabel;
enum LabelDrawingLocation{
PlayerOffset,
@@ -18,66 +18,96 @@ public class EnvironmentObserver{
IntersectingLength,
}
enum CastType{
public enum CastType{
Ray,
Box,
Sphere,
BoxOverlap,
SphereOverlap,
BoxCast,
SphereCast
}
// [BoxGroup("Settings")]
[ShowInInspector, SerializeField] public CastType castType;
[Button(ButtonSizes.Large), GUIColor("@GetObserverStatusColorStatic(active, hit)")]
public void Active(){
active = !active;
}
[ShowInInspector, SerializeField]
CastType castType;
[HideInInspector]
public bool active;
// Parameters for Cast cast types
[BoxGroup("Settings")]
public float length;
[BoxGroup("Settings")]
public Vector3 direction;
[BoxGroup("Settings")]
public Vector3 offset;
[ShowIfGroup("Settings/Casts3D", VisibleIf = "@castType == CastType.Ray || castType == CastType.BoxCast || castType == CastType.SphereCast")]
[BoxGroup("Settings/Casts3D")]
public float width;
// Parameters for Overlap cast types
[BoxGroup("Settings/Overlaps")]
public Vector3 size;
[PropertyTooltip(
"Only use rotation when an observers direction alone can't (for whatever reason) fully be expressed without specifying a rotation.")]
[ShowIfGroup("Settings/Casts3D")]
[BoxGroup("Settings/Casts3D")]
public Vector3 rotation;
[BoxGroup("Settings")]
public LayerMask ignoreLayers = ~0;
public RaycastHit hit;
[SerializeReference]
public List<EnvironmentObserver> children;
[HideInInspector]
public Collider[] overlapHits;
public bool drawLabel;
public Vector3 labelLocationOffset;
public Vector3 labelRotationOffset;
[ShowInInspector, SerializeField]
LabelDrawingLocation labelLocation;
public bool active;
// Parameters
public float length;
public float width;
public Vector3 size;
public Vector3 rotation;
public Vector3 start;
public Vector3 direction;
public bool useLayerMask;
public LayerMask ignoreMask;
public RaycastHit hit;
private Collider[] overlapHits;
// NOTE: I had a ref for a RaycastHit here that would correspond to hit but idk if it's needed.
public bool Evaluate(GameObject player){
if (active) {
ignoreMask -= player.layer;
Vector3 relativeStart = player.transform.position + start;
Vector3 startOffsetFromRotation = player.transform.position + player.transform.rotation * (start) ;
float halfExtents = width / 2f;
// NOTE: I had a ref for a RaycastHit here that would correspond to hit but idk if it's needed.
// Remove player's layer from LayerMask.
ignoreLayers -= player.layer;
// Set some of the variables used later during casting
Vector3 relativeStart = player.transform.position + offset;
Vector3 relativeStartWithRotation = player.transform.position + player.transform.rotation * (offset) ;
switch (castType) {
case CastType.Ray:
Physics.Raycast(relativeStart, player.transform.rotation * direction, out hit, length, ignoreMask);
Physics.Raycast(relativeStart, player.transform.rotation * direction, out hit, length, ignoreLayers);
break;
case CastType.Box:
if (Physics.OverlapBox(startOffsetFromRotation, size / 2f, player.transform.rotation * Quaternion.Euler(rotation), ignoreMask).Length > 0) {
case CastType.BoxOverlap:
overlapHits = Physics.OverlapBox(relativeStartWithRotation, size / 2f,
player.transform.rotation * Quaternion.Euler(rotation), ignoreLayers);
if (overlapHits.Length > 0) {
return true;
};
break;
case CastType.Sphere:
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, Vector3.one * (width / 2f), (player.transform.rotation * Quaternion.Euler(rotation) * direction),
out hit, Quaternion.LookRotation(direction) * Quaternion.Euler(rotation), length, ignoreLayers)
);
break;
case CastType.SphereCast:
break;
@@ -87,13 +117,12 @@ public class EnvironmentObserver{
return true;
}
}
hit = default;
return false;
}
public void DrawObserverGizmo(GameObject player){
Vector3 relativeStart = player.transform.position + start;
Vector3 startOffsetFromRotation = player.transform.position + player.transform.rotation * (start) ;
Vector3 relativeStart = player.transform.position + offset;
Vector3 relativeStartWithRotation = player.transform.position + player.transform.rotation * (offset) ;
Color gizmoColor = Evaluate(player) ? Color.green : Color.red;
gizmoColor = active ? gizmoColor : Color.gray;
@@ -120,12 +149,22 @@ public class EnvironmentObserver{
case CastType.Ray:
Draw.ingame.Line(relativeStart, relativeStart + (player.transform.rotation * direction.normalized) * length);
break;
case CastType.Box:
Draw.ingame.WireBox(startOffsetFromRotation, player.transform.rotation * Quaternion.Euler(rotation), size);
case CastType.BoxOverlap:
Draw.ingame.WireBox(relativeStartWithRotation, player.transform.rotation * Quaternion.Euler(rotation), size);
break;
case CastType.Sphere:
case CastType.SphereOverlap:
break;
case CastType.BoxCast:
// Create an offset start point for the center of the wirebox, since gizmos are drawn with their pivot in the center.
Vector3 offsetWithRotationAndLength = (Quaternion.LookRotation(direction) * Quaternion.Euler(rotation)) * (Vector3.forward * length / 2f);
Vector3 offsetFromCenter = relativeStartWithRotation + player.transform.rotation * offsetWithRotationAndLength;
// Also create a rotation for use with the gizmos. Mainly just to shorten the lines
Quaternion gizmosRotation = player.transform.rotation * Quaternion.LookRotation(direction) * Quaternion.Euler(rotation);
// Draw the gizmos for the boxcast
Draw.ingame.WireBox(relativeStartWithRotation, gizmosRotation, Vector3.one * width);
Draw.ingame.WireBox(offsetFromCenter, gizmosRotation, new float3(width, width, length + width));
break;
default:
throw new ArgumentOutOfRangeException();
@@ -139,14 +178,28 @@ public class EnvironmentObserver{
LabelAlignment.Center,
Color.black
);
Sirenix.Utilities.Editor.GUIHelper.RequestRepaint();
}
}
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<EnvironmentObserver> observers;
void Start(){
CheckDuplicateLabels(observers);
}
@@ -219,6 +272,7 @@ public class PlayerEnvironmentManager : MonoBehaviour{
}
void LateUpdate(){
// Draw Gizmos
foreach (EnvironmentObserver observer in observers) {
observer.DrawObserverGizmo(gameObject);
@@ -228,5 +282,16 @@ public class PlayerEnvironmentManager : MonoBehaviour{
}
}
}
// Clear hit
foreach (EnvironmentObserver observer in observers) {
observer.hit = default;
if (observer.children != null && observer.children.Count > 0) {
foreach (EnvironmentObserver childObserver in observer.children) {
childObserver.hit = default;
}
}
}
}
}