Unity AR宝可梦项目:为Scriptable Object卡牌添加独特技能功能
解决方案:给Pokemon卡牌添加可配置的独特技能
一、用Scriptable Object封装技能逻辑(推荐方案)
你当前的PokemonCard结构可以保留,核心是把PokemonMove改成抽象Scriptable Object,让每个技能作为独立实例封装自己的执行逻辑。
1. 定义抽象技能基类
创建一个抽象的PokemonMove Scriptable Object,统一技能的接口:
using UnityEngine; public abstract class PokemonMove : ScriptableObject { [SerializeField] public string MoveName; [SerializeField] public int BaseDamage; [SerializeField] public string Description; // 可扩展添加:所需能量类型/数量、特效Prefab等属性 // 抽象执行方法,让具体技能实现自定义逻辑 public abstract void Execute(PokemonCardRuntime user, PokemonCardRuntime target); }
2. 实现具体技能
针对每个独特技能创建子类,比如Hitmonlee的Jab和Punch:
// Jab技能 [CreateAssetMenu(menuName = "Moves/Jab")] public class JabMove : PokemonMove { public override void Execute(PokemonCardRuntime user, PokemonCardRuntime target) { // 基础伤害逻辑,可扩展属性克制、抗性计算 target.CurrentHP -= BaseDamage; target.CurrentHP = Mathf.Max(target.CurrentHP, 0); } } // Punch技能 [CreateAssetMenu(menuName = "Moves/Punch")] public class PunchMove : PokemonMove { public override void Execute(PokemonCardRuntime user, PokemonCardRuntime target) { target.CurrentHP -= BaseDamage; // 示例:Punch有20%概率让目标眩晕 if (Random.Range(0, 100) < 20) { target.IsStunned = true; } target.CurrentHP = Mathf.Max(target.CurrentHP, 0); } }
3. 修正动态数据存储问题
注意:currentHP属于卡牌的动态运行时状态,不能存在Scriptable Object里(Scriptable Object是全局共享资源,修改会影响所有引用它的实例)。需要单独创建运行时类存储动态数据:
public class PokemonCardRuntime { public PokemonCard CardData; public int CurrentHP; public bool IsStunned; // 示例状态属性 public PokemonCardRuntime(PokemonCard cardData) { CardData = cardData; CurrentHP = cardData.maxHP; IsStunned = false; } }
4. 更新PokemonCard类
修改你的PokemonCard类,确保Moves是PokemonMove类型:
using UnityEngine; [CreateAssetMenu(menuName = "Card/Pokemon Card", fileName = "new Pokemon Card")] public class PokemonCard : CardBase { [SerializeField] public PokemonMove[] Moves; // 现在是PokemonMove类型 public Energy Type; public Energy[] Weakenesses; public Energy[] Resistances; public PokemonCard evolvedFrom = null; [SerializeField] int maxHP; // 移除currentHP,放到PokemonCardRuntime里 }
5. 调用技能
在游戏逻辑中,玩家选择技能时调用对应Execute方法:
// 示例:玩家触发Hitmonlee的某个技能 public void UseMove(PokemonCardRuntime user, PokemonCardRuntime target, PokemonMove move) { move.Execute(user, target); // 后续处理:更新UI、检查目标是否KO等 }
二、替代方案:UnityEvent实现无代码技能配置
如果不想创建太多技能子类,可以用UnityEvent绑定外部逻辑,适合快速配置简单技能:
1. 创建带UnityEvent的技能类
using UnityEngine; using UnityEngine.Events; [CreateAssetMenu(menuName = "Moves/EventBasedMove")] public class EventBasedMove : ScriptableObject { public string MoveName; public int BaseDamage; // 绑定运行时执行的逻辑 public UnityEvent<PokemonCardRuntime, PokemonCardRuntime> OnExecute; public void Execute(PokemonCardRuntime user, PokemonCardRuntime target) { OnExecute?.Invoke(user, target); } }
2. 编写通用技能效果类
创建一个MonoBehaviour类,存放各种技能逻辑:
public class MoveEffectLibrary : MonoBehaviour { public void DealBaseDamage(PokemonCardRuntime user, PokemonCardRuntime target) { target.CurrentHP -= 40; target.CurrentHP = Mathf.Max(target.CurrentHP, 0); } public void DealHeavyDamage(PokemonCardRuntime user, PokemonCardRuntime target) { target.CurrentHP -= 70; target.CurrentHP = Mathf.Max(target.CurrentHP, 0); } }
3. Inspector绑定逻辑
创建EventBasedMove实例后,在Inspector里把MoveEffectLibrary的方法拖到OnExecute事件中,即可完成技能逻辑绑定。
三、Scriptable Object是否是最优选择?
对于宝可梦卡牌这种需要可视化配置、复用静态数据的场景,Scriptable Object非常合适:
- 优点:无需实例化即可访问数据,Inspector编辑直观,数据与代码分离,便于版本控制。
- 注意点:仅用于存储静态数据(如卡牌基础属性、技能模板),动态状态(如当前HP、状态)必须放在运行时实例中(比如
PokemonCardRuntime)。
如果需要更复杂的序列化或跨平台存储,可考虑:
- JSON/XML配置文件:适合批量导入卡牌数据,但需自行编写解析逻辑,无Inspector编辑便利性。
- Scriptable Object + Addressables:适合大规模卡牌库的资源管理,优化加载性能。
内容的提问来源于stack exchange,提问作者HarrisonO
相关产品推荐
相关产品推荐

