рдХрд╕реНрдЯрдо Coroutines рдПрдХрддрд╛ рдореЗрдВ рд╡рд░реАрдпрддрд╛ рдФрд░ рд╢рд┐рд╖реНрдЯрд╛рдЪрд╛рд░ рдХреЗ рд╕рд╛рде


рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЗрддрдиреЗ рд╢рд╛рдВрдд рд╣реИрдВ рдХрд┐ рдЖрдк рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рд╕рднреА рдХреБрд▓реНрд╣рд╛рдбрд╝рд┐рдпреЛрдВ рдХреЗ рдЪрд╛рд░реЛрдВ рдУрд░ рдХреЛрдЖрдЙрдЯ рдХрд░рддреЗ рд╣реИрдВ, рдЖрдкрдХреА рдПрдХ рдирдЬрд╝рд░ рд╕реЗ рд╡реЗ yield break рдФрд░ рдЖрдИрдбреАрдИ рдХреИрдирд╡рд╛рд╕ рдХреЗ рдкреАрдЫреЗ рдЫрд┐рдк рдЬрд╛рддреЗ рд╣реИрдВред рд╕рд░рд▓ рдЖрд╡рд░рдг рдПрдХ рд▓рдВрдмреЗ рд╕рдордп рд╕реЗ рдЪрд▓реЗ рдЧрдП рдЪрд░рдг рд╣реИрдВред


рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдЙрдиреНрд╣реЗрдВ рдЗрддрдиреА рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХреИрд╕реЗ рдкрдХрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рдЖрдк рдПрдХ рдорд┐рд╢реЗрд▓рд┐рди рд╕реНрдЯрд╛рд░ (рдпрд╛ рджреЛ рднреА) рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдЕрдкрдирд╛ рдЦреБрдж рдХрд╛ рд░реЗрд╕реНрддрд░рд╛рдВ рд╣реИред рдмреЗрд╢рдХ! рдХреЛрд░реНрдЙрдЯрд┐рди рд╕реЙрд╕ рдХреЗ рд╕рд╛рде рдЖрдкрдХреЗ рдмреБрдЗрд▓рд╛рдмрд╛рдЗрд╕ рдХреЛ рдЪрдЦрдиреЗ рд╕реЗ рдХреЛрдИ рднреА рдЙрджрд╛рд╕реАрди рдирд╣реАрдВ рд╣реЛрдЧрд╛ред


рдкреВрд░реЗ рдПрдХ рд╣рдлреНрддреЗ рддрдХ, рдареЗрд╕ рдореЗрдВ рдХреЛрдб рдирд╣реАрдВ рдЧрд┐рд░ рд░рд╣рд╛ рд╣реИ! рд░реИрдкрд░реНрд╕, callback 'рдФрд░ Start/Stop Coroutine рдЧреБрд▓рд╛рдореЛрдВ рдХреЗ рдмрд╣реБрдд рд╕рд╛рд░реЗ рд╣реИрдВред рдЖрдкрдХреЛ рдирд┐рдпрдВрддреНрд░рдг рдФрд░ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреА рд╕реНрд╡рддрдВрддреНрд░рддрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЖрдк рдЕрдЧрд▓реЗ рдЪрд░рдг рдкрд░ рдЪрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВ (рд▓реЗрдХрд┐рди рдХреЛрд░реНрд╕ рд╕реЗ рдмрд╛рд╣рд░ рдирд╣реАрдВ рдирд┐рдХрд▓реЗрдВ)ред


рдпрджрд┐ рдЖрдк рдЗрди рдкрдВрдХреНрддрд┐рдпреЛрдВ рдореЗрдВ рдЦреБрдж рдХреЛ рдкрд╣рдЪрд╛рдирддреЗ рд╣реИрдВ, рддреЛ рдмрд┐рд▓реНрд▓реА рдХрд╛ рд╕реНрд╡рд╛рдЧрдд рдХрд░реЗрдВред


рдореИрдВ рдЕрдкрдиреЗ рдкрд╕рдВрджреАрджрд╛ рдкреИрдЯрд░реНрди - рдХрдорд╛рдВрдб рдореЗрдВ рд╕реЗ рдПрдХ рдХреЛ рдирдорд╕реНрддреЗ рдХрд╣рдиреЗ рдХрд╛ рдЕрд╡рд╕рд░ рд▓реЗрддрд╛ рд╣реВрдВред


рдкрд░рд┐рдЪрдп


рдПрдХрддрд╛ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП рд╕рднреА yield рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рд▓рд┐рдП ( WaiForSeconds , AsyncOperation , WaiForSeconds рдФрд░ рдЕрдиреНрдп), рдЖрдзрд╛рд░ рд╡рд░реНрдЧ YieldInstruction ( рдбреЙрдХреНрд╕ ) рд╡рд░реНрдЧ рд╣реИ:


 [StructLayout (LayoutKind.Sequential)] [UsedByNativeCode] public class YieldInstruction { } 

