{"id":356367,"date":"2024-05-20T23:28:09","date_gmt":"2024-05-20T23:28:09","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=356367"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-20T23:28:09","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=356367","title":{"rendered":"<span>\u041c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u043d\u0430 Unity<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c16\/d4a\/35f\/c16d4a35f76d563aa0f6525952c852b1.png\" width=\"1280\" height=\"720\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c16\/d4a\/35f\/c16d4a35f76d563aa0f6525952c852b1.png\"\/><\/figure>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0418\u0433\u043e\u0440\u044c, \u0438 \u044f Unity Developer. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u0434\u043b\u044f \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043b\u043e\u0433\u0438\u043a\u0443.<\/p>\n<blockquote>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0447\u0438\u0442\u0430\u043b\u0438 \u043c\u043e\u044e <a href=\"https:\/\/habr.com\/ru\/articles\/735244\/\">\u0441\u0442\u0430\u0442\u044c\u044e<\/a> \u043f\u0440\u043e \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0434\u0438\u0437\u0430\u0439\u043d, \u0442\u043e \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u043d\u0435\u0439. \u041d\u043e \u044d\u0442\u043e \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e.<\/p>\n<\/blockquote>\n<p>\u0426\u0435\u043b\u044c \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0433\u0438\u0431\u043a\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 Unity, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0441\u0430\u0436\u0438\u0432\u0430\u0439\u0442\u0435\u0441\u044c \u043a \u043e\u0433\u043e\u043d\u044c\u043a\u0443.<\/p>\n<p>\u0414\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430 \u043a\u0443\u0431\u0430\u0445 \u2014 \u044d\u0442\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u0438 \u043f\u0443\u043b\u044f.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d6a\/b5f\/6f1\/d6ab5f6f15de71548525b2949033d9e4.png\" alt=\"\u041d\u0430\u0448\u0438 \u043f\u043e\u0434\u043e\u043f\u044b\u0442\u043d\u044b\u0435 \u0432 Unity\" title=\"\u041d\u0430\u0448\u0438 \u043f\u043e\u0434\u043e\u043f\u044b\u0442\u043d\u044b\u0435 \u0432 Unity\" width=\"780\" height=\"440\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d6a\/b5f\/6f1\/d6ab5f6f15de71548525b2949033d9e4.png\"\/><\/p>\n<div><figcaption>\u041d\u0430\u0448\u0438 \u043f\u043e\u0434\u043e\u043f\u044b\u0442\u043d\u044b\u0435 \u0432 Unity<\/figcaption><\/div>\n<\/figure>\n<p>\u0423 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435 \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f, \u0430 \u0443 \u043f\u0443\u043b\u0438 \u2014 \u043b\u0435\u0442\u0435\u0442\u044c \u0438 \u043d\u0430\u043d\u043e\u0441\u0438\u0442\u044c \u0443\u0440\u043e\u043d \u043f\u0440\u0438 \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u0438 \u0432 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430. \u041d\u0430 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u043e\u043f\u044b\u0442\u0430\u044e\u0441\u044c \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u044c \u043f\u0440\u0435\u043b\u0435\u0441\u0442\u044c \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043b\u043e\u0433\u0438\u043a\u0438. \u041d\u0443 \u0448\u043e, \u043f\u043e\u0435\u0445\u0430\u043b\u0438 \ud83d\ude42<\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430<\/h2>\n<p>\u0412 \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u043b\u044e\u0431\u043e\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043b\u043e\u0433\u0438\u043a\u0438. \u041f\u043e\u0434 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u044f \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u044e \u043b\u044e\u0431\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0445\u0440\u0430\u043d\u0438\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 (\u043f\u043e\u043b\u044f \/ \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \/ \u0441\u043e\u0431\u044b\u0442\u0438\u044f), \u043f\u043e\u0434 \u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u2014 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b (\u043c\u0435\u0442\u043e\u0434\u044b, \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \/ \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u044d\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430. \u0414\u0430, \u044d\u0442\u043e ECS, \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \ud83d\ude42<\/p>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u0438\u043c\u0435\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f \u0438 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0443\u0440\u043e\u043d\u0430, \u043e\u043f\u0438\u0448\u0435\u043c \u044d\u0442\u043e:<\/p>\n<pre><code class=\"cs\">public sealed class Character : MonoBehaviour {     \/\/\u0414\u0430\u043d\u043d\u044b\u0435:     public AtomicEvent&lt;int> takeDamageEvent;     public AtomicVariable&lt;int> hitPoints;          \/\/\u041b\u043e\u0433\u0438\u043a\u0430:     private TakeDamageMechanics takeDamageMechanics; }<\/code><\/pre>\n<ul>\n<li>\n<p>\u041f\u043e\u043b\u0435 takeDamageEvent \u0442\u0438\u043f\u0430 AtomicEvent&lt;T> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0443\u0440\u043e\u043d\u0430<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0435 hitPoints \u0442\u0438\u043f\u0430 AtomicVariable&lt;T> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u043a\u043e\u043b-\u0432\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f \u0438 \u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0435\u0442 \u043e \u0435\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0435 takeDamageMechanics \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0443\u0440\u043e\u043d\u0430 \u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442 \u043a\u043e\u043b-\u0432\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u043b\u0430\u0441\u0441\u044b AtomicEvent &amp; AtomicVariable \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u043b\u044e\u0431\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430:<\/p>\n<pre><code class=\"cs\">[Serializable] public sealed class AtomicEvent&lt;T> {     private event Action&lt;T> onEvent;      public void Invoke(T args)     {         this.onEvent?.Invoke(args);     }          public void Subscribe(Action&lt;T> action)     {         this.onEvent += action;     }      public void Unsubscribe(Action&lt;T> action)     {         this.onEvent -= action;     } }<\/code><\/pre>\n<pre><code class=\"cs\">[Serializable] public sealed class AtomicVariable&lt;T> {     private event Action&lt;T> onValueChanged;      public T Value     {         get { return this.value; }         set         {             this.value = value;             this.onValueChanged?.Invoke(value);         }     }      [SerializeField]     private T value;      public AtomicVariable()     {     }      public AtomicVariable(T value)     {         this.value = value;     }      public void Subscribe(Action&lt;T> action)     {         this.onValueChanged += action;     }      public void Unsubscribe(Action&lt;T> action)     {         this.onValueChanged -= action;     } }<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 TakeDamageMechanics \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f  \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u043b\u043e\u0433\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 takeDamageEvent. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 OnTakeDamage(int), \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f hitPoints:<\/p>\n<pre><code class=\"cs\">public sealed class TakeDamageMechanics {     \/\/\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0435:     private readonly AtomicEvent&lt;int> takeDamageEvent;     private readonly AtomicVariable&lt;int> hitPoints;      public TakeDamageMechanics(         AtomicEvent&lt;int> takeDamageEvent,          AtomicVariable&lt;int> hitPoints     )     {         this.takeDamageEvent = takeDamageEvent;         this.hitPoints = hitPoints;     }      \/\/\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u043d MonoBehaviour.OnEnable     public void OnEnable()     {         this.takeDamageEvent.Subscribe(this.OnTakeDamage);     }      \/\/\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u043d MonoBehaviour.OnDisable     public void OnDisable()     {         this.takeDamageEvent.Unsubscribe(this.OnTakeDamage);     }      \/\/\u041b\u043e\u0433\u0438\u043a\u0430:     private void OnTakeDamage(int damage)     {         this.hitPoints.Value -= damage;     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c TakeDamageMechanics \u043a \u043a\u043b\u0430\u0441\u0441\u0443 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430:<\/p>\n<pre><code class=\"cs\">public sealed class Character : MonoBehaviour {     \/\/Data:     public AtomicEvent&lt;int> takeDamageEvent;     public AtomicVariable&lt;int> hitPoints;          \/\/Logic:     private TakeDamageMechanics takeDamageMechanics;      private void Awake()     {         this.takeDamageMechanics = new TakeDamageMechanics(             this.takeDamageEvent, this.hitPoints         );     }      private void OnEnable()     {         this.takeDamageMechanics.OnEnable();     }      private void OnDisable()     {         this.takeDamageMechanics.OnDisable();     } }<\/code><\/pre>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0441\u043a\u0440\u0438\u043f\u0442 Character \u043a GameObject&#8217;\u0443 \u043d\u0430 \u0441\u0446\u0435\u043d\u0435<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/403\/fec\/e6b\/403fece6b1dbb99410463f378f7148bb.png\" alt=\"\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0432 Unity\" title=\"\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0432 Unity\" width=\"780\" height=\"440\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/403\/fec\/e6b\/403fece6b1dbb99410463f378f7148bb.png\"\/><\/p>\n<div><figcaption>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0432 Unity<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0443\u0440\u043e\u043d\u0430:<\/p>\n<pre><code class=\"cs\">public sealed class TakeDamageTest : MonoBehaviour {     [SerializeField]     private Character character;      [SerializeField]     private int damage;      [ContextMenu(\"TakeDamage\")]     public void TakeDamage()     {         this.character.takeDamageEvent.Invoke(this.damage);     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443 \u0441\u043c\u0435\u0440\u0442\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430, \u043a\u043e\u0433\u0434\u0430 \u0435\u0433\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435 \u0440\u0430\u0432\u043d\u043e \u043d\u0443\u043b\u044e. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u043a\u043b\u0430\u0441\u0441 Character:<\/p>\n<pre><code class=\"cs\">public sealed class Character : MonoBehaviour {     \/\/Data:     public AtomicEvent&lt;int> takeDamageEvent;     public AtomicVariable&lt;int> hitPoints;     public AtomicEvent deathEvent; \/\/+     public AtomicVariable&lt;bool> isDead; \/\/+      \/\/Logic:     private TakeDamageMechanics takeDamageMechanics;     private DeathMechanics deathMechanics; \/\/+          private void Awake()     {         this.takeDamageMechanics = new TakeDamageMechanics(             this.takeDamageEvent, this.hitPoints         );         this.deathMechanics = new DeathMechanics(         \/\/+             this.hitPoints, this.isDead, this.deathEvent  \/\/+         );                                                \/\/+     }          private void OnEnable()     {         this.takeDamageMechanics.OnEnable();         this.deathMechanics.OnEnable(); \/\/+     }      private void OnDisable()     {         this.takeDamageMechanics.OnDisable();         this.deathMechanics.OnDisable(); \/\/+     } }<\/code><\/pre>\n<ul>\n<li>\n<p>\u041f\u043e\u043b\u0435 deathEvent \u2014 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441\u043c\u0435\u0440\u0442\u0438<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0435 isDead \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435: \u043c\u0435\u0440\u0442\u0432 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u0438\u043b\u0438 \u043d\u0435\u0442<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0435 deathMechanics \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441\u043c\u0435\u0440\u0442\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0438 \u0441\u0442\u0430\u0432\u0438\u0442 \u0444\u043b\u0430\u0436\u043e\u043a isDead \u0432 true<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u0441\u043c\u0435\u0440\u0442\u0438:<\/p>\n<pre><code class=\"cs\">public sealed class DeathMechanics {     private readonly AtomicVariable&lt;int> hitPoints;     private readonly AtomicVariable&lt;bool> isDead;     private readonly AtomicEvent deathEvent;      public DeathMechanics(         AtomicVariable&lt;int> hitPoints,          AtomicVariable&lt;bool> isDead,          AtomicEvent deathEvent     )     {         this.hitPoints = hitPoints;         this.isDead = isDead;         this.deathEvent = deathEvent;     }      public void OnEnable()     {         this.hitPoints.Subscribe(this.OnHitPointsChanged);     }      public void OnDisable()     {         this.hitPoints.Unsubscribe(this.OnHitPointsChanged);     }      private void OnHitPointsChanged(int hitPoints)     {         if (hitPoints &lt;= 0)         {             this.deathEvent.Invoke();             this.isDead.Value = true;         }     } }<\/code><\/pre>\n<p>\u0412\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u044b \u043b\u043e\u0433\u0438\u043a\u0438, \u0442\u043e \u0432 \u044d\u0442\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u0430\u0445 <strong>\u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c<\/strong> \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f! \u042d\u0442\u0438 \u043a\u043b\u0430\u0441\u0441\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0441 \u043d\u0438\u043c\u0438.<\/p>\n<h3>\u041c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0434\u0432\u0438\u0433\u0430\u0442\u044c\u0441\u044f \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"cs\">public sealed class MovementMechanics {     private readonly AtomicVariable&lt;float> moveSpeed;     private readonly AtomicVariable&lt;Vector3> moveDirection;     private readonly Transform transform;      public MovementMechanics(         AtomicVariable&lt;float> moveSpeed,         AtomicVariable&lt;Vector3> moveDirection,         Transform transform     )     {         this.moveSpeed = moveSpeed;         this.moveDirection = moveDirection;         this.transform = transform;     }      \/\/\u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0434\u0440     public void Update()     {         this.transform.position += this.moveDirection.Value * (this.moveSpeed.Value * Time.deltaTime);     } }<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 MoveMechanics \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0438 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0438 \u043c\u0435\u043d\u044f\u0435\u0442 \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 Transform \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0434\u0440. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443 \u0432 \u043a\u043e\u0434 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430:<\/p>\n<pre><code class=\"cs\">public sealed class Character : MonoBehaviour {     \/\/Data :     public AtomicVariable&lt;float> moveSpeed;        \/\/+     public AtomicVariable&lt;Vector3> moveDirection;  \/\/+      \/\/Logic:     private MovementMechanics movementMechanics;   \/\/+          private void Awake()     {         \/\/+         this.movementMechanics = new MovementMechanics(             this.moveSpeed, this.moveDirection, this.transform         );     }      \/\/+     private void Update()     {         this.movementMechanics.Update();     } }<\/code><\/pre>\n<p>\u041a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u0434 \u0438 \u0432\u0438\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/084\/17f\/a00\/08417fa000265726059e3f98147910c3.png\" alt=\"\u0418\u043d\u0441\u043f\u0435\u043a\u0442\u043e\u0440 \u0432 Unity\" title=\"\u0418\u043d\u0441\u043f\u0435\u043a\u0442\u043e\u0440 \u0432 Unity\" width=\"780\" height=\"440\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/084\/17f\/a00\/08417fa000265726059e3f98147910c3.png\"\/><\/p>\n<div><figcaption>\u0418\u043d\u0441\u043f\u0435\u043a\u0442\u043e\u0440 \u0432 Unity<\/figcaption><\/div>\n<\/figure>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<pre><code class=\"cs\">public sealed class MovementTest : MonoBehaviour {     [SerializeField]     private Character character;      private void Update()     {         if (Input.GetKey(KeyCode.LeftArrow))         {             this.character.moveDirection.Value = Vector3.left;         }         else if (Input.GetKey(KeyCode.RightArrow))         {             this.character.moveDirection.Value = Vector3.right;         }         else if (Input.GetKey(KeyCode.UpArrow))         {             this.character.moveDirection.Value = Vector3.forward;         }         else if (Input.GetKey(KeyCode.DownArrow))         {             this.character.moveDirection.Value = Vector3.back;         }         else         {             this.character.moveDirection.Value = Vector3.zero;         }     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u043d\u0435 \u0441\u043c\u043e\u0433 \u0434\u0432\u0438\u0433\u0430\u0442\u044c\u0441\u044f, \u0435\u0441\u043b\u0438 \u043e\u043d \u043c\u0435\u0440\u0442\u0432. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0442\u044c \/ \u0437\u0430\u043f\u0440\u0435\u0449\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430:<\/p>\n<pre><code class=\"cs\">public sealed class CanMoveMechanics {     private readonly AtomicVariable&lt;bool> canMove;     private readonly AtomicVariable&lt;bool> isDead;      public CanMoveMechanics(       AtomicVariable&lt;bool> canMove,        AtomicVariable&lt;bool> isDead     )     {         this.canMove = canMove;         this.isDead = isDead;     }      \/\/\u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0434\u0440     public void Update()     {         this.canMove.Value = this.CanMove();     }      private bool CanMove()     {         if (this.isDead.Value)         {             return false;         }          \/\/\u0412 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0449\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f         return true;     } }<\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f canMove \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0442\u043e\u043c, \u043c\u043e\u0436\u0435\u0442 \u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f \u0438\u043b\u0438 \u043d\u0435\u0442. \u0421\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e, \u0435\u0441\u043b\u0438 canMove \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 true:<\/p>\n<pre><code class=\"cs\">\/\/\u0414\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f: public sealed class MovementMechanics {     private readonly AtomicVariable&lt;bool> canMove; \/\/+     private readonly AtomicVariable&lt;float> moveSpeed;     private readonly AtomicVariable&lt;Vector3> moveDirection;     private readonly Transform transform;      public MovementMechanics(         AtomicVariable&lt;bool> canMove, \/\/+         AtomicVariable&lt;float> moveSpeed,         AtomicVariable&lt;Vector3> moveDirection,         Transform transform     )     {         this.canMove = canMove; \/\/+         this.moveSpeed = moveSpeed;         this.moveDirection = moveDirection;         this.transform = transform;     }      public void Update()     {         if (this.canMove.Value) \/\/+         {             this.transform.position += this.moveDirection.Value * (this.moveSpeed.Value * Time.deltaTime);         }     } }<\/code><\/pre>\n<p>\u041e\u0431\u043d\u043e\u0432\u0438\u043c \u0441\u043a\u0440\u0438\u043f\u0442 Character.cs:<\/p>\n<pre><code class=\"cs\">public sealed class Character : MonoBehaviour {     \/\/Data :     public AtomicVariable&lt;bool> canMove;           \/\/+     public AtomicVariable&lt;float> moveSpeed;             public AtomicVariable&lt;Vector3> moveDirection;        \/\/Logic:     private MovementMechanics movementMechanics;     private CanMoveMechanics canMoveMechanics; \/\/+           private void Awake()     {         this.canMoveMechanics = new CanMoveMechanics( \/\/+           this.canMove, this.isDead         );         this.movementMechanics = new MovementMechanics(           this.canMove, this.moveSpeed, this.moveDirection, this.transform \/\/+         );     }      \/\/+     private void Update()     {         this.movementMechanics.Update();         this.canMoveMechanics.Update(); \/\/+     } }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043c\u0435\u0435\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f, \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0440\u043e\u043d \u0438 \u0443\u043c\u0438\u0440\u0430\u0442\u044c.<\/p>\n<h3>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0443\u043b\u0438<\/h3>\n<p>\u041f\u0443\u043b\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438: \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435, \u043d\u0430\u043d\u043e\u0441\u0438\u0442\u044c \u0443\u0440\u043e\u043d \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0443 \u043f\u0440\u0438 \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u0438, \u0438 \u0435\u0441\u043b\u0438 \u043f\u0443\u043b\u044f \u043b\u0435\u0442\u0438\u0442 \u0434\u043e\u043b\u0433\u043e, \u0442\u043e \u043e\u043d\u0430 \u0438\u0441\u0447\u0435\u0437\u0430\u0435\u0442 \u0441\u043e \u0441\u0446\u0435\u043d\u044b.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043c\u044b \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438, \u0442\u043e \u043c\u044b \u0435\u0435 \u043c\u043e\u0436\u0435\u043c \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u0443\u043b\u0438:<\/p>\n<pre><code class=\"cs\">public sealed class Bullet : MonoBehaviour {     \/\/Data:     public AtomicVariable&lt;bool> canMove = new(true);     public AtomicVariable&lt;float> moveSpeed = new(3);     public AtomicVariable&lt;Vector3> moveDirection = new(Vector3.forward);      \/\/Logic:     private MovementMechanics movementMechanics;          private void Awake()     {         this.movementMechanics = new MovementMechanics(           this.canMove,            this.moveSpeed,            this.moveDirection,            this.transform       );     }      private void Update()     {         this.movementMechanics.Update();     } }<\/code><\/pre>\n<p>\u041c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0436\u0438\u0437\u043d\u0438 \u0434\u043b\u044f \u043f\u0443\u043b\u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"cs\">public sealed class BulletLifetimeMechanics {     private readonly AtomicVariable&lt;float> lifetime;     private readonly GameObject bullet;      public BulletLifetimeMechanics(         AtomicVariable&lt;float> lifetime,          GameObject bullet     )     {         this.lifetime = lifetime;         this.bullet = bullet;     }      public void Update()     {         this.lifetime.Value -= Time.deltaTime;                  if (this.lifetime.Value &lt;= 0)         {             GameObject.Destroy(this.bullet);         }     } }<\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f lifetime \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043e\u0441\u0442\u0430\u0432\u0448\u0435\u0435\u0441\u044f \u0432\u0440\u0435\u043c\u044f \u0434\u043e \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0443\u043b\u0438. \u0421\u0430\u043c\u0430 \u043b\u043e\u0433\u0438\u043a\u0430 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 Update() \u0447\u0435\u0440\u0435\u0437 Time.deltaTime. \u0412 \u043a\u043b\u0430\u0441\u0441\u0430\u0445 \u044f \u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0438\u0437\u0431\u0435\u0433\u0430\u0442\u044c \u043a\u043e\u0440\u0443\u0442\u0438\u043d. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043a \u043f\u0443\u043b\u0435:<\/p>\n<pre><code class=\"cs\">public sealed class Bullet : MonoBehaviour {     \/\/Data:     public AtomicVariable&lt;float> lifetime = new(3); \/\/+      \/\/Logic:     private BulletLifetimeMechanics lifetimeMechanics; \/\/+          private void Awake()     {         \/\/+         this.lifetimeMechanics = new BulletLifetimeMechanics(           this.lifetime, this.gameObject         );     }      private void Update()     {        this.lifetimeMechanics.Update(); \/\/+     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u043d\u0430\u043d\u0435\u0441\u0435\u043d\u0438\u044f \u0443\u0440\u043e\u043d\u0430 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0443 \u043f\u0440\u0438 \u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u0441 \u043d\u0438\u043c:<\/p>\n<pre><code class=\"cs\">public sealed class BulletCollisionMechanics {     private readonly AtomicVariable&lt;int> damage;     private readonly GameObject bullet;      public BulletCollisionMechanics(       AtomicVariable&lt;int> damage,        GameObject bullet     )     {         this.damage = damage;         this.bullet = bullet;     }      public void OnTriggerEnter(Collider collider)     {         if (collider.TryGetComponent(out Character character))         {             character.takeDamageEvent.Invoke(this.damage.Value);             GameObject.Destroy(this.bullet);         }     } }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 OnTriggerEnter \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u0435\u0442 \u0432\u044b\u0437\u043e\u0432 \u0438\u0437 \u043c\u043e\u043d\u043e\u0431\u0435\u0445\u0430 \u0438 \u0441\u0430\u043c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043b\u043e\u0433\u0438\u043a\u0443 \u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043a\u043b\u0430\u0441\u0441 Bullet \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"cs\">public sealed class Bullet : MonoBehaviour {     public AtomicVariable&lt;bool> canMove = new(true);     public AtomicVariable&lt;float> moveSpeed = new(3);     public AtomicVariable&lt;Vector3> moveDirection = new(Vector3.forward);      [Space]     public AtomicVariable&lt;int> damage = new(1);     public AtomicVariable&lt;float> lifetime = new(3);      private MovementMechanics movementMechanics;     private BulletCollisionMechanics collisionMechanics;     private BulletLifetimeMechanics lifetimeMechanics;      private void Awake()     {         this.movementMechanics = new MovementMechanics(           this.canMove, this.moveSpeed, this.moveDirection, this.transform         );         this.collisionMechanics = new BulletCollisionMechanics(           this.damage, this.gameObject         );         this.lifetimeMechanics = new BulletLifetimeMechanics(           this.lifetime, this.gameObject         );     }      private void Update()     {         this.movementMechanics.Update();         this.lifetimeMechanics.Update();     }      private void OnTriggerEnter(Collider other)     {         this.collisionMechanics.OnTriggerEnter(other);     } }<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043b\u043b\u0430\u0439\u0434\u0435\u0440\u044b \u043d\u0430 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0438 \u043f\u0443\u043b\u044e, \u0442\u043e \u043f\u0443\u043b\u044f \u0431\u0443\u0434\u0435\u0442 \u043b\u0435\u0442\u0435\u0442\u044c \u0438 \u043d\u0430\u043d\u043e\u0441\u0438\u0442\u044c \u0443\u0440\u043e\u043d<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b6d\/033\/576\/b6d033576dc89c622eb3a32b067831f3.png\" alt=\"\u0418\u043d\u0441\u043f\u0435\u043a\u0442\u043e\u0440 \u0432 Unity\" title=\"\u0418\u043d\u0441\u043f\u0435\u043a\u0442\u043e\u0440 \u0432 Unity\" width=\"780\" height=\"440\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b6d\/033\/576\/b6d033576dc89c622eb3a32b067831f3.png\"\/><\/p>\n<div><figcaption>\u0418\u043d\u0441\u043f\u0435\u043a\u0442\u043e\u0440 \u0432 Unity<\/figcaption><\/div>\n<\/figure>\n<h2>\u0412\u044b\u0432\u043e\u0434\u044b<\/h2>\n<p>\u0418\u0442\u0430\u043a, \u0447\u0442\u043e \u043d\u0430\u043c \u0434\u0430\u0435\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043b\u043e\u0433\u0438\u043a\u0438:<\/p>\n<ol>\n<li>\n<p>\u041a\u0430\u0436\u0434\u0430\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e\u0439, \u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c<\/p>\n<\/li>\n<li>\n<p>\u041b\u0435\u0433\u043a\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c \u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u041b\u0435\u0433\u043a\u043e \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043b\u044e\u0431\u0430\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445<\/p>\n<\/li>\n<\/ol>\n<p>\u041a\u0430\u043a\u0438\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438, \u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0434\u0430\u0442\u044c:<\/p>\n<ol>\n<li>\n<p>\u0421\u0442\u0430\u0440\u0430\u0442\u044c\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043a\u043b\u0430\u0441\u0441 \u043b\u043e\u0433\u0438\u043a\u0438 \u043d\u0435 \u0438\u043c\u0435\u043b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0430\u0440\u0430\u0442\u044c\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441\u044b \u043b\u043e\u0433\u0438\u043a\u0438 \u043f\u043e \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443 SRP<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0430\u0440\u0430\u0442\u044c\u0441\u044f \u0443\u0445\u043e\u0434\u0438\u0442\u044c \u043e\u0442 \u043a\u043e\u0440\u0443\u0442\u0438\u043d \u0432 \u0446\u0435\u043b\u044f\u0445 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0441\u043a\u0430\u0436\u0443, \u0447\u0442\u043e \u044d\u0442\u043e \u0431\u044b\u043b \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 <a href=\"https:\/\/habr.com\/ru\/articles\/735244\/\">\u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430<\/a> \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u0430 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u044b\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u043d\u0430 Unity, \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043d\u0430 <a href=\"https:\/\/otus.pw\/igcp\/\">\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u043c \u0432\u0435\u0431\u0438\u043d\u0430\u0440\u0435 \u0443\u0436\u0435 5 \u043e\u043a\u0442\u044f\u0431\u0440\u044f<\/a>. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0438 <a href=\"https:\/\/otus.pw\/igcp\/\">\u0436\u0434\u0443 \u0432\u0441\u0435\u0445 \u043d\u0430 \u0432\u0435\u0431\u0438\u043d\u0430\u0440\u0435<\/a> \ud83d\ude42<\/p>\n<p><a href=\"https:\/\/drive.google.com\/file\/d\/1f9dK9s0H7jq2EDohmd8MEZ4xxuJQIvQJ\/view?usp=sharing\">\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0434\u0435\u043c\u043e-\u043f\u0440\u043e\u0435\u043a\u0442<\/a> \u0432 Google Drive<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/764658\/\"> https:\/\/habr.com\/ru\/articles\/764658\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><\/figure>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0418\u0433\u043e\u0440\u044c, \u0438 \u044f Unity Developer. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u0434\u043b\u044f \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043b\u043e\u0433\u0438\u043a\u0443.<\/p>\n<blockquote>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0447\u0438\u0442\u0430\u043b\u0438 \u043c\u043e\u044e <a href=\"https:\/\/habr.com\/ru\/articles\/735244\/\">\u0441\u0442\u0430\u0442\u044c\u044e<\/a> \u043f\u0440\u043e \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0434\u0438\u0437\u0430\u0439\u043d, \u0442\u043e \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u043d\u0435\u0439. \u041d\u043e \u044d\u0442\u043e \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e.<\/p>\n<\/blockquote>\n<p>\u0426\u0435\u043b\u044c \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0433\u0438\u0431\u043a\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 Unity, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0441\u0430\u0436\u0438\u0432\u0430\u0439\u0442\u0435\u0441\u044c \u043a \u043e\u0433\u043e\u043d\u044c\u043a\u0443.<\/p>\n<p>\u0414\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430 \u043a\u0443\u0431\u0430\u0445 \u2014 \u044d\u0442\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u0438 \u043f\u0443\u043b\u044f.<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u041d\u0430\u0448\u0438 \u043f\u043e\u0434\u043e\u043f\u044b\u0442\u043d\u044b\u0435 \u0432 Unity<\/figcaption><\/div>\n<\/figure>\n<p>\u0423 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435 \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f, \u0430 \u0443 \u043f\u0443\u043b\u0438 \u2014 \u043b\u0435\u0442\u0435\u0442\u044c \u0438 \u043d\u0430\u043d\u043e\u0441\u0438\u0442\u044c \u0443\u0440\u043e\u043d \u043f\u0440\u0438 \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u0438 \u0432 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430. \u041d\u0430 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u043e\u043f\u044b\u0442\u0430\u044e\u0441\u044c \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u044c \u043f\u0440\u0435\u043b\u0435\u0441\u0442\u044c \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043b\u043e\u0433\u0438\u043a\u0438. \u041d\u0443 \u0448\u043e, \u043f\u043e\u0435\u0445\u0430\u043b\u0438 \ud83d\ude42<\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430<\/h2>\n<p>\u0412 \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u043b\u044e\u0431\u043e\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043b\u043e\u0433\u0438\u043a\u0438. \u041f\u043e\u0434 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u044f \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u044e \u043b\u044e\u0431\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0445\u0440\u0430\u043d\u0438\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 (\u043f\u043e\u043b\u044f \/ \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \/ \u0441\u043e\u0431\u044b\u0442\u0438\u044f), \u043f\u043e\u0434 \u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u2014 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b (\u043c\u0435\u0442\u043e\u0434\u044b, \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \/ \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u044d\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430. \u0414\u0430, \u044d\u0442\u043e ECS, \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \ud83d\ude42<\/p>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u0438\u043c\u0435\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f \u0438 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0443\u0440\u043e\u043d\u0430, \u043e\u043f\u0438\u0448\u0435\u043c \u044d\u0442\u043e:<\/p>\n<pre><code class=\"cs\">public sealed class Character : MonoBehaviour {     \/\/\u0414\u0430\u043d\u043d\u044b\u0435:     public AtomicEvent&lt;int> takeDamageEvent;     public AtomicVariable&lt;int> hitPoints;          \/\/\u041b\u043e\u0433\u0438\u043a\u0430:     private TakeDamageMechanics takeDamageMechanics; }<\/code><\/pre>\n<ul>\n<li>\n<p>\u041f\u043e\u043b\u0435 takeDamageEvent \u0442\u0438\u043f\u0430 AtomicEvent&lt;T> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0443\u0440\u043e\u043d\u0430<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0435 hitPoints \u0442\u0438\u043f\u0430 AtomicVariable&lt;T> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u043a\u043e\u043b-\u0432\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f \u0438 \u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0435\u0442 \u043e \u0435\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0435 takeDamageMechanics \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0443\u0440\u043e\u043d\u0430 \u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442 \u043a\u043e\u043b-\u0432\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u043b\u0430\u0441\u0441\u044b AtomicEvent &amp; AtomicVariable \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u043b\u044e\u0431\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430:<\/p>\n<pre><code class=\"cs\">[Serializable] public sealed class AtomicEvent&lt;T> {     private event Action&lt;T> onEvent;      public void Invoke(T args)     {         this.onEvent?.Invoke(args);     }          public void Subscribe(Action&lt;T> action)     {         this.onEvent += action;     }      public void Unsubscribe(Action&lt;T> action)     {         this.onEvent -= action;     } }<\/code><\/pre>\n<pre><code class=\"cs\">[Serializable] public sealed class AtomicVariable&lt;T> {     private event Action&lt;T> onValueChanged;      public T Value     {         get { return this.value; }         set         {             this.value = value;             this.onValueChanged?.Invoke(value);         }     }      [SerializeField]     private T value;      public AtomicVariable()     {     }      public AtomicVariable(T value)     {         this.value = value;     }      public void Subscribe(Action&lt;T> action)     {         this.onValueChanged += action;     }      public void Unsubscribe(Action&lt;T> action)     {         this.onValueChanged -= action;     } }<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 TakeDamageMechanics \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f  \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u043b\u043e\u0433\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 takeDamageEvent. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 OnTakeDamage(int), \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f hitPoints:<\/p>\n<pre><code class=\"cs\">public sealed class TakeDamageMechanics {     \/\/\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0435:     private readonly AtomicEvent&lt;int> takeDamageEvent;     private readonly AtomicVariable&lt;int> hitPoints;      public TakeDamageMechanics(         AtomicEvent&lt;int> takeDamageEvent,          AtomicVariable&lt;int> hitPoints     )     {         this.takeDamageEvent = takeDamageEvent;         this.hitPoints = hitPoints;     }      \/\/\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u043d MonoBehaviour.OnEnable     public void OnEnable()     {         this.takeDamageEvent.Subscribe(this.OnTakeDamage);     }      \/\/\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u043d MonoBehaviour.OnDisable     public void OnDisable()     {         this.takeDamageEvent.Unsubscribe(this.OnTakeDamage);     }      \/\/\u041b\u043e\u0433\u0438\u043a\u0430:     private void OnTakeDamage(int damage)     {         this.hitPoints.Value -= damage;     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c TakeDamageMechanics \u043a \u043a\u043b\u0430\u0441\u0441\u0443 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430:<\/p>\n<pre><code class=\"cs\">public sealed class Character : MonoBehaviour {     \/\/Data:     public AtomicEvent&lt;int> takeDamageEvent;     public AtomicVariable&lt;int> hitPoints;          \/\/Logic:     private TakeDamageMechanics takeDamageMechanics;      private void Awake()     {         this.takeDamageMechanics = new TakeDamageMechanics(             this.takeDamageEvent, this.hitPoints         );     }      private void OnEnable()     {         this.takeDamageMechanics.OnEnable();     }      private void OnDisable()     {         this.takeDamageMechanics.OnDisable();     } }<\/code><\/pre>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0441\u043a\u0440\u0438\u043f\u0442 Character \u043a GameObject&#8217;\u0443 \u043d\u0430 \u0441\u0446\u0435\u043d\u0435<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0432 Unity<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0443\u0440\u043e\u043d\u0430:<\/p>\n<pre><code class=\"cs\">public sealed class TakeDamageTest : MonoBehaviour {     [SerializeField]     private Character character;      [SerializeField]     private int damage;      [ContextMenu(\"TakeDamage\")]     public void TakeDamage()     {         this.character.takeDamageEvent.Invoke(this.damage);     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443 \u0441\u043c\u0435\u0440\u0442\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430, \u043a\u043e\u0433\u0434\u0430 \u0435\u0433\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435 \u0440\u0430\u0432\u043d\u043e \u043d\u0443\u043b\u044e. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u043a\u043b\u0430\u0441\u0441 Character:<\/p>\n<pre><code class=\"cs\">public sealed class Character : MonoBehaviour {     \/\/Data:     public AtomicEvent&lt;int> takeDamageEvent;     public AtomicVariable&lt;int> hitPoints;     public AtomicEvent deathEvent; \/\/+     public AtomicVariable&lt;bool> isDead; \/\/+      \/\/Logic:     private TakeDamageMechanics takeDamageMechanics;     private DeathMechanics deathMechanics; \/\/+          private void Awake()     {         this.takeDamageMechanics = new TakeDamageMechanics(             this.takeDamageEvent, this.hitPoints         );         this.deathMechanics = new DeathMechanics(         \/\/+             this.hitPoints, this.isDead, this.deathEvent  \/\/+         );                                                \/\/+     }          private void OnEnable()     {         this.takeDamageMechanics.OnEnable();         this.deathMechanics.OnEnable(); \/\/+     }      private void OnDisable()     {         this.takeDamageMechanics.OnDisable();         this.deathMechanics.OnDisable(); \/\/+     } }<\/code><\/pre>\n<ul>\n<li>\n<p>\u041f\u043e\u043b\u0435 deathEvent \u2014 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441\u043c\u0435\u0440\u0442\u0438<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0435 isDead \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435: \u043c\u0435\u0440\u0442\u0432 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u0438\u043b\u0438 \u043d\u0435\u0442<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0435 deathMechanics \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441\u043c\u0435\u0440\u0442\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0438 \u0441\u0442\u0430\u0432\u0438\u0442 \u0444\u043b\u0430\u0436\u043e\u043a isDead \u0432 true<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u0441\u043c\u0435\u0440\u0442\u0438:<\/p>\n<pre><code class=\"cs\">public sealed class DeathMechanics {     private readonly AtomicVariable&lt;int> hitPoints;     private readonly AtomicVariable&lt;bool> isDead;     private readonly AtomicEvent deathEvent;      public DeathMechanics(         AtomicVariable&lt;int> hitPoints,          AtomicVariable&lt;bool> isDead,          AtomicEvent deathEvent     )     {         this.hitPoints = hitPoints;         this.isDead = isDead;         this.deathEvent = deathEvent;     }      public void OnEnable()     {         this.hitPoints.Subscribe(this.OnHitPointsChanged);     }      public void OnDisable()     {         this.hitPoints.Unsubscribe(this.OnHitPointsChanged);     }      private void OnHitPointsChanged(int hitPoints)     {         if (hitPoints &lt;= 0)         {             this.deathEvent.Invoke();             this.isDead.Value = true;         }     } }<\/code><\/pre>\n<p>\u0412\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u044b \u043b\u043e\u0433\u0438\u043a\u0438, \u0442\u043e \u0432 \u044d\u0442\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u0430\u0445 <strong>\u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c<\/strong> \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f! \u042d\u0442\u0438 \u043a\u043b\u0430\u0441\u0441\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0441 \u043d\u0438\u043c\u0438.<\/p>\n<h3>\u041c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0434\u0432\u0438\u0433\u0430\u0442\u044c\u0441\u044f \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"cs\">public sealed class MovementMechanics {     private readonly AtomicVariable&lt;float> moveSpeed;     private readonly AtomicVariable&lt;Vector3> moveDirection;     private readonly Transform transform;      public MovementMechanics(         AtomicVariable&lt;float> moveSpeed,         AtomicVariable&lt;Vector3> moveDirection,         Transform transform     )     {         this.moveSpeed = moveSpeed;         this.moveDirection = moveDirection;         this.transform = transform;     }      \/\/\u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0434\u0440     public void Update()     {         this.transform.position += this.moveDirection.Value * (this.moveSpeed.Value * Time.deltaTime);     } }<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 MoveMechanics \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0438 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0438 \u043c\u0435\u043d\u044f\u0435\u0442 \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 Transform \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0434\u0440. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443 \u0432 \u043a\u043e\u0434 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430:<\/p>\n<pre><code class=\"cs\">public sealed class Character : MonoBehaviour {     \/\/Data :     public AtomicVariable&lt;float> moveSpeed;        \/\/+     public AtomicVariable&lt;Vector3> moveDirection;  \/\/+      \/\/Logic:     private MovementMechanics movementMechanics;   \/\/+          private void Awake()     {         \/\/+         this.movementMechanics = new MovementMechanics(             this.moveSpeed, this.moveDirection, this.transform         );     }      \/\/+     private void Update()     {         this.movementMechanics.Update();     } }<\/code><\/pre>\n<p>\u041a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u0434 \u0438 \u0432\u0438\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u0418\u043d\u0441\u043f\u0435\u043a\u0442\u043e\u0440 \u0432 Unity<\/figcaption><\/div>\n<\/figure>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<pre><code class=\"cs\">public sealed class MovementTest : MonoBehaviour {     [SerializeField]     private Character character;      private void Update()     {         if (Input.GetKey(KeyCode.LeftArrow))         {             this.character.moveDirection.Value = Vector3.left;         }         else if (Input.GetKey(KeyCode.RightArrow))         {             this.character.moveDirection.Value = Vector3.right;         }         else if (Input.GetKey(KeyCode.UpArrow))         {             this.character.moveDirection.Value = Vector3.forward;         }         else if (Input.GetKey(KeyCode.DownArrow))         {             this.character.moveDirection.Value = Vector3.back;         }         else         {             this.character.moveDirection.Value = Vector3.zero;         }     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u043d\u0435 \u0441\u043c\u043e\u0433 \u0434\u0432\u0438\u0433\u0430\u0442\u044c\u0441\u044f, \u0435\u0441\u043b\u0438 \u043e\u043d \u043c\u0435\u0440\u0442\u0432. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0442\u044c \/ \u0437\u0430\u043f\u0440\u0435\u0449\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430:<\/p>\n<pre><code class=\"cs\">public sealed class CanMoveMechanics {     private readonly AtomicVariable&lt;bool> canMove;     private readonly AtomicVariable&lt;bool> isDead;      public CanMoveMechanics(       AtomicVariable&lt;bool> canMove,        AtomicVariable&lt;bool> isDead     )     {         this.canMove = canMove;         this.isDead =<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-356367","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/356367","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=356367"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/356367\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=356367"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=356367"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=356367"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}