Execute Behaviors
This commit is contained in:
parent
c4d084acb2
commit
e4d35c0af6
@ -78,7 +78,7 @@ Material:
|
|||||||
- _Mode: 0
|
- _Mode: 0
|
||||||
- _OcclusionStrength: 1
|
- _OcclusionStrength: 1
|
||||||
- _Parallax: 0.02
|
- _Parallax: 0.02
|
||||||
- _Rotation: 6.1873918
|
- _Rotation: 6.1601553
|
||||||
- _SmoothnessTextureChannel: 0
|
- _SmoothnessTextureChannel: 0
|
||||||
- _SpecularHighlights: 1
|
- _SpecularHighlights: 1
|
||||||
- _SrcBlend: 1
|
- _SrcBlend: 1
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b8fc798226bf8b24e9bcefd5efa43c31
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,181 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class ProjectileExecutionBehavior : RuntimeBehavior
|
||||||
|
{
|
||||||
|
[Header("Projectile Settings")]
|
||||||
|
public GameObject projectilePrefab;
|
||||||
|
public float projectileSpeed = 15f;
|
||||||
|
public float lifeSpan = 1.5f;
|
||||||
|
public bool canPierce = false;
|
||||||
|
public bool canHitSelf = false;
|
||||||
|
|
||||||
|
[Header("Movement Behaviour")]
|
||||||
|
public AnimationCurve speedOverLifetime = AnimationCurve.Linear(0, 1, 1, 1);
|
||||||
|
public bool useSpeedCurve = false;
|
||||||
|
public bool enableCurving = false;
|
||||||
|
public Vector3 curveAxis = Vector3.up;
|
||||||
|
public float curveStrength = 1f;
|
||||||
|
public float curveAmplitude = 45f;
|
||||||
|
|
||||||
|
public bool enableRicochet = false;
|
||||||
|
public int maxRicochets = 1;
|
||||||
|
public float ricochetSpread = 10f;
|
||||||
|
|
||||||
|
public ProjectileExecutionBehavior()
|
||||||
|
{
|
||||||
|
Trigger = BehaviorTrigger.Execute; // This replaces your Execute() override
|
||||||
|
BehaviorName = "Projectile Execution";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Execute(RuntimeAbilityInstance ability, Taggable user, Transform target, Vector3 point)
|
||||||
|
{
|
||||||
|
// This is your old ProjectileAbility.Execute() logic!
|
||||||
|
|
||||||
|
// Get spawn location
|
||||||
|
var spawnController = user.GetComponentInChildren<ProjectileSpawnLocationController>();
|
||||||
|
Vector3 spawnPos = spawnController?.transform.position ?? user.transform.position;
|
||||||
|
Quaternion spawnRot = spawnController?.transform.rotation ?? user.transform.rotation;
|
||||||
|
|
||||||
|
// Spawn projectile
|
||||||
|
var projectileGO = Object.Instantiate(projectilePrefab, spawnPos, spawnRot);
|
||||||
|
|
||||||
|
// Setup projectile
|
||||||
|
var networkedProjectile = projectileGO.GetComponent<NetworkedProjectile>();
|
||||||
|
if (networkedProjectile != null)
|
||||||
|
{
|
||||||
|
SetupProjectileInstance(ability, networkedProjectile, user);
|
||||||
|
|
||||||
|
networkedProjectile.Init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void SetupProjectileInstance(RuntimeAbilityInstance ability, NetworkedProjectile networkedProjectile, Taggable user)
|
||||||
|
{
|
||||||
|
networkedProjectile.speed = projectileSpeed;
|
||||||
|
networkedProjectile.ownerTag = user;
|
||||||
|
networkedProjectile.ability = ability.SourceAbility;
|
||||||
|
networkedProjectile.lifeSpan = lifeSpan;
|
||||||
|
networkedProjectile.canPierce = canPierce;
|
||||||
|
networkedProjectile.canHitSelf = canHitSelf;
|
||||||
|
networkedProjectile.speedOverLifetime = speedOverLifetime;
|
||||||
|
networkedProjectile.useSpeedCurve = useSpeedCurve;
|
||||||
|
networkedProjectile.enableCurving = enableCurving;
|
||||||
|
networkedProjectile.curveAxis = curveAxis;
|
||||||
|
networkedProjectile.curveStrength = curveStrength;
|
||||||
|
networkedProjectile.curveAmplitude = curveAmplitude;
|
||||||
|
networkedProjectile.enableRicochet = enableRicochet;
|
||||||
|
networkedProjectile.maxRicochets = maxRicochets;
|
||||||
|
networkedProjectile.ricochetSpread = ricochetSpread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override RuntimeBehavior Clone()
|
||||||
|
{
|
||||||
|
return new ProjectileExecutionBehavior
|
||||||
|
{
|
||||||
|
// Basic settings
|
||||||
|
projectilePrefab = this.projectilePrefab,
|
||||||
|
projectileSpeed = this.projectileSpeed,
|
||||||
|
lifeSpan = this.lifeSpan,
|
||||||
|
canPierce = this.canPierce,
|
||||||
|
canHitSelf = this.canHitSelf,
|
||||||
|
|
||||||
|
// Movement behavior
|
||||||
|
speedOverLifetime = this.speedOverLifetime,
|
||||||
|
useSpeedCurve = this.useSpeedCurve,
|
||||||
|
enableCurving = this.enableCurving,
|
||||||
|
curveAxis = this.curveAxis,
|
||||||
|
curveStrength = this.curveStrength,
|
||||||
|
curveAmplitude = this.curveAmplitude,
|
||||||
|
enableRicochet = this.enableRicochet,
|
||||||
|
maxRicochets = this.maxRicochets,
|
||||||
|
ricochetSpread = this.ricochetSpread
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// FACTORY METHODS - Easy Creation of Common Projectile Types
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a simple straight projectile
|
||||||
|
/// </summary>
|
||||||
|
public static ProjectileExecutionBehavior CreateSimple(GameObject prefab, float speed = 15f, float lifeSpan = 5f)
|
||||||
|
{
|
||||||
|
return new ProjectileExecutionBehavior
|
||||||
|
{
|
||||||
|
projectilePrefab = prefab,
|
||||||
|
projectileSpeed = speed,
|
||||||
|
lifeSpan = lifeSpan
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a piercing projectile
|
||||||
|
/// </summary>
|
||||||
|
public static ProjectileExecutionBehavior CreatePiercing(GameObject prefab, float speed = 15f, float lifeSpan = 5f)
|
||||||
|
{
|
||||||
|
return new ProjectileExecutionBehavior
|
||||||
|
{
|
||||||
|
projectilePrefab = prefab,
|
||||||
|
projectileSpeed = speed,
|
||||||
|
lifeSpan = lifeSpan,
|
||||||
|
canPierce = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a curved projectile (like magic missile)
|
||||||
|
/// </summary>
|
||||||
|
public static ProjectileExecutionBehavior CreateCurved(GameObject prefab, float speed = 12f, float curveStrength = 2f)
|
||||||
|
{
|
||||||
|
return new ProjectileExecutionBehavior
|
||||||
|
{
|
||||||
|
projectilePrefab = prefab,
|
||||||
|
projectileSpeed = speed,
|
||||||
|
enableCurving = true,
|
||||||
|
curveStrength = curveStrength,
|
||||||
|
curveAmplitude = 30f
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a ricochet projectile
|
||||||
|
/// </summary>
|
||||||
|
public static ProjectileExecutionBehavior CreateRicochet(GameObject prefab, int maxBounces = 3, float speed = 15f)
|
||||||
|
{
|
||||||
|
return new ProjectileExecutionBehavior
|
||||||
|
{
|
||||||
|
projectilePrefab = prefab,
|
||||||
|
projectileSpeed = speed,
|
||||||
|
enableRicochet = true,
|
||||||
|
maxRicochets = maxBounces,
|
||||||
|
ricochetSpread = 15f
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a projectile with speed curve (accelerating/decelerating)
|
||||||
|
/// </summary>
|
||||||
|
public static ProjectileExecutionBehavior CreateWithSpeedCurve(GameObject prefab, AnimationCurve curve, float baseSpeed = 15f)
|
||||||
|
{
|
||||||
|
return new ProjectileExecutionBehavior
|
||||||
|
{
|
||||||
|
projectilePrefab = prefab,
|
||||||
|
projectileSpeed = baseSpeed,
|
||||||
|
useSpeedCurve = true,
|
||||||
|
speedOverLifetime = curve
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProjectileExecutionBehavior CreateIceshardLikeWithCurve(GameObject prefab, float baseSpeed = 15f)
|
||||||
|
{
|
||||||
|
return new ProjectileExecutionBehavior
|
||||||
|
{
|
||||||
|
projectilePrefab = prefab,
|
||||||
|
projectileSpeed = baseSpeed,
|
||||||
|
useSpeedCurve = true,
|
||||||
|
lifeSpan = 1f,
|
||||||
|
speedOverLifetime = GameConstants.BehaviorUtils.GetIceshardProjectileCurve()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ae360e58fae69584f9a3a850f466195f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -191,6 +191,8 @@ public class RuntimeAbilityInstance
|
|||||||
Health userHealth;
|
Health userHealth;
|
||||||
public virtual void SpendResourcesNecessary(Taggable user)
|
public virtual void SpendResourcesNecessary(Taggable user)
|
||||||
{
|
{
|
||||||
|
if (userMana == null) userMana = user.GetComponent<Mana>();
|
||||||
|
if (userHealth == null) userHealth = user.GetComponent<Health>();
|
||||||
|
|
||||||
userMana.ChangeValue(-GetFinalManaCost(user));
|
userMana.ChangeValue(-GetFinalManaCost(user));
|
||||||
userHealth.ChangeValue(-GetFinalHealthCost(user));
|
userHealth.ChangeValue(-GetFinalHealthCost(user));
|
||||||
@ -202,8 +204,10 @@ public class RuntimeAbilityInstance
|
|||||||
if (!CanExecute(user)) return;
|
if (!CanExecute(user)) return;
|
||||||
|
|
||||||
ExecuteBehaviors(BehaviorTrigger.PreCast, user, null, Vector3.zero);
|
ExecuteBehaviors(BehaviorTrigger.PreCast, user, null, Vector3.zero);
|
||||||
|
|
||||||
SpendResourcesNecessary(user);
|
SpendResourcesNecessary(user);
|
||||||
sourceAbility.Execute(user);
|
ExecuteBehaviors(BehaviorTrigger.Execute, user, null, Vector3.zero);
|
||||||
|
|
||||||
ExecuteBehaviors(BehaviorTrigger.PostCast, user, null, Vector3.zero);
|
ExecuteBehaviors(BehaviorTrigger.PostCast, user, null, Vector3.zero);
|
||||||
|
|
||||||
lastUsedTime = Time.time;
|
lastUsedTime = Time.time;
|
||||||
@ -214,8 +218,10 @@ public class RuntimeAbilityInstance
|
|||||||
if (!CanExecute(user)) return;
|
if (!CanExecute(user)) return;
|
||||||
|
|
||||||
ExecuteBehaviors(BehaviorTrigger.PreCast, user, null, point);
|
ExecuteBehaviors(BehaviorTrigger.PreCast, user, null, point);
|
||||||
|
|
||||||
SpendResourcesNecessary(user);
|
SpendResourcesNecessary(user);
|
||||||
sourceAbility.Execute(user, point);
|
ExecuteBehaviors(BehaviorTrigger.Execute, user, null, point);
|
||||||
|
|
||||||
ExecuteBehaviors(BehaviorTrigger.PostCast, user, null, point);
|
ExecuteBehaviors(BehaviorTrigger.PostCast, user, null, point);
|
||||||
|
|
||||||
lastUsedTime = Time.time;
|
lastUsedTime = Time.time;
|
||||||
@ -226,8 +232,10 @@ public class RuntimeAbilityInstance
|
|||||||
if (!CanExecute(user)) return;
|
if (!CanExecute(user)) return;
|
||||||
|
|
||||||
ExecuteBehaviors(BehaviorTrigger.PreCast, user, target, target.position);
|
ExecuteBehaviors(BehaviorTrigger.PreCast, user, target, target.position);
|
||||||
|
|
||||||
SpendResourcesNecessary(user);
|
SpendResourcesNecessary(user);
|
||||||
sourceAbility.Execute(user, target);
|
ExecuteBehaviors(BehaviorTrigger.Execute, user, target, target.position);
|
||||||
|
|
||||||
ExecuteBehaviors(BehaviorTrigger.PostCast, user, target, target.position);
|
ExecuteBehaviors(BehaviorTrigger.PostCast, user, target, target.position);
|
||||||
|
|
||||||
lastUsedTime = Time.time;
|
lastUsedTime = Time.time;
|
||||||
|
@ -2,12 +2,15 @@ using UnityEngine;
|
|||||||
|
|
||||||
public enum BehaviorTrigger
|
public enum BehaviorTrigger
|
||||||
{
|
{
|
||||||
PreCast, // Before ability executes
|
PreCast, // Before ability executes
|
||||||
Execute, // MAIN EXECUTION - replaces your override Execute()
|
Execute, // MAIN EXECUTION - replaces your override Execute()
|
||||||
PostCast, // After ability executes
|
PostCast, // After ability executes
|
||||||
OnHit, // When ability hits target
|
OnHit, // When ability hits target
|
||||||
OnKill, // When ability kills target
|
OnKill, // When ability kills target
|
||||||
OnCrit // When ability crits
|
OnCrit, // When ability crits
|
||||||
|
OnMiss, // When ability misses
|
||||||
|
OnChannelTick, // During channeling
|
||||||
|
OnChannelEnd // When channeling ends
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class RuntimeBehavior
|
public abstract class RuntimeBehavior
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using static GameConstants.EnemySpawning;
|
using static GameConstants.EnemySpawning;
|
||||||
|
|
||||||
public static class GameConstants
|
public static class GameConstants
|
||||||
@ -408,4 +408,24 @@ public static class GameConstants
|
|||||||
return HuntersInn;
|
return HuntersInn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class BehaviorUtils
|
||||||
|
{
|
||||||
|
public static AnimationCurve GetIceshardProjectileCurve()
|
||||||
|
{
|
||||||
|
var keyframes = new Keyframe[]
|
||||||
|
{
|
||||||
|
// time, value, inTangent, outTangent
|
||||||
|
new Keyframe(0.0f, 0.0f, -0.0635979f, -0.0635979f),
|
||||||
|
new Keyframe(0.6008623f, 1.0058026f, 3.168166f, 3.168166f), // ← This steep tangent creates the sharp rise!
|
||||||
|
new Keyframe(0.9846547f, 1.3325472f, 0.3161671f, 0.3161671f)
|
||||||
|
};
|
||||||
|
|
||||||
|
var curve = new AnimationCurve(keyframes);
|
||||||
|
curve.preWrapMode = WrapMode.PingPong;
|
||||||
|
curve.postWrapMode = WrapMode.PingPong;
|
||||||
|
|
||||||
|
return curve;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ public class NetworkedProjectile : MonoBehaviour
|
|||||||
|
|
||||||
[Header("Set by code")]
|
[Header("Set by code")]
|
||||||
public Taggable ownerTag;
|
public Taggable ownerTag;
|
||||||
public ProjectileAbility ability;
|
public BaseAbility ability;
|
||||||
public float speed;
|
public float speed;
|
||||||
public float lifeSpan;
|
public float lifeSpan;
|
||||||
public bool canPierce;
|
public bool canPierce;
|
||||||
@ -79,6 +79,7 @@ public class NetworkedProjectile : MonoBehaviour
|
|||||||
float lifetimeFraction = Mathf.Clamp01(timeAlive / lifeSpan);
|
float lifetimeFraction = Mathf.Clamp01(timeAlive / lifeSpan);
|
||||||
float currentSpeed = useSpeedCurve ? speed * speedOverLifetime.Evaluate(lifetimeFraction) : speed;
|
float currentSpeed = useSpeedCurve ? speed * speedOverLifetime.Evaluate(lifetimeFraction) : speed;
|
||||||
|
|
||||||
|
|
||||||
// Curving logic
|
// Curving logic
|
||||||
if (enableCurving)
|
if (enableCurving)
|
||||||
{
|
{
|
||||||
|
@ -185,6 +185,11 @@ public class AbilityKeyBinder : MonoBehaviour
|
|||||||
[ContextMenu("debug Add manacost reduction")]
|
[ContextMenu("debug Add manacost reduction")]
|
||||||
public void AddManaCostModifierDebug()
|
public void AddManaCostModifierDebug()
|
||||||
{
|
{
|
||||||
|
if(abilityInstance.SourceAbility is ProjectileAbility projectileAbility)
|
||||||
|
{
|
||||||
|
abilityInstance.AddBehavior(ProjectileExecutionBehavior.CreateIceshardLikeWithCurve(projectileAbility.projectilePrefab, 50f));
|
||||||
|
}
|
||||||
|
|
||||||
abilityInstance.AddModifier(AbilityModifier.CreateManaCostReduction(100f));
|
abilityInstance.AddModifier(AbilityModifier.CreateManaCostReduction(100f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user