рд╣реБрдб рдХреЗ рддрд╣рдд, рдХреЛрд░рд╛рдЙрдЯрд╛рдЗрди рд╕рд╛рдзрд╛рд░рдг рдПрдиреНрдпреВрдорд░реЗрдЯрд░ ( IEnumerator ( рдбреЙрдХреНрд╕ )) рд╣реИрдВред рдкреНрд░рддреНрдпреЗрдХ рдлрд╝реНрд░реЗрдо рдХреЛ MoveNext() рд╡рд┐рдзрд┐ рджреНрд╡рд╛рд░рд╛ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрджрд┐ рд░рд┐рдЯрд░реНрди рд╡реИрд▓реНрдпреВ true , рддреЛ рдЕрдЧрд▓реА yield рд╕реНрдЯреЗрдЯрдореЗрдВрдЯ рддрдХ рдирд┐рд╖реНрдкрд╛рджрди рдореЗрдВ рджреЗрд░реА рд╣реЛрддреА рд╣реИ; рдпрджрд┐ false , рддреЛ рдпрд╣ рдмрдВрдж рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред


рдХрд╕реНрдЯрдо yield рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рд▓рд┐рдП, рдПрдХрддрд╛ рдЙрд╕реА рдирд╛рдо рдХрд╛ CustomYieldInstruction ( рдбреЙрдХреНрд╕ ) рд╡рд░реНрдЧ рдкреНрд░рджрд╛рди рдХрд░рддреА рд╣реИред


 public abstract class CustomYieldInstruction : IEnumerator { public abstract bool keepWaiting { get; } public object Current => null; public bool MoveNext(); public void Reset(); } 

рдпрд╣ рдЙрд╕рд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓рд╛ рд╣реИ рдФрд░ KeepWaiting рд╕рдВрдкрддреНрддрд┐ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред рд╣рдордиреЗ рдКрдкрд░ рдЗрд╕рдХреЗ рддрд░реНрдХ рдкрд░ рдЪрд░реНрдЪрд╛ рдХреА рд╣реИред рдпрд╣ рддрдм рддрдХ true рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдЬрдм рддрдХ рдХрд┐ рдХреЛрд░рдЯрд╛рдЗрди рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рд╣реИред


рдкреНрд░рд▓реЗрдЦрди рд╕реЗ рдЙрджрд╛рд╣рд░рдг:


 using UnityEngine; public class WaitForMouseDown : CustomYieldInstruction { public override bool keepWaiting { get { return !Input.GetMouseButtonDown(1); } } public WaitForMouseDown() { Debug.Log("Waiting for Mouse right button down"); } } 

рдЙрдирдХреЗ рдЕрдиреБрд╕рд╛рд░, Update() рдФрд░ LateUpdate() рдмрд╛рдж Update() рдкреНрд░рддреНрдпреЗрдХ Update() LateUpdate() рд╣рд░ рдлреНрд░реЗрдо рдХреЗ рдмрд╛рдж рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


рдпрджрд┐ рдЖрдк рдЙрд╕ рдХреЛрдб рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ рдХреБрдЫ рдЪреАрдЬреЛрдВ рдХреЛ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдХреНрд╖рдг рдореЗрдВ рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдФрд░ рдлрд┐рд░ рднреА рдЗрд╕ рдкреГрд╖реНрда рдХрд╛ рдЕрдзреНрдпрдпрди рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ, рддреЛ рдореИрдВ рдЗрд╕ рдЙрдкрд▓рдмреНрдзрд┐ рдХреЛ рддрдп рдХрд░рдиреЗ рдХреА рдЕрддреНрдпрдзрд┐рдХ рдЕрдиреБрд╢рдВрд╕рд╛ рдХрд░рддрд╛ рд╣реВрдВред


рдХрд╕реНрдЯрдо рдЙрдкрдЬ рдирд┐рд░реНрджреЗрд╢



рд▓реЗрдХрд┐рди рд╣рдо рд░реЗрдЧреНрдпреБрд▓рд░рдЗрдиреНрдбрдорд┐рд╢рди рдЗрдирд╣реЗрд░рд┐рдЯ CustomYieldInstruction рдирд┐рдпрдорд┐рдд рд░реИрдкрд░ рдХреЗ рд╕рд╛рде рдпрд╣рд╛рдВ рдирд╣реАрдВ рдЖрдПред рдЗрд╕рдХреЗ рд▓рд┐рдП рдЖрдк рдмрд┐рдирд╛ рдорд┐рд╢реЗрд▓рд┐рди рдХреЗ рднреА рд░рд╣ рд╕рдХрддреЗ рд╣реИрдВред


