3 Commits

9 changed files with 81793 additions and 6056 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -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<Collider> ignoreObjects = new List<Collider>();
[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<EnvironmentObserver> 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<Collider> collidersAsList = new List<Collider>();
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<Collider>())) {
collidersAsList.Remove(source.GetComponent<Collider>());
}
}
// 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<IInteractable>();
if (interactable != null && interactable.CanInteract()) {
hit.transform.GetComponent<IInteractable>().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;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0aad4dcbee894497b63c2954e0961e7b
timeCreated: 1765311249

View File

@@ -0,0 +1,49 @@
using UnityEngine;
namespace Reset.Units{
public interface ILockOnTarget{
public float lockonTargetRadius{ set; get; }
public bool lockonDebug{ set; get; }
public float lockonRaycastVerticalOffset{ set; get; }
Transform transform{ get; }
GameObject gameObject{ get; }
abstract void OnTargetDelete();
void Help(){
SafelyDeleteTarget();
}
public Vector3 GetReticlePosition(){
float upValue = 0f;
if (gameObject.GetComponent<Renderer>()) {
Bounds objectBounds = gameObject.GetComponent<Renderer>().bounds;
upValue = objectBounds.size.y;
upValue = 4f;
}
Vector3 reticlePosition =
new Vector3(transform.position.x, transform.position.y + upValue, transform.position.z);
return reticlePosition;
}
public void SafelyDeleteTarget(){
// gameObject.
foreach (LockOnManager.ActiveLockOnTarget target in LockOnManager.Instance.activeTargets) {
if (target.gameObject == this.gameObject) {
GameObject clone = new GameObject
{ name = $"Target Clone of {gameObject.name}", transform = { position = transform.position } };
target.gameObject = clone;
target.cinemachineTarget.Object = clone.transform;
LockOnManager.Instance.QueueTargetRemoval(clone, true);
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3cf599680bc840b59ee6ea3cd0114ab8
timeCreated: 1765311171

View File

@@ -1,54 +1,6 @@
using System;
using UnityEngine;
namespace Reset.Units{
public interface ILockOnTarget{
public float lockonTargetRadius{ set; get; }
public bool lockonDebug{ set; get; }
public float lockonRaycastVerticalOffset{ set; get; }
Transform transform{ get; }
GameObject gameObject{ get; }
abstract void OnTargetDelete();
void Help(){
SafelyDeleteTarget();
}
public Vector3 GetReticlePosition(){
float upValue = 0f;
if (gameObject.GetComponent<Renderer>()) {
Bounds objectBounds = gameObject.GetComponent<Renderer>().bounds;
upValue = objectBounds.size.y;
upValue = 4f;
}
Vector3 reticlePosition =
new Vector3(transform.position.x, transform.position.y + upValue, transform.position.z);
return reticlePosition;
}
public void SafelyDeleteTarget(){
// gameObject.
foreach (LockOnManager.ActiveLockOnTarget target in LockOnManager.Instance.activeTargets) {
if (target.gameObject == this.gameObject) {
GameObject clone = new GameObject
{ name = $"Target Clone of {gameObject.name}", transform = { position = transform.position } };
target.gameObject = clone;
target.cinemachineTarget.Object = clone.transform;
LockOnManager.Instance.QueueTargetRemoval(clone, true);
}
}
}
}
}
public class PlayerCamera : MonoBehaviour{
void Start(){

View File

@@ -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<Collider> ignoreObjects = new List<Collider>();
[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<EnvironmentObserver> 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<Collider> collidersAsList = new List<Collider>();
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<Collider>())) {
collidersAsList.Remove(source.GetComponent<Collider>());
}
}
// 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<IInteractable>();
if (interactable != null && interactable.CanInteract()) {
hit.transform.GetComponent<IInteractable>().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<EnvironmentObserver> observers;