#c# #unity3d #coroutine #yield-return
Вопрос:
Я пишу мод для игры, написанной на C#, в которой широко используются сопрограммы Unity. Существует шаблон программирования, который требуется каждый раз, когда пишется сопрограмма для модов для этой игры, который выглядит следующим образом:
IEnumerator e = SomeCoroutineFunc();
if (UseUnityCoroutines) { yield return GameController.StartCoroutine(e); }
else { GameController.ExhaustCoroutine(e); }
Я хотел бы заменить блок запуска или выпуска сопрограммы какой-нибудь абстракцией, чтобы мне не приходилось все время писать один и тот же фрагмент кода. То есть я хотел бы иметь возможность писать:
IEnumerator e = SomeCoroutineFunc();
DoCoroutine(e);
(или какой — то аналогичный эквивалент).
Но поскольку фрагмент приводит только к одному пути, я не уверен, как это сделать! В C я бы использовал макрос, но я не знаю ни одного механизма перезаписи на уровне исходного кода в C#, который мог бы достичь аналогичного эффекта? Есть ли какая-то особенность языка, о которой я не знаю, которая позволила бы мне это сделать?
Более полный пример кода с некоторым контекстом:
public class PureStrengthCardController : CardController
{
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()
);
if (UseUnityCoroutines)
{
yield return GameController.StartCoroutine(e);
}
else
{
GameController.ExhaustCoroutine(e);
}
}
}
Очевидно, что я не контролирую ни один код GameController или CardController, ни более широкую архитектуру игры; Я пишу мод.
Комментарии:
1. Можете ли вы объяснить контекст, в котором это называется? в идеале, по крайней мере, с подписью метода, окружающей предоставленный вами код.
2. Добавлен полный (простой) пример
3. Нет, вы действительно не можете этого сделать. Он всегда уступал, по крайней мере, один раз … вам всегда будет нужна, по крайней мере, какая-то структура, например
if(yieldRequired) { yield return null; }
, где само условие может быть извлечено в выделенный класс, ноyield
само это должно произойти именно так4. Есть ли в вашем моде когда-нибудь случаи, когда вы хотите
yield return GameController.StartCoroutine(e)
несколько раз использовать один и тот же метод?5. Да, это действительно обычное дело, что вам нужно делать это несколько раз.
Ответ №1:
Работает ли это для вас?
public abstract class EnhancedCardController : CardController
{
public EnhancedCardController(Card card, TurnTakerController controller) : base(card, controller)
{ }
public IEnumerator DoCoroutine(IEnumerator coroutine)
{
if (UseUnityCoroutines)
{
yield return GameController.StartCoroutine(coroutine);
}
else
{
GameController.ExhaustCoroutine(coroutine);
}
}
}
А затем использование на вашем примере
public class PureStrengthCardController : EnhancedCardController
{
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 DoCoroutine(e); EDIT: this won't compile! sorry.
return DoCoroutine(e);
}
}
Комментарии:
1. Это все равно
yield
будет по крайней мере один раз2. @derHugo это проблема? Я вообще не знаком с Unity, поэтому непонятно, как все это вписывается в общую картину. С таким же успехом можно было бы сделать это
return
вместоyield return
, но я не уверен, насколько «упрощенным» примером это было для начала.3. @CallumMorrison, конечно, зависит от использования .. если вы хотите пропустить кадр только при определенном условии, то да, это будет иметь значение
4. @derHugo из вопроса, однако, он говорит, что должен дублировать те же самые 3 строки кода в куче мест (предположительно всегда внутри a
CardController
), если условие всегда одно и то же, и результат всегда один и тот же, почему его нельзя абстрагировать, как я сделал?5. Привет, я не уверен, что
yield
вelse
ветке будет иметь значение или нет. Я думал , что Unity не пропускает кадр для ayield break
, он пропускает только кадр дляyield return null
.