рдЗрд╕рд▓рд┐рдП рд╣рдо рдкреНрд░рд▓реЗрдЦрди рдХреЛ рдФрд░ рдЕрдзрд┐рдХ рдзреВрдореНрд░рдкрд╛рди рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рд▓рдЧрднрдЧ рдЙрд╕реА рдкреГрд╖реНрда рдХреЗ рдиреАрдЪреЗ рд╣рдо рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкреИрд░рд╛рдЧреНрд░рд╛рдл рдкрд╛рддреЗ рд╣реИрдВред


рдЕрдзрд┐рдХ рдирд┐рдпрдВрддреНрд░рдг рдФрд░ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдЙрдкрдЬ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдк рд╕реАрдзреЗ System.Collections.IEnumerator рд╡рд░реНрдЧ рд╕реЗ рдЗрдирд╣реЗрд░рд┐рдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ред рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, MoveNext() рдкрджреНрдзрддрд┐ рдХреЛ рдЙрд╕реА рддрд░рд╣ рд╕реЗ рд▓рд╛рдЧреВ рдХрд░реЗрдВ рдЬрд┐рд╕ рддрд░рд╣ рд╕реЗ рдЖрдк рд░рдЦрдиреЗ keepWaiting рд╕рдВрдкрддреНрддрд┐ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВрдЧреЗ ред рдЗрд╕рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд, рдЖрдк Current рдкреНрд░реЙрдкрд░реНрдЯреА рдореЗрдВ рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рднреА рд▓реМрдЯрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд┐рд╕реЗ рдореВрд╡рдиреЗрдХреНрд╕реНрдЯ MoveNext() рд╡рд┐рдзрд┐ рдХреЛ рдЕрдВрдЬрд╛рдо рджреЗрдиреЗ рдХреЗ рдмрд╛рдж рдпреВрдирд┐рдЯреА рдХреЗ рдХреЛрд░рдЯрд╛рдЗрди рд╢реЗрдбреНрдпреВрд▓рд░ рджреНрд╡рд╛рд░рд╛ рдкреНрд░реЛрд╕реЗрд╕ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ ред рдЗрд╕рд▓рд┐рдП рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдпрджрд┐ Current IEnumerator рд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓реА рджреВрд╕рд░реА рд╡рд╕реНрддреБ рдХреЛ IEnumerator , рддреЛ рдЬрдм рддрдХ рд▓реМрдЯрд╛рдпрд╛ рд╣реБрдЖ рдПрдХ рдкреВрд░рд╛ рдирд╣реАрдВ рд╣реЛ рдЬрд╛рддрд╛, рддрдм рддрдХ рд╡рд░реНрддрдорд╛рди рдЧрдгрдирд╛рдХрд░реНрддрд╛ рдирд┐рд▓рдВрдмрд┐рдд рд░рд╣реЗрдЧрд╛ред


рд░реВрд╕реА рдореЗрдВ

рдЕрдзрд┐рдХ рдирд┐рдпрдВрддреНрд░рдг рдкрд╛рдиреЗ рдФрд░ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ yield рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП , рдЖрдк рд╕реАрдзреЗ System.Collections.IEnumerator рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕реЗ рдЗрдирд╣реЗрд░рд┐рдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ред рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, MoveNext() рдкрджреНрдзрддрд┐ рдХреЛ рдЙрд╕реА рдкреНрд░рдХрд╛рд░ рд▓рд╛рдЧреВ рд░рдЦреЗрдВ, рдЬреИрд╕реЗ рдХрд┐ keepWaiting рд╕рдВрдкрддреНрддрд┐ ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЖрдк Current рд╕рдВрдкрддреНрддрд┐ рдореЗрдВ рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ , рдЬрд┐рд╕реЗ MoveNext() рд╡рд┐рдзрд┐ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдпреВрдирд┐рдЯреА рдХреЛрд░рдЯрд╛рдЗрди рд╢реЗрдбреНрдпреВрд▓рд░ рджреНрд╡рд╛рд░рд╛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ Current рд╕рдВрдкрддреНрддрд┐ IEnumerator рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рд╡рд╛рд▓реА рдХрд┐рд╕реА рдЕрдиреНрдп рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд▓реМрдЯрд╛рддреА рд╣реИ , рддреЛ рдирдП рдХреЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рддрдХ рд╡рд░реНрддрдорд╛рди рдЧрдгрдирд╛рдХрд░реНрддрд╛ рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдореЗрдВ рджреЗрд░реА рд╣реЛрдЧреАред


