init
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92d4ae60438d4ddc92655e075655c935
|
||||
timeCreated: 1719507871
|
||||
@@ -0,0 +1,114 @@
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VOID.Generic.Projectile.Drawers
|
||||
{
|
||||
public class BeamProjectileDrawer : MonoBehaviour
|
||||
{
|
||||
[Title("Positions")]
|
||||
[SerializeField] private bool autoPositions;
|
||||
[HideIf(nameof(autoPositions))] [SerializeField] [Required] private Transform from;
|
||||
[HideIf(nameof(autoPositions))] [SerializeField] [Required] private Transform to;
|
||||
|
||||
[Title("Prefabs")]
|
||||
[InfoBox("Those prefabs are from addon MagicArsenal located in <b>Assets/_ADDONS/MagicArsenal/Effects/Prefabs/Beams/Setup</b>")]
|
||||
[SerializeField] [Required] private GameObject beamLineRendererPrefab;
|
||||
[SerializeField] [Required] private GameObject beamStartPrefab;
|
||||
[SerializeField] [Required] private GameObject beamEndPrefab;
|
||||
|
||||
[Title("Beam Options")]
|
||||
[SerializeField] private float textureScrollSpeed = 5f;
|
||||
[SerializeField] private float textureLengthScale = 5f;
|
||||
|
||||
[Title("Width Pulse Options")]
|
||||
[SerializeField] private float startScale = 1.0f;
|
||||
[SerializeField] private float endScale = 1.0f;
|
||||
[SerializeField] private float pulseSpeed = 1.0f;
|
||||
|
||||
private GameObject _beamStart;
|
||||
private GameObject _beamEnd;
|
||||
private GameObject _beam;
|
||||
private LineRenderer _line;
|
||||
|
||||
private float _lerpValue;
|
||||
private bool _pulseExpanding;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
if (autoPositions)
|
||||
{
|
||||
GetComponent<ProjectileObject>().onStart.AddListener(SetPositions);
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
SpawnBeam();
|
||||
}
|
||||
|
||||
private void SetPositions(ProjectileObject projectile)
|
||||
{
|
||||
from = projectile.caster.unitData.castPosition;
|
||||
to = projectile.gameObject.transform;
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (_beam)
|
||||
{
|
||||
var fromPosition = from.position;
|
||||
var toPosition = to.position;
|
||||
|
||||
_line.SetPosition(0, fromPosition);
|
||||
_line.SetPosition(1, toPosition);
|
||||
|
||||
_beamStart.transform.position = fromPosition;
|
||||
_beamStart.transform.LookAt(toPosition);
|
||||
_beamEnd.transform.position = toPosition;
|
||||
_beamEnd.transform.LookAt(fromPosition);
|
||||
|
||||
var distance = Vector3.Distance(fromPosition, toPosition);
|
||||
|
||||
//This sets the scale of the texture so it doesn't look stretched
|
||||
_line.material.mainTextureScale = new Vector2(distance / textureLengthScale, 1);
|
||||
//This scrolls the texture along the beam if not set to 0
|
||||
_line.material.mainTextureOffset -= new Vector2(Time.deltaTime * textureScrollSpeed, 0);
|
||||
}
|
||||
|
||||
_lerpValue += (_pulseExpanding ? 1 : -1) * Time.deltaTime * pulseSpeed;
|
||||
|
||||
if (_lerpValue >= 1.0f)
|
||||
{
|
||||
_pulseExpanding = false;
|
||||
_lerpValue = 1.0f;
|
||||
}
|
||||
else if (_lerpValue <= 0.0f)
|
||||
{
|
||||
_pulseExpanding = true;
|
||||
_lerpValue = 0.0f;
|
||||
}
|
||||
|
||||
var currentWidth = Mathf.Lerp(startScale, endScale, Mathf.Sin(_lerpValue * Mathf.PI));
|
||||
|
||||
_line.startWidth = currentWidth;
|
||||
_line.endWidth = currentWidth;
|
||||
}
|
||||
|
||||
private void SpawnBeam()
|
||||
{
|
||||
if (!beamLineRendererPrefab) return;
|
||||
|
||||
_beam = Instantiate(beamLineRendererPrefab);
|
||||
_beam.transform.position = transform.position;
|
||||
_beam.transform.parent = transform;
|
||||
_beam.transform.rotation = transform.rotation;
|
||||
|
||||
_line = _beam.GetComponent<LineRenderer>();
|
||||
_line.useWorldSpace = true;
|
||||
_line.positionCount = 2;
|
||||
|
||||
_beamStart = beamStartPrefab ? Instantiate(beamStartPrefab, _beam.transform) : null;
|
||||
_beamEnd = beamEndPrefab ? Instantiate(beamEndPrefab, _beam.transform) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e925d1593dd43368f3237aa42ca8315
|
||||
timeCreated: 1719507917
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 95c27c54fd7e439fbc57d8a89b3eda77
|
||||
timeCreated: 1694376610
|
||||
@@ -0,0 +1,10 @@
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
|
||||
namespace VOID.Generic.Projectile.HitValidator
|
||||
{
|
||||
public interface IProjectileHitValidator
|
||||
{
|
||||
public bool IsValid(UnitObject caster, AbstractObject target);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 923e7c5bc9bd414297e822c7c46ad8b0
|
||||
@@ -0,0 +1,16 @@
|
||||
using Sirenix.OdinInspector;
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Item;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
|
||||
namespace VOID.Generic.Projectile.HitValidator
|
||||
{
|
||||
[TypeRegistryItem("Item")]
|
||||
public class ProjectileHitItem : IProjectileHitValidator
|
||||
{
|
||||
public bool IsValid(UnitObject caster, AbstractObject target)
|
||||
{
|
||||
return target is ItemObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 164b8f6c007ed544da396cd6a9874d65
|
||||
@@ -0,0 +1,15 @@
|
||||
using Sirenix.OdinInspector;
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
|
||||
namespace VOID.Generic.Projectile.HitValidator
|
||||
{
|
||||
[TypeRegistryItem("Other")]
|
||||
public class ProjectileHitOther : IProjectileHitValidator
|
||||
{
|
||||
public bool IsValid(UnitObject caster, AbstractObject target)
|
||||
{
|
||||
return caster != target;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b11ba2fe64fb42e794811cf45a8e03ec
|
||||
@@ -0,0 +1,15 @@
|
||||
using Sirenix.OdinInspector;
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
|
||||
namespace VOID.Generic.Projectile.HitValidator
|
||||
{
|
||||
[TypeRegistryItem("Self")]
|
||||
public class ProjectileHitSelf : IProjectileHitValidator
|
||||
{
|
||||
public bool IsValid(UnitObject caster, AbstractObject target)
|
||||
{
|
||||
return caster == target;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa232c3837fa4f23afe8df94a0e3db7b
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.Utilities;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.Dict;
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
|
||||
namespace VOID.Generic.Projectile.HitValidator
|
||||
{
|
||||
[TypeRegistryItem("Unit")]
|
||||
public class ProjectileHitUnit : IProjectileHitValidator
|
||||
{
|
||||
[SerializeField] private List<AttitudeType> _attitudes = new();
|
||||
|
||||
public bool IsValid(UnitObject caster, AbstractObject target)
|
||||
{
|
||||
if (target is not UnitObject targetUnit) return false;
|
||||
if (_attitudes.IsNullOrEmpty()) return true;
|
||||
if (_attitudes.Contains(caster.unitAttitude.GetAttitudeWith(targetUnit))) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1c051c72ef24497a5206391bd86e57c
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VOID.Generic.Projectile
|
||||
{
|
||||
[DefaultExecutionOrder(1)]
|
||||
public class ProjectileAoe : MonoBehaviour
|
||||
{
|
||||
public event Action<Collider> OnAoeEnter;
|
||||
public event Action<Collider> OnAoeExit;
|
||||
|
||||
private void OnTriggerEnter(Collider other) => OnAoeEnter?.Invoke(other);
|
||||
private void OnTriggerExit(Collider other) => OnAoeExit?.Invoke(other);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 908f4254ee0809d4d81ac1c1cd417188
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
using Sirenix.OdinInspector;
|
||||
|
||||
namespace VOID.Generic.Projectile
|
||||
{
|
||||
[InfoBox("What can stop this projectile:\n" +
|
||||
"<u><b>" + nameof(StaticOrDynamicCollision) + "</b></u> any collider\n" +
|
||||
"<u><b>" + nameof(StaticCollision) + "</b></u> only static colliders\n" +
|
||||
"<u><b>" + nameof(NoCollision) + "</b></u> nothing can stop this projectile")]
|
||||
public enum ProjectileCollisionType
|
||||
{
|
||||
StaticOrDynamicCollision,
|
||||
StaticCollision,
|
||||
NoCollision,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 070cbc890f4b4c788eb4ca3a289fbc72
|
||||
timeCreated: 1675895859
|
||||
@@ -0,0 +1,15 @@
|
||||
using Sirenix.OdinInspector;
|
||||
|
||||
namespace VOID.Generic.Projectile
|
||||
{
|
||||
[InfoBox("When projectile can do *OnHit* objects:\n" +
|
||||
"<u><b>" + nameof(Always) + "</b></u> when they touch projectile's collider\n" +
|
||||
"<u><b>" + nameof(OnEnd) + "</b></u> when projectile reach step's end\n" +
|
||||
"<u><b>" + nameof(Never) + "</b></u> projectile on current step won't trigger OnHit")]
|
||||
public enum ProjectileHitType
|
||||
{
|
||||
Always,
|
||||
OnEnd,
|
||||
Never,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 191fa44350354b9dafabf09f8a96d639
|
||||
timeCreated: 1675895939
|
||||
@@ -0,0 +1,267 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Sirenix.Utilities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
using VOID.Generic.Trajectory;
|
||||
|
||||
namespace VOID.Generic.Projectile
|
||||
{
|
||||
/// <summary>
|
||||
/// Moves projectile on defined <see cref="ProjectileStep"/>
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(-1)]
|
||||
public class ProjectileObject : MonoBehaviour
|
||||
{
|
||||
// Projectile Configuration
|
||||
public int index { private set; get; }
|
||||
public UnitObject caster { private set; get; }
|
||||
public ProjectileStep[] steps { private set; get; }
|
||||
|
||||
// Events
|
||||
public UnityEvent<ProjectileObject> onStart = new();
|
||||
public UnityEvent<ProjectileObject, AbstractObject> onHit = new();
|
||||
public UnityEvent<ProjectileObject> onNextStep = new();
|
||||
public UnityEvent<ProjectileObject> onEnd = new();
|
||||
|
||||
// Step info
|
||||
private ProjectileStep _currentStep;
|
||||
private int _currentStepIndex = -1;
|
||||
private float _currentStepDistance;
|
||||
private AbstractTrajectory _currentTrajectory;
|
||||
private Vector3 _startPosition;
|
||||
private Vector3 _targetPosition;
|
||||
private Vector3 _lastHitPosition;
|
||||
|
||||
// Projectile and its AOE game objects
|
||||
private GameObject _gameObject;
|
||||
private GameObject _aoeGameObject;
|
||||
|
||||
// Storing collisions
|
||||
private readonly Dictionary<AbstractObject, int> _aoeCollisions = new();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (MoveProjectile() || CheckCollision()) StartCoroutine(NextStep());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves projectile by one step in trajectory.
|
||||
/// </summary>
|
||||
/// <returns>TRUE if current step reached end</returns>
|
||||
private bool MoveProjectile()
|
||||
{
|
||||
_currentStepDistance += Time.fixedDeltaTime * _currentStep.speed;
|
||||
var newProgress = _currentTrajectory.GetProgressForDistance(_currentStepDistance);
|
||||
var newPosition = _currentTrajectory.GetPositionByProgress(newProgress);
|
||||
|
||||
// Update rotation
|
||||
_gameObject.transform.rotation = Quaternion.LookRotation(transform.position - newPosition);
|
||||
|
||||
// Update position
|
||||
_aoeGameObject.transform.position = transform.position = newPosition;
|
||||
|
||||
return Mathf.Approximately(newProgress, 1f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if projectile should end early because it hit something.
|
||||
/// </summary>
|
||||
/// <returns>TRUE if collision ends this projectile step</returns>
|
||||
private bool CheckCollision()
|
||||
{
|
||||
int layerMask;
|
||||
switch (_currentStep.collisionType)
|
||||
{
|
||||
case ProjectileCollisionType.StaticOrDynamicCollision:
|
||||
layerMask = LayerManager.Static | LayerManager.StaticHideable | LayerManager.Dynamic;
|
||||
break;
|
||||
case ProjectileCollisionType.StaticCollision:
|
||||
layerMask = LayerManager.Static | LayerManager.StaticHideable;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just to be sure - ignore caster :D
|
||||
var colliders = new Collider[2];
|
||||
Physics.OverlapSphereNonAlloc(transform.position, _currentStep.radius, colliders, layerMask);
|
||||
return colliders.Any(collider => collider && collider.GetComponentInParent<UnitObject>() != caster);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts next step of projectile. If no more steps available then whole projectile is destroyed.
|
||||
/// </summary>
|
||||
private IEnumerator NextStep()
|
||||
{
|
||||
// IMPORTANT
|
||||
// 1. Collisions calculate after fixed update, we need to wait 1 (or 2?) fixed updates
|
||||
// to be sure that we dont ignore collision that will occour later this frame in projectile's AOE
|
||||
// 2. Also we want to stop FixedUpdate from running when this happens otherwise this part will be executed twice
|
||||
enabled = false;
|
||||
yield return new WaitForFixedUpdate();
|
||||
enabled = true;
|
||||
|
||||
if (_currentStep.hitType == ProjectileHitType.OnEnd)
|
||||
_aoeCollisions.Keys.ForEach(hitGameObject => onHit.Invoke(this, hitGameObject));
|
||||
|
||||
if (_currentStepIndex >= steps.Length - 1)
|
||||
{
|
||||
EndProjectile();
|
||||
yield break;
|
||||
}
|
||||
|
||||
_lastHitPosition = gameObject.transform.position;
|
||||
onNextStep.Invoke(this);
|
||||
PrepareNextStep();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 1. Clear temporary data<br/>
|
||||
/// 2. Initialize next Trajectory<br/>
|
||||
/// 3. Initialize next Area Of Effect
|
||||
/// </summary>
|
||||
private void PrepareNextStep()
|
||||
{
|
||||
// Clear temp data about previous step
|
||||
_currentStepDistance = 0f;
|
||||
_currentStep = steps[++_currentStepIndex];
|
||||
_aoeCollisions.Clear();
|
||||
_currentTrajectory = _currentStep.trajectory.Clone();
|
||||
|
||||
// Update AOE GameObject's rotation and collider by data in AreaOfEffect
|
||||
// This process can be done once when starting new step, because AOE dont change during flight
|
||||
if (_aoeGameObject.TryGetComponent(out Collider aoeCollider)) Destroy(aoeCollider);
|
||||
_currentStep.areaOfEffect.AddCollider(_aoeGameObject);
|
||||
_aoeGameObject.transform.rotation = _currentStep.areaOfEffect.GetRotation(_startPosition, _targetPosition);
|
||||
|
||||
// Prepare trajectory
|
||||
_currentTrajectory.Init(FindStartPositionForStep(), _targetPosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns start position for current step by defined <see cref="ProjectileStepStartFrom"/>.
|
||||
/// </summary>
|
||||
private Vector3 FindStartPositionForStep()
|
||||
{
|
||||
return _currentStep.startFrom switch
|
||||
{
|
||||
ProjectileStepStartFrom.FromStart => _startPosition,
|
||||
ProjectileStepStartFrom.FromCaster => caster.transform.position,
|
||||
ProjectileStepStartFrom.FromHit => _lastHitPosition == default ? _lastHitPosition : _startPosition,
|
||||
_ => throw new ArgumentOutOfRangeException(
|
||||
nameof(_currentStep.startFrom), _currentStep.startFrom, null)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes and starts whole projectile.
|
||||
/// </summary>
|
||||
/// <param name="index">Index of this projectile from source ability</param>
|
||||
/// <param name="caster">UnitObject that fired this projectile</param>
|
||||
/// <param name="startPosition">Projectile starting position</param>
|
||||
/// <param name="targetPosition">Projectile target position</param>
|
||||
/// <param name="steps">Definition HOW projectile should move and hit</param>
|
||||
public void StartProjectile(
|
||||
int index,
|
||||
UnitObject caster,
|
||||
Vector3 startPosition,
|
||||
Vector3 targetPosition,
|
||||
ProjectileStep[] steps
|
||||
)
|
||||
{
|
||||
this.index = index;
|
||||
this.caster = caster;
|
||||
this.steps = steps;
|
||||
_startPosition = startPosition;
|
||||
_targetPosition = targetPosition;
|
||||
|
||||
// Projectile GameObject
|
||||
_gameObject = gameObject;
|
||||
_gameObject.layer = LayerManager.TriggerIndex;
|
||||
_gameObject.transform.position = _startPosition;
|
||||
_gameObject.SetActive(true);
|
||||
|
||||
// Projectile AOE GameObject
|
||||
_aoeGameObject = new GameObject("Projectile AOE collider");
|
||||
_aoeGameObject.layer = LayerManager.TriggerIndex;
|
||||
_aoeGameObject.transform.position = gameObject.transform.position;
|
||||
|
||||
// Projectile AOE controlling component
|
||||
var projectileAoe = _aoeGameObject.AddComponent<ProjectileAoe>();
|
||||
projectileAoe.OnAoeEnter += OnAoeEnter;
|
||||
projectileAoe.OnAoeExit += OnAoeExit;
|
||||
|
||||
onStart.Invoke(this);
|
||||
|
||||
PrepareNextStep();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends and destroy projectile.
|
||||
/// </summary>
|
||||
private void EndProjectile()
|
||||
{
|
||||
onEnd.Invoke(this);
|
||||
|
||||
// Destroying only projectile's AOE and script, not whole projectile yet!
|
||||
Destroy(this);
|
||||
Destroy(_aoeGameObject);
|
||||
|
||||
// Wait a little bit for other things like VFX to finish then we can safely destroy whole projectile
|
||||
Destroy(_gameObject, 3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checking if given target should be hit and executed OnHit.
|
||||
/// </summary>
|
||||
private bool IsValidHit(UnitObject caster, AbstractObject target)
|
||||
{
|
||||
return _currentStep.validHits.Count == 0 ||
|
||||
_currentStep.validHits.Any(validator => validator.IsValid(caster, target));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collision enter detected by projectile AOE.
|
||||
/// </summary>
|
||||
private void OnAoeEnter(Collider other)
|
||||
{
|
||||
if (!LayerManager.CodeInMask(other.gameObject.layer, LayerManager.Dynamic)) return;
|
||||
|
||||
var hitObject = other.GetComponentInParent<AbstractObject>();
|
||||
if (!hitObject) return;
|
||||
|
||||
if (!IsValidHit(caster, hitObject)) return;
|
||||
|
||||
_aoeCollisions.TryAdd(hitObject, 0);
|
||||
_aoeCollisions[hitObject]++;
|
||||
if (_currentStep.hitType == ProjectileHitType.Always) onHit.Invoke(this, hitObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collision exit detected by projectile AOE.
|
||||
/// </summary>
|
||||
private void OnAoeExit(Collider other)
|
||||
{
|
||||
if (!LayerManager.CodeInMask(other.gameObject.layer, LayerManager.Dynamic)) return;
|
||||
|
||||
var hitObject = other.GetComponentInParent<AbstractObject>();
|
||||
if (!hitObject) return;
|
||||
|
||||
if (!_aoeCollisions.ContainsKey(hitObject)) return;
|
||||
|
||||
_aoeCollisions[hitObject]--;
|
||||
|
||||
if (_aoeCollisions[hitObject] == 0) _aoeCollisions.Remove(hitObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60bc05bd3f5944328cf0613fee18cd40
|
||||
timeCreated: 1668807593
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.AreaOfEffect;
|
||||
using VOID.Generic.Projectile.HitValidator;
|
||||
using VOID.Generic.Projectile.TargetValidator;
|
||||
using VOID.Generic.Trajectory;
|
||||
using VOID.ScriptableObjects.Abilities;
|
||||
|
||||
namespace VOID.Generic.Projectile
|
||||
{
|
||||
/// <summary>
|
||||
/// Defined in <see cref="BasicAbility"/> and used by <see cref="ProjectileObject"/>.
|
||||
/// Defines how projectile will move and hit.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ProjectileStep
|
||||
{
|
||||
// Projectile own HitBox and speed
|
||||
[MinValue(.1f)] public float radius = .1f;
|
||||
[OnValueChanged(nameof(OnValidate)), ShowIf(nameof(ShowSpeed)), MinValue(1f), SuffixLabel("m/s")] public float speed = 10f;
|
||||
|
||||
// Variables which enhance projectile movement and trajectory
|
||||
[OnValueChanged(nameof(OnValidate)), ShowIf(nameof(ShowHitType)), Required] public ProjectileHitType hitType;
|
||||
[OnValueChanged(nameof(OnValidate)), Required] public ProjectileCollisionType collisionType;
|
||||
[Required] public ProjectileStepStartFrom startFrom;
|
||||
|
||||
// Validating if can be targeted or hit
|
||||
[InfoBox("Validates if target can be selected")]
|
||||
[SerializeReference, HorizontalGroup("validating")] public List<IProjectileTargetValidator> validTargets = new();
|
||||
[InfoBox("Validates if object touched by AOE can be hit")]
|
||||
[SerializeReference, HorizontalGroup("validating")] public List<IProjectileHitValidator> validHits = new();
|
||||
|
||||
// Generic definition of TRAJECTORY and AOE
|
||||
[SerializeReference, Required] public AbstractTrajectory trajectory;
|
||||
[SerializeReference, Required] public AbstractAreaOfEffect areaOfEffect;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if (!ShowSpeed()) speed = 10f;
|
||||
if (!ShowHitType()) hitType = ProjectileHitType.Never;
|
||||
}
|
||||
|
||||
private bool ShowSpeed() => trajectory is not InstantTrajectory;
|
||||
private bool ShowHitType() => areaOfEffect is not NoneAreaOfEffect;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49b63bd283fa450faa65160fdfc490d3
|
||||
timeCreated: 1675895813
|
||||
@@ -0,0 +1,15 @@
|
||||
using Sirenix.OdinInspector;
|
||||
|
||||
namespace VOID.Generic.Projectile
|
||||
{
|
||||
[InfoBox("Starting point for this projectile's step:\n" +
|
||||
"<u><b>" + nameof(FromStart) + "</b></u> from casting position\n" +
|
||||
"<u><b>" + nameof(FromCaster) + "</b></u> from caster's position\n" +
|
||||
"<u><b>" + nameof(FromHit) + "</b></u> from current projectile's position")]
|
||||
public enum ProjectileStepStartFrom
|
||||
{
|
||||
FromStart,
|
||||
FromCaster,
|
||||
FromHit,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8fcb71fa9d824e3197961d71956e7115
|
||||
timeCreated: 1694200927
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40e53ece385640aeafea80551c238724
|
||||
timeCreated: 1731080883
|
||||
@@ -0,0 +1,12 @@
|
||||
using JetBrains.Annotations;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
|
||||
namespace VOID.Generic.Projectile.TargetValidator
|
||||
{
|
||||
public interface IProjectileTargetValidator
|
||||
{
|
||||
public bool IsValid(UnitObject caster, Vector3 targetPosition, [CanBeNull] AbstractObject targetObject);
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5995c2ee1ec41f0b43069e5d8fd5bb5
|
||||
timeCreated: 1731080877
|
||||
@@ -0,0 +1,17 @@
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Item;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
|
||||
namespace VOID.Generic.Projectile.TargetValidator
|
||||
{
|
||||
[TypeRegistryItem("Item")]
|
||||
public class ProjectileTargetItem : IProjectileTargetValidator
|
||||
{
|
||||
public bool IsValid(UnitObject caster, Vector3 targetPosition, AbstractObject targetObject)
|
||||
{
|
||||
return targetObject is ItemObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50f8b528d89f4254b041adf5f3400e13
|
||||
timeCreated: 1731099384
|
||||
@@ -0,0 +1,16 @@
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
|
||||
namespace VOID.Generic.Projectile.TargetValidator
|
||||
{
|
||||
[TypeRegistryItem("Other")]
|
||||
public class ProjectileTargetOther : IProjectileTargetValidator
|
||||
{
|
||||
public bool IsValid(UnitObject caster, Vector3 targetPosition, AbstractObject targetObject)
|
||||
{
|
||||
return caster != targetObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa20fa37f9ea4484ac5181068fc23e03
|
||||
timeCreated: 1731089158
|
||||
@@ -0,0 +1,16 @@
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
|
||||
namespace VOID.Generic.Projectile.TargetValidator
|
||||
{
|
||||
[TypeRegistryItem("Self")]
|
||||
public class ProjectileTargetSelf : IProjectileTargetValidator
|
||||
{
|
||||
public bool IsValid(UnitObject caster, Vector3 targetPosition, AbstractObject targetObject)
|
||||
{
|
||||
return caster == targetObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2aac834351ab47d793aa3647a5b3e4ee
|
||||
timeCreated: 1731099384
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.Utilities;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.Dict;
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
|
||||
namespace VOID.Generic.Projectile.TargetValidator
|
||||
{
|
||||
[TypeRegistryItem("Unit")]
|
||||
public class ProjectileTargetUnit : IProjectileTargetValidator
|
||||
{
|
||||
[SerializeField] private List<AttitudeType> _attitudes = new();
|
||||
|
||||
public bool IsValid(UnitObject caster, Vector3 targetPosition, AbstractObject targetObject)
|
||||
{
|
||||
if (targetObject is not UnitObject targetUnit) return false;
|
||||
if (_attitudes.IsNullOrEmpty()) return true;
|
||||
if (_attitudes.Contains(caster.unitAttitude.GetAttitudeWith(targetUnit))) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 443176e8033443c6b192c4d873ed81b1
|
||||
timeCreated: 1731099384
|
||||
@@ -0,0 +1,16 @@
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.Objects.Abstract;
|
||||
using VOID.Generic.Objects.Unit;
|
||||
|
||||
namespace VOID.Generic.Projectile.TargetValidator
|
||||
{
|
||||
[TypeRegistryItem("Walkable")]
|
||||
public class ProjectileTargetWalkable : IProjectileTargetValidator
|
||||
{
|
||||
public bool IsValid(UnitObject caster, Vector3 targetPosition, AbstractObject targetObject)
|
||||
{
|
||||
return caster.unitNavAgent.IsValidGround(targetPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 208d383dab1d4481a6a5e487d9aa3c13
|
||||
timeCreated: 1731099524
|
||||
Reference in New Issue
Block a user