本技能系统采用"数据驱动+事件驱动"的混合架构,核心设计目标包括:
// 技能基础数据(ScriptableObject)
[CreateAssetMenu(fileName = "NewSkill", menuName = "Skill System/Skill Data")]
public class SkillData : ScriptableObject
{
[Header("基础设置")]
public string skillName; // 技能名称
public float cooldown = 1f; // 冷却时间
public Sprite icon; // 技能图标
[Header("阶段配置")]
public List<SkillPhase> phases = new List<SkillPhase>(); // 技能阶段列表
[Header("资源引用")]
public GameObject castVFX; // 施法特效
public AudioClip castSFX; // 施法音效
}
// 技能阶段配置
[System.Serializable]
public class SkillPhase
{
[Range(0, 5)] public float triggerTime; // 触发时间(秒)
public SkillEffectType effectType; // 效果类型
public TargetSelectionStrategy targetStrategy; // 目标选择策略
public EffectParams parameters; // 效果参数
}
[RequireComponent(typeof(Animator))]
public class SkillSystem : MonoBehaviour
{
private SkillData currentSkill; // 当前释放的技能
private float cooldownTimer; // 冷却计时器
private Coroutine castingCoroutine; // 施法协程
// 开始释放技能
public void StartCast(SkillData skill)
{
if(cooldownTimer > 0 || currentSkill != null) return;
currentSkill = skill;
castingCoroutine = StartCoroutine(CastingProcess());
}
// 施法过程协程
private IEnumerator CastingProcess()
{
// 初始化状态
PlayCastAnimation();
SpawnVFX(currentSkill.castVFX);
PlaySFX(currentSkill.castSFX);
// 执行技能阶段
foreach(var phase in currentSkill.phases)
{
yield return new WaitForSeconds(phase.triggerTime);
// 获取目标
var targets = SelectTargets(phase.targetStrategy);
// 执行效果
ExecuteEffect(phase.effectType, targets, phase.parameters);
}
// 结束处理
currentSkill = null;
cooldownTimer = currentSkill.cooldown;
}
// 目标选择策略
private List<GameObject> SelectTargets(TargetSelectionStrategy strategy)
{
// 实现不同目标选择逻辑(示例:圆形范围选择)
switch(strategy)
{
case TargetSelectionStrategy.Self:
return new List<GameObject>{gameObject};
case TargetSelectionStrategy.CircleRange:
return Physics.OverlapSphere(transform.position, 5f)
.Select(c => c.gameObject).ToList();
default:
return new List<GameObject>();
}
}
}
// 效果接口
public interface ISkillEffect
{
void Execute(GameObject caster, List<GameObject> targets, EffectParams parameters);
}
// 伤害效果实现
public class DamageEffect : ISkillEffect
{
public void Execute(GameObject caster, List<GameObject> targets, EffectParams parameters)
{
foreach(var target in targets)
{
if(target.TryGetComponent<HealthSystem>(out var health))
{
float finalDamage = parameters.baseValue +
(parameters.isPercentDamage ?
health.maxHP * parameters.percentValue : 0);
health.TakeDamage(finalDamage);
}
}
}
}
// 投射物生成效果
public class SpawnProjectileEffect : ISkillEffect
{
public void Execute(GameObject caster, List<GameObject> targets, EffectParams parameters)
{
var projectile = Instantiate(parameters.projectilePrefab,
caster.transform.position,
caster.transform.rotation);
var controller = projectile.GetComponent<ProjectileController>();
controller.Initialize(caster, parameters);
}
}
public class ProjectileController : MonoBehaviour
{
private GameObject owner;
private EffectParams effectParams;
private Vector3 direction;
public void Initialize(GameObject owner, EffectParams params)
{
this.owner = owner;
this.effectParams = params;
this.direction = owner.transform.forward;
Destroy(gameObject, params.lifetime); // 自动销毁
}
private void Update()
{
// 移动逻辑
transform.position += direction * effectParams.speed * Time.deltaTime;
}
private void OnTriggerEnter(Collider other)
{
if(other.gameObject == owner) return;
// 触发命中效果
var effect = SkillEffectFactory.Create(effectParams.effectType);
effect.Execute(owner, new List<GameObject>{other.gameObject}, effectParams);
Destroy(gameObject);
}
}
// 效果工厂(策略模式)
public class SkillEffectFactory
{
private static Dictionary<SkillEffectType, ISkillEffect> effects = new Dictionary<SkillEffectType, ISkillEffect>()
{
{SkillEffectType.Damage, new DamageEffect()},
{SkillEffectType.Heal, new HealEffect()},
{SkillEffectType.SpawnProjectile, new SpawnProjectileEffect()}
};
public static ISkillEffect Create(SkillEffectType type)
{
return effects.ContainsKey(type) ? effects[type] : null;
}
}
// 在SkillData中添加数据验证
private void OnValidate()
{
// 自动排序阶段
phases = phases.OrderBy(p => p.triggerTime).ToList();
// 参数合法性检查
foreach(var phase in phases)
{
if(phase.parameters.damage < 0)
phase.parameters.damage = 0;
}
}
该实现方案具有以下技术特点:
开发者可以通过继承ISkillEffect接口快速扩展新效果类型,配合Unity编辑器实现可视化的技能配置流程,满足大多数ARPG类游戏的技能系统需求。