рдкрд╡рд┐рддреНрд░ рдХреБрд▓реЛрдВ! рдпреЗ рдирд┐рдпрдВрддреНрд░рдг рдФрд░ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреА рд╕реНрд╡рддрдВрддреНрд░рддрд╛ рд╣реИ рдЬреЛ рдореИрдВ рдмрд╣реБрдд рдЪрд╛рд╣рддрд╛ рдерд╛ред рдЦреИрд░ рдпрд╣ рдмрд╛рдд рд╣реИ, рдЕрдм рдЖрдк рдЗрддрдиреЗ рдХреЛрд░рдЯреАрди рд▓рдкреЗрдЯреЗрдВрдЧреЗ рдХрд┐ рдХреЛрдИ рднреА рдЧрд┐рдордмрд▓ рд▓реЙрдХ рдбрд░рд╛рд╡рдирд╛ рдирд╣реАрдВ рд╣реИред рдореБрдЦреНрдп рдмрд╛рдд, рдЦреБрд╢реА рд╕реЗ, рд▓рдВрдмреВ рд╕реЗ рдЯрдХрд░рд╛рдХрд░ рдзрдорд╛рдХрд╛ рди рдХрд░рдирд╛ред


рдЗрдВрдЯрд░рдлрд╝реЗрд╕


рдЦреИрд░, рдпрд╣ рддрдп рдХрд░рдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдХрд┐ рд╣рдорд╛рд░реЗ рдирд┐рд░реНрджреЗрд╢ рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдХрд╛ рдХреМрди рд╕рд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╣рдо рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдХреБрдЫ рдиреНрдпреВрдирддрдо рд╕реЗрдЯред


рдореИрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╡рд┐рдХрд▓реНрдк рдХрд╛ рд╕реБрдЭрд╛рд╡ рджреЗрддрд╛ рд╣реВрдВ


 public interface IInstruction { bool IsExecuting { get; } bool IsPaused { get; } Instruction Execute(); void Pause(); void Resume(); void Terminate(); event Action<Instruction> Started; event Action<Instruction> Paused; event Action<Instruction> Cancelled; event Action<Instruction> Done; } 

рдореИрдВ рдЗрд╕ рддрдереНрдп рдкрд░ рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдЖрдХрд░реНрд╖рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ IsExecuting рдФрд░ IsPaused рдпрд╣рд╛рдВ рд╡рд┐рдкрд░реАрдд рдирд╣реАрдВ рд╣реИрдВред рдпрджрд┐ рдХреЛрд░рдЯрд╛рдЗрди рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЛ рд░реЛрдХ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЗрд╕реЗ рдЕрднреА рднреА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИред


рддреНрдпрд╛рдЧреА рдФрд░ рд╕реМрдЬрдиреНрдп


рдЬреИрд╕рд╛ рдХрд┐ рдкреНрд░рд▓реЗрдЦрди рдХрд╣рддрд╛ рд╣реИ, рдЖрдкрдХреЛ IEnumerator рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдХреБрдЫ рд╕реНрдерд╛рдиреЛрдВ рдкрд░, рдЕрдм рдХреЗ рд▓рд┐рдП, рд╕реНрдЯрдмреНрд╕ рдХреЛ рдЫреЛрдбрд╝ рджреЗрдВ, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕реАрдзреЗ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдЗрд╕реЗ рдХрд┐рд╕ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдореЗрдВ рд▓рд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред


 using UnityEngine; using IEnumerator = System.Collections.IEnumerator; public abstract class Instruction : IEnumerator { private Instruction current; object IEnumerator.Current => current; void IEnumerator.Reset() { } bool IEnumerator.MoveNext() { } } 

рдпрд╣ рд╡рд┐рдЪрд╛рд░ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рдирд┐рд░реНрджреЗрд╢ рдХреЛ рдХрдо рд╕реЗ рдХрдо рджреЛ рддрд░реАрдХреЗ рд╕реЗ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:


  1. StartCoroutine(IEnumerator routine) рд╡рд┐рдзрд┐ StartCoroutine(IEnumerator routine) :


     StartCoroutine(new ConcreteInstruction()); 

  2. рдЙрдкрдЬ yield :


     private IEnumerator SomeRoutine() { yield return new ConcreteInstruction(); } 


Execute рдкрджреНрдзрддрд┐, рдЬрд┐рд╕реЗ рд╣рдордиреЗ IInstruction рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рдКрдкрд░ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рд╣реИ, рдкрд╣рд▓реА рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧреАред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдХреБрдЫ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ рдЬреЛ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдирд┐рд░реНрджреЗрд╢ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдВрдЧреЗред


 private object routine; public MonoBehaviour Parent { get; private set; } 

