Execute Behaviors
This commit is contained in:
parent
c4d084acb2
commit
e4d35c0af6
@ -78,7 +78,7 @@ Material:
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _Rotation: 6.1873918
|
||||
- _Rotation: 6.1601553
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 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;
|
||||
public virtual void SpendResourcesNecessary(Taggable user)
|
||||
{
|
||||
if (userMana == null) userMana = user.GetComponent<Mana>();
|
||||
if (userHealth == null) userHealth = user.GetComponent<Health>();
|
||||
|
||||
userMana.ChangeValue(-GetFinalManaCost(user));
|
||||
userHealth.ChangeValue(-GetFinalHealthCost(user));
|
||||
@ -202,8 +204,10 @@ public class RuntimeAbilityInstance
|
||||
if (!CanExecute(user)) return;
|
||||
|
||||
ExecuteBehaviors(BehaviorTrigger.PreCast, user, null, Vector3.zero);
|
||||
|
||||
SpendResourcesNecessary(user);
|
||||
sourceAbility.Execute(user);
|
||||
ExecuteBehaviors(BehaviorTrigger.Execute, user, null, Vector3.zero);
|
||||
|
||||
ExecuteBehaviors(BehaviorTrigger.PostCast, user, null, Vector3.zero);
|
||||
|
||||
lastUsedTime = Time.time;
|
||||
@ -214,8 +218,10 @@ public class RuntimeAbilityInstance
|
||||
if (!CanExecute(user)) return;
|
||||
|
||||
ExecuteBehaviors(BehaviorTrigger.PreCast, user, null, point);
|
||||
|
||||
SpendResourcesNecessary(user);
|
||||
sourceAbility.Execute(user, point);
|
||||
ExecuteBehaviors(BehaviorTrigger.Execute, user, null, point);
|
||||
|
||||
ExecuteBehaviors(BehaviorTrigger.PostCast, user, null, point);
|
||||
|
||||
lastUsedTime = Time.time;
|
||||
@ -226,8 +232,10 @@ public class RuntimeAbilityInstance
|
||||
if (!CanExecute(user)) return;
|
||||
|
||||
ExecuteBehaviors(BehaviorTrigger.PreCast, user, target, target.position);
|
||||
|
||||
SpendResourcesNecessary(user);
|
||||
sourceAbility.Execute(user, target);
|
||||
ExecuteBehaviors(BehaviorTrigger.Execute, user, target, target.position);
|
||||
|
||||
ExecuteBehaviors(BehaviorTrigger.PostCast, user, target, target.position);
|
||||
|
||||
lastUsedTime = Time.time;
|
||||
|
@ -2,12 +2,15 @@ using UnityEngine;
|
||||
|
||||
public enum BehaviorTrigger
|
||||
{
|
||||
PreCast, // Before ability executes
|
||||
Execute, // MAIN EXECUTION - replaces your override Execute()
|
||||
PostCast, // After ability executes
|
||||
OnHit, // When ability hits target
|
||||
OnKill, // When ability kills target
|
||||
OnCrit // When ability crits
|
||||
PreCast, // Before ability executes
|
||||
Execute, // MAIN EXECUTION - replaces your override Execute()
|
||||
PostCast, // After ability executes
|
||||
OnHit, // When ability hits target
|
||||
OnKill, // When ability kills target
|
||||
OnCrit, // When ability crits
|
||||
OnMiss, // When ability misses
|
||||
OnChannelTick, // During channeling
|
||||
OnChannelEnd // When channeling ends
|
||||
}
|
||||
|
||||
public abstract class RuntimeBehavior
|
||||
|
@ -1,4 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine;
|
||||
using static GameConstants.EnemySpawning;
|
||||
|
||||
public static class GameConstants
|
||||
@ -408,4 +408,24 @@ public static class GameConstants
|
||||
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")]
|
||||
public Taggable ownerTag;
|
||||
public ProjectileAbility ability;
|
||||
public BaseAbility ability;
|
||||
public float speed;
|
||||
public float lifeSpan;
|
||||
public bool canPierce;
|
||||
@ -79,6 +79,7 @@ public class NetworkedProjectile : MonoBehaviour
|
||||
float lifetimeFraction = Mathf.Clamp01(timeAlive / lifeSpan);
|
||||
float currentSpeed = useSpeedCurve ? speed * speedOverLifetime.Evaluate(lifetimeFraction) : speed;
|
||||
|
||||
|
||||
// Curving logic
|
||||
if (enableCurving)
|
||||
{
|
||||
|
@ -185,6 +185,11 @@ public class AbilityKeyBinder : MonoBehaviour
|
||||
[ContextMenu("debug Add manacost reduction")]
|
||||
public void AddManaCostModifierDebug()
|
||||
{
|
||||
if(abilityInstance.SourceAbility is ProjectileAbility projectileAbility)
|
||||
{
|
||||
abilityInstance.AddBehavior(ProjectileExecutionBehavior.CreateIceshardLikeWithCurve(projectileAbility.projectilePrefab, 50f));
|
||||
}
|
||||
|
||||
abilityInstance.AddModifier(AbilityModifier.CreateManaCostReduction(100f));
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user