C#中如何抽象封装带条件yield的Unity协程执行逻辑
解决方案
C# 没有 C++ 风格的宏,但有两种可行的方案可以实现你的需求,不需要修改任何游戏原生代码:
方案1:协程包装方法(最推荐,零额外依赖)
你只需要将判断逻辑封装为一个返回 IEnumerator 的公共方法,统一通过 yield return 调用即可,逻辑和你原来的手写代码完全等价:
- 首先编写一个所有自定义卡牌控制器继承的中间基类,把通用逻辑沉淀在基类中:
public abstract class ModCardController : CardController { protected ModCardController(Card card, TurnTakerController controller) : base(card, controller) { } // 封装协程调度逻辑 protected IEnumerator RunCoroutine(IEnumerator coroutine) { if (UseUnityCoroutines) { yield return GameController.StartCoroutine(coroutine); } else { GameController.ExhaustCoroutine(coroutine); } } }
- 之后所有你编写的卡牌控制器继承这个基类,调用时只需要一行代码:
public class PureStrengthCardController : ModCardController { public PureStrengthCardController(Card card, TurnTakerController controller) : base(card, controller) { } public override IEnumerator Play() { // "{AlexandriaCharacter} deals a target 4 melee damage" var e = GameController.SelectTargetsAndDealDamage( HeroTurnTakerController, new DamageSource(GameController, CharacterCard), amount: 4, DamageType.Melee, numberOfTargets: 1, optional: false, requiredTargets: 1, cardSource: GetCardSource() ); // 直接调用封装好的方法即可 yield return RunCoroutine(e); } }
这个方案没有任何运行时额外开销,完全兼容原有逻辑,只比你期望的 DoCoroutine(e) 多了一个 yield return 前缀,已经能解决99%的重复代码问题。
方案2:源代码生成器(适合大规模Mod场景)
如果你确实希望完全去掉 yield return 前缀,实现和你示例完全一致的 DoCoroutine(e) 调用效果,可以使用 C# 9 及以上版本支持的**源代码生成器(Source Generator)**功能,它属于编译期的源码级重写机制,可以实现类似C++宏的效果:
你可以编写一个简单的源生成器,扫描所有代码中 DoCoroutine(e) 的调用,在编译时自动替换为你原来的 if 分支代码,不需要修改运行时代码。这个方案适合Mod代码量很大、协程调用点特别多的场景,缺点是需要额外实现一套生成器逻辑,有一定的开发成本。
为什么不能直接封装为无返回值的DoCoroutine?
因为原有逻辑中 yield return 的作用是让当前的 Play 协程等待子协程执行完成后再继续往下执行,如果封装为无返回值方法,Unity协程分支下子协程会启动,但当前 Play 协程会直接往后执行,会出现逻辑时序错误。
内容的提问来源于stack exchange,提问作者James Picone
相关产品推荐
相关产品推荐