рдЕрдм рдЧреБрдг рдФрд░ IInstruction рд▓рд┐рдП рдШрдЯрдирд╛рдУрдВред


 using UnityEngine; using System; using IEnumerator = System.Collections.IEnumerator; public abstract class Instruction : IEnumerator, IInstruction { private Instruction current; object IEnumerator.Current => current; private object routine; public MonoBehaviour Parent { get; private; } public bool IsExecuting { get; private set; } public bool IsPaused { get; private set; } private bool IsStopped { get; set; } public event Action<Instruction> Started; public event Action<Instruction> Paused; public event Action<Instruction> Terminated; public event Action<Instruciton> Done; void IEnumerator.Reset() { } bool IEnumerator.MoveNext() { } Instruction(MonoBehaviour parent) => Parent = parent; } 

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдмрд╛рд▓ рд╡рд░реНрдЧреЛрдВ рдореЗрдВ рдШрдЯрдирд╛рдУрдВ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреЗ рд▓рд┐рдП рддрд░реАрдХреЗ:


 protected virtual void OnStarted() { } protected virtual void OnPaused() { } protected virtual void OnResumed() { } protected virtual void OnTerminated() { } protected virtual void OnDone() { } 

рдмрдЪреНрдЪреЗ рдХреЛ рдЙрдирдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреА рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдВрдмрдВрдзрд┐рдд рдШрдЯрдирд╛рдУрдВ рд╕реЗ рдареАрдХ рдкрд╣рд▓реЗ рдЙрдиреНрд╣реЗрдВ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред


рдЕрдм рд╢реЗрд╖ рд╡рд┐рдзрд┐рдпрд╛рдБред


 public void Pause() { if (IsExecuting && !IsPaused) { IsPaused = true; OnPaused(); Paused?.Invoke(this); } } public bool Resume() { if (IsExecuting) { IsPaused = false; OnResumed(); } } 

рдпрд╣рд╛рдВ рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рд╣реИред рдирд┐рд░реНрджреЗрд╢ рдХреЛ рдХреЗрд╡рд▓ рддрднреА рд░реЛрдХрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдЬрдм рдЙрд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ рдФрд░ рдпрджрд┐ рдЙрд╕реЗ рдирд┐рд▓рдВрдмрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдФрд░ рдХреЗрд╡рд▓ рдирд┐рд▓рдВрдмрд┐рдд рд░рд╣рдиреЗ рдкрд░ рдирд┐рд╖реНрдкрд╛рджрди рдЬрд╛рд░реА рд░рдЦреЗрдВред


 public void Terminate() { if (Stop()) { OnTerminated(); Terminate?.Invoke(this); } } private bool Stop() { if (IsExecuting) { if (routine is Coroutine) Parent.StopCoroutine(routine as Coroutine); (this as IEnumerator).Reset(); return IsStopped = true; } return false; } 

рдирд┐рд░реНрджреЗрд╢ рдХреЛ рд░реЛрдХрдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЦреНрдп рддрд░реНрдХ Stop рд╡рд┐рдзрд┐ рдореЗрдВ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рдпрд╣ рдПрдХ рдореВрдХ рд╕реНрдЯреЙрдк (рдЯреНрд░рд┐рдЧрд░рд┐рдВрдЧ рдШрдЯрдирд╛рдУрдВ рдХреЗ рдмрд┐рдирд╛) рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИред
рдпрд╣ рдЬрд╛рдБрдЪрдирд╛ if (routine is Coroutine) рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХреНрдпреЛрдВрдХрд┐, рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рдКрдкрд░ рд▓рд┐рдЦрд╛ рд╣реИ, рдирд┐рд░реНрджреЗрд╢ yield (рдЬреЛ рдХрд┐ StartCoroutine рдХреЛ рдмреБрд▓рд╛рдП рдмрд┐рдирд╛) рджреНрд╡рд╛рд░рд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ StartCoroutine рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдХреЛрдИ рд▓рд┐рдВрдХ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, routine рдХреЗрд╡рд▓ рдПрдХ рдареВрдВрда рд╣реЛрдЧреАред


 public Instruction Execute(MonoBehaviour parent) { if (current != null) { Debug.LogWarning($"Instruction { GetType().Name} is currently waiting for another one and can't be stared right now."); return this; } if (!IsExecuting) { IsExecuting = true; routine = (Parent = parent).StartCoroutine(this); return this; } Debug.LogWarning($"Instruction { GetType().Name} is already executing."); return this; } 

рдореБрдЦреНрдп рд▓реЙрдиреНрдЪ рд╡рд┐рдзрд┐ рднреА рдмреЗрд╣рдж рд╕рд░рд▓ рд╣реИ - рд▓реЙрдиреНрдЪ рдХреЗрд╡рд▓ рддрднреА рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдЬрдм рдирд┐рд░реНрджреЗрд╢ рдЕрднреА рддрдХ рд▓реЙрдиреНрдЪ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред


рдпрд╣ IEnumerator рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдордиреЗ рдХреБрдЫ рддрд░реАрдХреЛрдВ рдореЗрдВ рдЦрд╛рд▓реА рд╕реНрдерд╛рди рдЫреЛрдбрд╝ рджрд┐рдП рд╣реИрдВред


 IEnumerator.Reset() { IsExecuting = false; IsPaused = false; IsStopped = false; routine = null; } 

рдФрд░ рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк, рд▓реЗрдХрд┐рди рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рд╣реИ, MoveNext :


 bool IEnumerator.MoveNext() { if (IsStopped) { (this as IEnumerator).Reset(); return false; } if (!IsExecuting) { IsExecuting = true; routine = new object(); OnStarted(); Started?.Invoke(this); } if (current != null) return true; if (IsPaused) return true; if (!Update()) { OnDone(); Done?.Invoke(this); IsStopped = true; return false; } return true; } 

if (!IsExecuting) - рдпрджрд┐ рдирд┐рд░реНрджреЗрд╢ StartCoroutine рдорд╛рдзреНрдпрдо рд╕реЗ рд▓реЙрдиреНрдЪ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдФрд░ рдХреЛрдб рдХреА рдЗрд╕ рд▓рд╛рдЗрди рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ yield рдиреЗ рдЗрд╕реЗ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ред рд╣рдо routine рдФрд░ рдЖрдЧ рдХреА рдШрдЯрдирд╛рдУрдВ рдореЗрдВ рдПрдХ рдареВрдВрда рд▓рд┐рдЦрддреЗ рд╣реИрдВред


if (current != null) - current рдЗрд╕реНрддреЗрдорд╛рд▓ рдмрдЪреНрдЪреЗ рдХреЗ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЕрдЧрд░ рдЕрдЪрд╛рдирдХ рдпрд╣ рд╕рд╛рдордиреЗ рдЖрдпрд╛ рд╣реИ, рддреЛ рд╣рдо рдЗрд╕рдХреЗ рдЦрддреНрдо рд╣реЛрдиреЗ рдХрд╛ рдЗрдВрддрдЬрд╛рд░ рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдореИрдВ рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдмрдЪреНрдЪреЗ рдХреЗ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдЬреЛрдбрд╝рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдпрд╛рдж рдХрд░реВрдВрдЧрд╛ рддрд╛рдХрд┐ рдЗрд╕реЗ рдФрд░ рдЕрдзрд┐рдХ рди рдмрдврд╝рд╛рдпрд╛ рдЬрд╛рдПред рдЗрд╕рд▓рд┐рдП, рдпрджрд┐ рдЖрдк рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рдЖрдЧреЗ рдмрдврд╝рд╛рдиреЗ рдореЗрдВ рд░реБрдЪрд┐ рдирд╣реАрдВ рд░рдЦрддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдмрд╕ рдЗрди рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рд╣рдЯрд╛ рд╕рдХрддреЗ рд╣реИрдВред


if (!Update()) - рд╣рдорд╛рд░реЗ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдореЗрдВ Update рд╡рд┐рдзрд┐, keepWaiting рддрд░рд╣ рд╣реА рдХрд╛рдо рдХрд░рддреА CustomYieldInstruction рдФрд░ рдЗрд╕реЗ рдмрд╛рд▓ рд╡рд░реНрдЧ рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред Instruction рдорд╛рддреНрд░ рдПрдХ рдЕрдореВрд░реНрдд рд╡рд┐рдзрд┐ рд╣реИред


 protected abstract bool Update(); 

рд╕рдВрдкреВрд░реНрдг рдирд┐рд░реНрджреЗрд╢ рдХреЛрдб
 using UnityEngine; using System; using IEnumerator = System.Collections.IEnumerator; public abstract class Instruction : IEnumerator, IInstruction { private Instruction current; object IEnumerator.Current => current; private object routine; public MonoBehaviour Parent { get; private set; } public bool IsExecuting { get; private set; } public bool IsPaused { get; private set; } private bool IsStopped { get; set; } public event Action<Instruction> Started; public event Action<Instruction> Paused; public event Action<Instruction> Terminated; public event Action<Instruction> Done; void IEnumerator.Reset() { IsPaused = false; IsStopped = false; routine = null; } bool IEnumerator.MoveNext() { if (IsStopped) { (this as IEnumerator).Reset(); return false; } if (!IsExecuting) { IsExecuting = true; routine = new object(); OnStarted(); Started?.Invoke(this); } if (current != null) return true; if (IsPaused) return true; if (!Update()) { OnDone(); Done?.Invoke(this); IsStopped = true; return false; } return true; } protected Instruction(MonoBehaviour parent) => Parent = parent; public void Pause() { if (IsExecuting && !IsPaused) { IsPaused = true; OnPaused(); Paused?.Invoke(this); } } public void Resume() { IsPaused = false; OnResumed(); } public void Terminate() { if (Stop()) { OnTerminated(); Terminated?.Invoke(this); } } private bool Stop() { if (IsExecuting) { if (routine is Coroutine) Parent.StopCoroutine(routine as Coroutine); (this as IEnumerator).Reset(); return IsStopped = true; } return false; } public Instruction Execute() { if (current != null) { Debug.LogWarning($"Instruction { GetType().Name} is currently waiting for another one and can't be stared right now."); return this; } if (!IsExecuting) { IsExecuting = true; routine = Parent.StartCoroutine(this); return this; } Debug.LogWarning($"Instruction { GetType().Name} is already executing."); return this; } public Instruction Execute(MonoBehaviour parent) { if (current != null) { Debug.LogWarning($"Instruction { GetType().Name} is currently waiting for another one and can't be stared right now."); return this; } if (!IsExecuting) { IsExecuting = true; routine = (Parent = parent).StartCoroutine(this); return this; } Debug.LogWarning($"Instruction { GetType().Name} is already executing."); return this; } public void Reset() { Terminate(); Started = null; Paused = null; Terminated = null; Done = null; } protected virtual void OnStarted() { } protected virtual void OnPaused() { } protected virtual void OnResumed() { } protected virtual void OnTerminated() { } protected virtual void OnDone() { } protected abstract bool Update(); } 

рдЙрджрд╛рд╣рд░рдг


рдмреЗрд╕ рдХреНрд▓рд╛рд╕ рддреИрдпрд╛рд░ рд╣реИред рдХрд┐рд╕реА рднреА рдирд┐рд░реНрджреЗрд╢ рдХреЛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдпрд╣ рдЙрд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рджреЗрдирд╛ рдФрд░ рдЖрд╡рд╢реНрдпрдХ рд╕рджрд╕реНрдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред рдореИрдВ рдХреБрдЫ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓рдиреЗ рдХрд╛ рд╕реБрдЭрд╛рд╡ рджреЗрддрд╛ рд╣реВрдВред


рдмрд┐рдВрджреБ рдкрд░ рд▓реЗ рдЬрд╛рдПрдБ


 public sealed class MoveToPoint : Instruction { public Transform Transform { get; set; } public Vector3 Target { get; set; } public float Speed { get; set; } public float Threshold { get; set; } public MoveToPoint(MonoBehaviour parent) : base(parent) { } protected override bool Update() { Transform.position = Vector3.Lerp(Transform.position, Target, Time.deltaTime * Speed); return Vector3.Distance(Transform.position, Target) >= Threshold; } } 

рд╡рд┐рдХрд▓реНрдк рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ
 private void Method() { var move = new MoveToPoint(this) { Actor = transform, Target = target, Speed = 1.0F, Threshold = 0.05F }; move.Execute(); } 

 private void Method() { var move = new MoveToPoint(this); move.Execute(transform, target, 1.0F, 0.05F); } 

 private IEnumerator Method() { yield return new MoveToPoint(this) { Actor = transform, Target = target, Speed = 1.0F, Threshold = 0.05F }; } 

 private IEnumerator Method() { var move = new MoveToPoint(this) { Actor = transform, Target = target, Speed = 1.0F, Threshold = 0.05F }; yield return move; } 

 private IEnumerator Method() { var move = new MoveToPoint(this); yield return move.Execute(transform, target, 1.0F, 0.05F); } 

рдЗрдирдкреБрдЯ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ


 public sealed class WaitForKeyDown : Instruction { public KeyCode Key { get; set; } protected override bool Update() { return !Input.GetKeyDown(Key); } public WaitForKeyDown(MonoBehaviour parent) : base(parent) { } public Instruction Execute(KeyCode key) { Key = key; return base.Execute(); } } 

рдЙрджрд╛рд╣рд░рдг рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ
 private void Method() { car wait = new WaitForKeyDown(this); wait.Execute(KeyCode.Space).Done += (i) => DoSomething(); } 

 private IEnumerator Method() { yield return new WaitForKeyDown(this) { Key = KeyCode.Space }; // do something; } 

рд░реБрдХреЗрдВ рдФрд░ рд░реБрдХреЗрдВ


 public sealed class Wait : Instruction { public float Delay { get; set; } private float startTime; protected override bool Update() { return Time.time - startTime < Delay; } public Wait(MonoBehaviour parent) : base(parent) { } public Wait(float delay, MonoBehaviour parent) : base(parent) { Delay = delay; } protected override void OnStarted() { startTime = Time.time; } public Instruction Execute(float delay) { Delay = delay; return base.Execute(); } } 

рдпрд╣рд╛рдБ, рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ, рд╕рдм рдХреБрдЫ рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рдЙрддрдирд╛ рд╕рд░рд▓ рд╣реИред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдордиреЗ рдкреНрд░рд╛рд░рдВрдн рд╕рдордп рджрд░реНрдЬ рдХрд┐рдпрд╛, рдФрд░ рдлрд┐рд░ рд╡рд░реНрддрдорд╛рди рд╕рдордп рдФрд░ StartTime рд╕рдордп рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВред рд▓реЗрдХрд┐рди рдПрдХ рдЕрддрд┐ рд╕реВрдХреНрд╖реНрдо рдЕрдВрддрд░ рд╣реИ рдЬрд┐рд╕реЗ рдЖрдк рддреБрд░рдВрдд рдиреЛрдЯрд┐рд╕ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗред рдпрджрд┐ рдХрд┐рд╕реА рдирд┐рд░реНрджреЗрд╢ рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рджреМрд░рд╛рди рдЖрдк рдЗрд╕реЗ рд░реЛрдХрддреЗ рд╣реИрдВ ( Pause рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ) рдФрд░ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВ, рддреЛ рдлрд┐рд░ рд╕реЗ рд╢реБрд░реВ рдХрд░рдиреЗ ( Resume ) рдХреЗ рдмрд╛рдж рдЗрд╕реЗ рддреБрд░рдВрдд рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдФрд░ рд╕рднреА рдХреНрдпреЛрдВрдХрд┐ рдЕрдм рдпрд╣ рдирд┐рд░реНрджреЗрд╢ рдзреНрдпрд╛рди рдореЗрдВ рдирд╣реАрдВ рдЖрддрд╛ рд╣реИ рдХрд┐ рдореИрдВ рдЗрд╕реЗ рд░реЛрдХ рд╕рдХрддрд╛ рд╣реВрдВред


рдЖрдЗрдП рдЗрд╕ рдЕрдиреНрдпрд╛рдп рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ:


 protected override void OnPaused() { Delay -= Time.time - startTime; } protected override void OnResumed() { startTime = Time.time; } 

рд╣реЛ рдЧрдпрд╛ред рдЕрдм, рдард╣рд░рд╛рд╡ рдХреА рд╕рдорд╛рдкреНрддрд┐ рдХреЗ рдмрд╛рдж, рдирд┐рд░реНрджреЗрд╢ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрдиреЗ рдореЗрдВ рдЙрддрдирд╛ рд╣реА рд╕рдордп рд▓рдЧреЗрдЧрд╛ рдЬрд┐рддрдирд╛ рдХрд┐ рдЗрд╕рдХреЗ рд╢реБрд░реВ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЫреЛрдбрд╝рд╛ рдЧрдпрд╛ рдерд╛ред


рдЙрджрд╛рд╣рд░рдг рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ
 private void Method() { var wait = new Wait(this); wait.Execute(5.0F).Done += (i) => DoSomething; } 

 private IEnumerator Method() { yield return new Wait(this, 5.0F); // do something; } 

рд╕рдВрдкреВрд░реНрдг


рдПрдХрддрд╛ рдореЗрдВ Coroutines рдЖрдк рдЕрджреНрднреБрдд рдФрд░ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдмрд╛рддреЗрдВ рдХрд░рддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рд╡реЗ рдХрд┐рддрдиреЗ рдЬрдЯрд┐рд▓ рд╣реЛрдВрдЧреЗ рдФрд░ рдЖрдкрдХреЛ рдЙрдирдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВ, рдпрд╣ рд╕рднреА рдХреА рд╡реНрдпрдХреНрддрд┐рдЧрдд рдкрд╕рдВрдж рд╣реИред


рдХреЛрд░рдЯреАрди рдХреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рдирд╛ рд╕рдмрд╕реЗ рдореБрд╢реНрдХрд┐рд▓ рдХрд╛рдо рдирд╣реАрдВ рд╣реИред рдЖрдкрдХреЛ рдмрд╕ рдпрд╣ рддрдп рдХрд░рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ рдХрд┐ рдЖрдк рдХрд┐рд╕ рдЗрдВрдЯрд░рдлреЗрд╕ рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдФрд░ рдЙрдирдХреЗ рдХрд╛рдо рдХрд╛ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреНрдпрд╛ рд╣реЛрдЧрд╛ред


рдЖрдкрдХреЗ рд╕рдордп рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред рдЕрдкрдиреЗ рдкреНрд░рд╢реНрдиреЛрдВ / рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ / рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЛ рдЯрд┐рдкреНрдкрдгреА рдореЗрдВ рдЫреЛрдбрд╝ рджреЗрдВред рдореБрдЭреЗ рд╕рдВрд╡рд╛рдж рдХрд░рдиреЗ рдореЗрдВ рдЦреБрд╢реА рд╣реЛрдЧреАред




PS рдЕрдЧрд░, рдЕрдЪрд╛рдирдХ, рдЖрдк corutin рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд▓ рдЧрдП, рддреЛ рдЗрд╕ рдЯрд┐рдкреНрдкрдгреА рдХреЛ рдкрдврд╝реЗрдВ рдФрд░ рдХреБрдЫ рдардВрдбрд╛ рдкреАрдПрдВред

Source: https://habr.com/ru/post/hi442820/


All Articles