<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های sina karimi</title>
        <link>https://virgool.io/feed/@sinakarimi0938</link>
        <description>نیمچه برنامه نویس و توسعه دهنده بازی</description>
        <language>fa</language>
        <pubDate>2026-06-16 17:58:52</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/1725433/avatar/XCx05f.jpeg?height=120&amp;width=120</url>
            <title>sina karimi</title>
            <link>https://virgool.io/@sinakarimi0938</link>
        </image>

                    <item>
                <title>راه‌اندازی سریع Nakama در Unity</title>
                <link>https://virgool.io/codenevis/%D8%B1%D8%A7%D9%87-%D8%A7%D9%86%D8%AF%D8%A7%D8%B2%DB%8C-%D8%B3%D8%B1%DB%8C%D8%B9-nakama-%D8%AF%D8%B1-unity-qxyfdl14doga</link>
                <description>چند روزی بود که درگیر پیاده سازی یک جدول امتیاز ( پیاده سازی Leader board) داخل یونیتی بودم، با خودم گفتم که ای کاش یک پکیج جمع و جور براش بنویسم و سعی کنم که توسعش بدماین شد که یک Repo به نام Nakama Server Communication ایجاد کردم.خوش حال میشم ازش انتقاد کنید.لینک Repoسعی کردم که داکیومنت خوبی رو برای نحوه پیاده سازیش تعریف کنم و داخل Repo قرار بدم.</description>
                <category>sina karimi</category>
                <author>sina karimi</author>
                <pubDate>Wed, 28 May 2025 15:44:00 +0330</pubDate>
            </item>
                    <item>
                <title>معماری سرور بازی های چند نفره</title>
                <link>https://virgool.io/@sinakarimi0938/%D9%85%D8%B9%D9%85%D8%A7%D8%B1%DB%8C-%D8%B3%D8%B1%D9%88%D8%B1-%D9%87%D8%A7%DB%8C-%D8%A8%D8%A7%D8%B2%DB%8C-%D9%87%D8%A7%DB%8C-%DA%86%D9%86%D8%AF-%D9%86%D9%81%D8%B1%D9%87-glmwoacqql5t</link>
                <description>سلام امیدوارم که حال دلتون خوب باشه، باز آخر هفته شد و تصمیم گرفتم که راجب یک موضوع جدید تو حوزه بازی سازی تحقیق کنم و نتیجه رو با شما به اشتراک بزارم.قرار گذاشتم که راجب بازی های آنلاین و چند نفره تحقیق کنم و ببینم که چجوری می تونم یک بازی چند نفره خیلی ساده با موتور بازی سازی یونیتی توسعه بدم تا در این زمینه هم تجربه ایی بدست بیارم.با یک سرچ ساده به کلمه ایی بر خوردم به نام NetCode که احتمالا راجبش شنیدین. قبل از اینکه راجب NetCode داخل موتور بازی سازی یونیتی صحبت کنم دوست دارم که چند تا معماری مختلف برای بازی های چند نفره رو بررسی کنیم و در نوشته های بعدی (اگر عمری باشه و تایمی داشته باشم ...) به مسئله NetCode بپردازیم.معماری های متفاوتی برای توسعه یک بازی چند نفره وجود داره که به ما کمک میکنن تا client ها یا همون player هامون رو به یکدیگر متصل کنیم.Local or couch multiplayerقطعا برای شما هم اتفاق افتاده که با رفیق رفقا جمع بشید دور هم و بازی هایی مثل کراش ماشینی  بازی کنید، معماری این دسته از بازیی هایی که می تونیم تو جمع ها و دوره همی ها با دوستانمون بازی کنیم local or couch multiplayer نام میگیرن، جالبه بدونید، کلمه couch که به کاناپه اشاره داره، این مفهوم رو میرسونه که می تونیم باهم دیگه روی یک کاناپه بشینیم و روی یک صفحه نمایش بازی کنیم.Lan game (offline)احتمالا برای شما هم اتفاق افتاده که چند تا سیستم رو از طریق کابل های Lan به یکدیگر متصل کنید و بازی هایی مثل کانتر رو با اطرافیان بازی کنید، این دسته از بازی ها به معماری Lan (offline) تعلق پیدا میکنن.Peer-to-Peer (P2P)این معماری زمانی اعمال می شود که به عنوان مثال دو client می خواهند بدون وجود یک سرور مرکزی به یکدیگر متصل بشن و از منابع یکدیگر نیز استفاده بکنند.Client hosted (Listen server)در این معماری یکی از client ها دارای دو مسئولیت هست، هم به عنوان Host عمل میکنه که سایر client ها به او وصل میشن  و هم به عنوان client می تونه داخل بازی شرکت کند.یکی از تفاوت های این معماری با معماری P2P این است که این معماری centralize و معماری P2P یک معماری decentralize می باشد.Dedicated Game Server (DGS)در این نوع معماری زیر ساخت ها و سرور هایی برای بازی طراحی می شود که بازیکنان می توانند از طریق اتصال به آن با یکدیگر بازی کنند.اینکه کدام یک از این معماری ها برای بازی ما مناسب هست، به خواسته ها و نوع پروژه ما بستگی داره و نمی توان گفت کدام معماری بهترین هست و بهترین نتیجه رو خواهد داشت.مرسی که وقت گذاشتین، تا مطالب بعدی شاد باشید. :)</description>
                <category>sina karimi</category>
                <author>sina karimi</author>
                <pubDate>Fri, 26 Jan 2024 20:56:50 +0330</pubDate>
            </item>
                    <item>
                <title>Clean Architecture</title>
                <link>https://virgool.io/@sinakarimi0938/clean-architecture-kv7xe5gluoku</link>
                <description>سلام امیدوارم که شاد و خندون باشید.امروز کتاب Clean Architecture اثر Robert C. Martin (Uncle Bob) شروع به خوندن کردم و دوست دارم بخش هایی که برای خودم جذاب بود رو با شما به اشتراک بزارم.عمو باب میگه داستان دوران کودکیمون که در رابطه با مسابقه بین خرگوش و لاکپشت بود خیلی مشابه داستان توسعه دهندگان نرم افزار هست.ما سه تا درس از داستان خرگوش و لاکپشت گرفتیم:رهرو آن نیست که گهی تند و گهی خسته رود، ره رو آن است که آهسته و پیوسته رود. البته اون بزرگوار این جمله رو نگفت و این برداشت من بود :)صرفا افرادی که سرعت بالاتری دارند قهرمان مسابقه نمی شوند، قدرت شرط کافی برای پیروزی در نبرد نیست.هرچه آدم عجول تر رفتار بکنه سرعت و دقتش برای به ثمر رسوندن کار کمتر میشه.درسته توسعه دهندگان نرم افزار مثل خرگوش قصه ما زیر سایه یک درخت در دشتی خوش آب و هوا به خواب نمیرن اما ممکن هست که ذهنشون زیر سایه غرور، عادت های بد و دروغ هایی که جلو تر مطرح میکنم به خوابی عمیق برود و در بلند مدت ( چه بسا حتی در کوتاه مدت) باعث به ضیان رسیدن یک پروژه شود.این دسته از توسعه دهندگان این دروغ ها رو به خودشون میگن:بعدا سر فرصت کد رو تمیز و ساختار مند میکنیم.اول بازار رو بدست بیاریم بعدش خدا بزرگه و اصول رو داخل پروژه پیاده سازی میکنیم....غافل از اینکه هیچوقت اون فرصتی که دنبالش هستن پیش نخواهد آمد. هرچقدر پروژه جلوتر بره فشار بازار و نیاز کاربران چند برابر خواهد شد.بهتر هست که از ابتدا به اصول و ساختار یک پروژه فکر کنیم و زمان بگذاریم تا در آینده مجبور نباشیم دو برار زمان و منابع خود را مصرف کنیم تا به بتونیم پروژه رو به حالت تعادل برسونیم.ناگفته نماند که خیلی از اوقات توسعه دهندگان مقصر نیستن و این فشار کارفرما هست که همچین فاجعه ایی رو رقم میزند.با تشکر از عمو بابتا مطلب بعدی شاد باشید.</description>
                <category>sina karimi</category>
                <author>sina karimi</author>
                <pubDate>Fri, 24 Nov 2023 22:44:42 +0330</pubDate>
            </item>
                    <item>
                <title>پس از کامپایل شدن برنامه های مبتنی بر Net. چه فایل هایی داریم؟</title>
                <link>https://virgool.io/@sinakarimi0938/%D9%BE%D8%B3-%D8%A7%D8%B2-%DA%A9%D8%A7%D9%85%D9%BE%D8%A7%DB%8C%D9%84-%D8%B4%D8%AF%D8%AF%D9%86-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-%D9%85%D8%A8%D8%AA%D9%86%DB%8C-%D8%A8%D8%B1-net-%DA%86%D9%87-%D9%81%D8%A7%DB%8C%D9%84-%D9%87%D8%A7%DB%8C%DB%8C-%D8%AF%D8%A7%D8%B1%DB%8C%D9%85-bfjqm9cfvdfy</link>
                <description>برنامه هایی که مبتنی بر Net.  نوشته می شوند بعد از Compile شدن، تبدیل به یک سری فایل خروجی می شوند که به این فایل های خروجی اصطلاحاً Assembly می گویند. در حقیقت Assembly ها شامل اطلاعات مربوط به کدهای نوشته شده برای برنامه هستند. هر اسمبلی می تواند شامل موارد زیر باشد:Assembly Manifest:توصیفات اسمبلی،  مانند نام اسمبلی، نسخه اسمبلی و ...Type Metadataاطلاعات نوع های داده موجود در اسمبلی، برای مثال نام کلاس، سطح دسترسی به کلاس، اعضاء کلاس و  یکسری اطلاعات  که آن عضو را به صورت اختصاری توصیف می کنند، برای مثال یک متد می تواند شامل اطلاعاتی مانند نام متد، نوع داده بازگشتی و پارامتر های متد باشد.IL codeکدی که در زبان سی شارپ نوشته می شود، بعد از Compile شدن به کد IL یا Intermediate Language که یک زبان میانی است تبدیل می شود و در انتها، این کد با کمک CLR به زبان ماشین تبدیل می شود.در زبان سی شارپ می توان با کمک قابلیتی به نام Reflection، اطلاعات یا Meta Data های مربوط به برنامه ها را خواند و از آن ها استفاده کرد.اگر مایل هستید که با Reflection آشنایی پیدا کنید، نوشته کار با Reflection در C# را مطالعه کنید.</description>
                <category>sina karimi</category>
                <author>sina karimi</author>
                <pubDate>Mon, 06 Mar 2023 09:02:09 +0330</pubDate>
            </item>
                    <item>
                <title>کار با Reflection در C#</title>
                <link>https://virgool.io/@sinakarimi0938/%DA%A9%D8%A7%D8%B1-%D8%A8%D8%A7-reflection-%D8%AF%D8%B1-c-nu5ee2nv7wib</link>
                <description>سلام امیدوارم که لبتون خندون و حالتون خوب باشه.اخیرا در حال توسعه یک پروژه آموزشی هستم و داخل پروژه به یک سیستم save و Load نیاز پیدا کردم و پس از کمک گرفتن از یک فرد حرفه ایی و بررسی راه های موجود تصمیم گرفتم که از مبحثی به نام Reflection داخل پروژه استفاده کنم و دوست دارم مطالبی که یاد گرفته ام رو با شما عزیزان هم به اشتراک بگذارم.قبل از هرچیز، اگر با فایل ها اسمبلی که در هنگام خروجی گرفتن برنامه های Net. ایجاد می شوند آشنایی ندارید، توصیه میکنم نوشته پس از کامپایل شدن برنامه های مبتنی بر Net. چه فایل هایی داریم؟ را مطالعه کنید.توسعه دهندگان می توانند با استفاده از Reflection به بررسی و کنترل MetaData های Types، Objects و Assemblies بپردازند.از این قابلیت می توان برای بدست آوردن اطلاعاتی در رابطه با ساختار و رفتار یک کد استفاده نمود.( به عنوان مثال اطلاعاتی در رابطه با classes , methods , attributes , properties , fields و events)در چه زمانی Reflection بدردمون می خوره؟هنگامی که برنامه نیاز به آنالیز و ایجاد تغییر در رفتار کد دارد، به عنوان مثال در زمان های زیر می توان از Reflection کمک گرفت:Serialization of objectsDeserialization of objectsCode generatorsPlugin systemsدر صورت استفاده از Reflection  برنامه چه توانایی هایی پیدا میکند؟با استفاده از این قابلیت قدرتمند، برنامه توانایی استخراج و استفاده از اطلاعاتی در رابطه با موارد زیر را پیدا میکند:Types and objectsCreate new objectsInvoke methodsAccess properties and fieldsInspect attributesچگونه از Reflection استفاده کنیم؟جهت استفاده از Reflection در C# می بایست از فضای نام System.Reflectionاستفاده نمود.مثال :using System;
using System.Reflection;
class MyClass {
    public int MyField;
    public void MyMethod() {}
}
class Program {
    static void Main() {
        Type t = typeof(MyClass);
        Console.WriteLine(&amp;quotName: &amp;quot + t.Name);
        Console.WriteLine(&amp;quotFields: &amp;quot);
        foreach (FieldInfo f in t.GetFields()) 
        {
            Console.WriteLine(&amp;quot- &amp;quot + f.Name);
        }
        Console.WriteLine(&amp;quotMethods: &amp;quot);
        foreach (MethodInfo m in t.GetMethods())
        {
           Console.WriteLine(&amp;quot- &amp;quot + m.Name);
        }
    }
}</description>
                <category>sina karimi</category>
                <author>sina karimi</author>
                <pubDate>Mon, 06 Mar 2023 00:34:55 +0330</pubDate>
            </item>
                    <item>
                <title>میان سخت افزار و نرم افزار چیست ؟!</title>
                <link>https://virgool.io/@sinakarimi0938/%D9%85%DB%8C%D8%A7%D9%86-%D8%B3%D8%AE%D8%AA-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D9%88-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%DA%86%DB%8C%D8%B3%D8%AA-itpx00dqkofb</link>
                <description>سلام امیدوام که کیفتون کوک باشه و لبتون خندون  یک هفته ایی از انتشار نوشته ام در رابطه با کارهای جذاب با تابع سازنده Constructor در سی شارپ میگذره و تو این هفته ایی که گذشت با خودم گفتم چقدر خوب است که هر هفته اطلاعاتی که برای خودم جذاب و با حال هستن رو اینجا به اشتراک بزارم .به احتمال زیاد اکثر انسان ها راجب سخت افزار (Hardware) و نرم افزار (Software) شنیده اند اما من امروز می خواهم راجب میان افزار (Firmware) صحبت کنم، مبحثی که شاید نامش به گوش افرادی نرسیده باشد.میان افزار همانطور که از نامش پیداس نه سخت افزار هست و نه نرم افزار بلکه یک چیزی میان این دو هست که به سخت افزار ها  برای انجام کار ها کمک میکند.به عنوان مثال Motherboard کامپیوتر ها که روی آن ها cpu , Ram و ... قرار گرفته است رو در نظر بگیرید، این بخش خالصا از سخت افزار و الکترونیک ساخته نشده است بلکه خودش بروی خودش در حال اجرا کردن نرم افزاری هست که به واسطه آن خیلی از کار ها را متوجه میشود، مثلا می گوید سعی کن یک Hard پیدا بکنی و از رو آن Hard بخوان و بعدش روی Memory ثبتش کن. ( بافرض اینکه Motherboard زبان داشته باشد و این حرف رو بزنه D: )اون به اصطلاح نرم افزاری که روی سخت افزار اجرا میشود و به سخت افزار کمک میکند همان میان نرم افزار ما هست . :)میان نرم افزار های قدیمی BIOS نام داشتند که احتمالا اگر یکبار اقدام به نصب سیستم عامل کرده باشید، آشناییت کلی نسبت بهش دارید و عکسش هم در قسمت پایین براتون قرار داده ام.BIOSشیوه کار BIOS اینگونه بود که به MBR (اولین پارتیشن HardDisk) مراجعه میکرد و با استفاده از آن و Memory به cpu میگفت که اجرا بشود.از معایب BIOS می توانیم به کوچک بدون فضای MBR اشاره کنیم که برای بوت کردن سیستم های مدرن کار را سخت میکرد اما از آنجایی که علم بیکار نشست و روز به روز پیشرفت کرد، میان نرم افزاری به اسم UEFI را ساختند که دیگر محدودیت BIOS قدیمی را نداشت و چه از نظر زیبایی محیط گرافیکیش و چه از نظر قابلیت هایی که در اختیار کاربر قرا میداد، خیره کننده و قابل توجه بود.UEFI  امیدوارم که اطلاعات مفیدی را به اطلاعات شما افزوده باشم و به نظرم دنیا جای قشنگ تری میشه اگر اطلاعات خوبمون رو با هم به اشتراک بگذاریم.شاد باشید. :)منبع:  Lpic1Book</description>
                <category>sina karimi</category>
                <author>sina karimi</author>
                <pubDate>Fri, 02 Sep 2022 16:28:14 +0430</pubDate>
            </item>
                    <item>
                <title>کارهای جذاب با تابع سازنده Constructor در سی شارپ</title>
                <link>https://virgool.io/Rocket/%DA%A9%D8%A7%D8%B1-%D9%87%D8%A7%DB%8C-%D8%AC%D8%B0%D8%A7%D8%A8-%D8%A8%D8%A7-%D8%AA%D8%A7%D8%A8%D8%B9-%D8%B3%D8%A7%D8%B2%D9%86%D8%AF%D9%87-constructor-%D8%AF%D8%B1-%D8%B3%DB%8C-%D8%B4%D8%A7%D8%B1%D9%BE-q4wqrakxe665</link>
                <description>در حال دیدن ویدیو هایی در رابطه با زبان سی شارپ بودم که متوجه یک نکته جالب شدم که برای خودم هیجان انگیز بود و گفتم شاید برای شما نیز جالب و کاربردی باشد.در زبان سی شارپ، کلاس ها توابعی تحت عنوان سازنده (Constructor) دارند که در موقع ساخت یک نمونه (instance) از یک کلاس فراخوانی می شوند و کار هایی که برا آن ها تعریف شده باشد را انجام میدهند.در کلاس ها می توانیم چندین تابع سازنده داشته باشیم که هرکدام متناسب با پارامتر هایی که می خواهند صدا زده شوند. ماننده مثال زیر:class Person
{
    public string Name;
    public int id;
    public Person( )
    {
        Console.WriteLine(&amp;quotperson Constructor 0&amp;quot);
    }
    public Person(int id)
    {
        this.id = id;
        Console.WriteLine(&amp;quotperson Constructor 1&amp;quot);
    }
    public Person(int id, string name)
    {
        this.id = id;
        this.Name = name;
        Console.WriteLine(&amp;quotperson Constructor 2&amp;quot);
     }
}حال ما می توانیم یک نمونه از این کلاس بسازیم و متناسب با پارامتر هایی که به تابع سازنده آن ارسال میکنیم، یکی از توابع سازنده آن اجرا شوند.احتمالا خیلی از دوستان تا به اینجای مسئله را آگاهی دارند اما نکته قابل توجه و جالبی که می خواستم راجب آن با شما صحبت کنم این است که ما می توانیم این توابع سازنده را به ترتیب و پشت هم با یک دستور فرا خوانی کنیم :)به  اسکریپت زیر که تغییر یافته اسکریپت بالا با استفاده از نکته ذکر شده است توجه کنید :class Person
{
    public string Name;
    public int id;
    public Person()
    {
        Console.WriteLine(&amp;quotperson Constructor 0&amp;quot);
    }
    public Person(int id)
    : this()
    {
        this.id = id;
        Console.WriteLine(&amp;quotperson Constructor 1&amp;quot);
    }
    public Person(int id, string name)
    : this(id)
    {
        this.Name = name;
        Console.WriteLine(&amp;quotperson Constructor 2&amp;quot);
    }
}حال اگر قطعه کد زیر را در تابع Main اجرا کنیم شاهد فراخوانی تمامی توابع سازنده خواهیم بود که به ترتیب فراخوانی می شوند.  var p = new Person(5, &amp;quotsina&amp;quot);این هم از خروجی به همراه دو قطعه کد اضافی موفق و خندون باشید. :)</description>
                <category>sina karimi</category>
                <author>sina karimi</author>
                <pubDate>Fri, 26 Aug 2022 23:46:08 +0430</pubDate>
            </item>
                    <item>
                <title>الگو های طراحی در یونیتی</title>
                <link>https://virgool.io/@sinakarimi0938/%D8%A7%D9%84%DA%AF%D9%88%DB%8C-%D9%87%D8%A7%DB%8C-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D8%AF%D8%B1-%DB%8C%D9%88%D9%86%DB%8C%D8%AA%DB%8C-tvv7n80g4366</link>
                <description> Observer Pattern  in Unity در دنیای برنامه نویسی Design Pattern  های گوناگونی وجود دارند که همگی آنها به خوانایی، زیبا تر شدن  و عملکرد بهتر کد ما کمک می کنند.می خواهم راجب یکی از پرکاربرد ترین Design Pattern هایی که راجب آن بسیار صحبت میکنند با شما اطلاعاتی را به اشتراک بگذارم و با هم به بررسی یک مثال تشریحی و یک مثال عملی بپردازیم.مثال تشریحیفرض کنید که ما یک بازی ساخته اییم که داخل آن کاراکتر ما یک قدرتی به نام Rampage دارد که اگر این قدرت را بدست بیاورد دشمنان کاراکتر ما وحشت زده می شوند و نه تنها به کاراکتر حمله نمی کنند بلکه از او فرار نیز میکنند علاوه بر این ما تغییراتی در Health کاراکتر و UI بازی نیز داریم.( به عنوان مثال UI قرمز رنگ می شود)حال زمانی که Rampage اتفاق بیوفتد می بایست به تمامی دشمنان و کلاس های  Health  و UI بازی اطلاع داده بشود که این حالت اتفاق افتاده است و دچار تغییر بشوید یا به اصطلاح دیگر تابعی را در این کلاس ها صدا بزنیم تا تغییرات به آنها اعمال بشوند.برای ساخت چنین چیزی یکی از راه های پیش روی ما این هست که در تابع Update این کلاس ها در هر فریم از بازی بیایم فعال یا غیر فعال بودن Rampage را چک بکنیم تا زمانی که Rampage فعال شد کلاس های ما مطلع بشوند و شروع به فراخوانی توابع مورد نیاز بکنند.راه حل اول راه بدی نیست اما این فرآیند چک کردن Rampage که آیا فعال شده است یا خیر در تمامی فریم های بازی ما اتفاق میوفتد در صورتی که ما به چنین چیزی نیاز نداریم و در بیشتر مواقع الکی CPU را درگیر میکند.در چنین شرایطی بحث Observer Pattern به میان می آید.در  این Design Pattern ما یک آبجکت به نام Subject داریم که آبجکت های گوناگونی به آن وابسته هستند، به آن آبجکت هایی که به Subject ما وابسته هستند Observer (مشاهده گر) می گویند.نحوه عملکرد  Observer Pattern به این گونه هست که تمامی Observer ها منتظر دریافت Notification از Subject هستند تا پس از دریافت آن توابع مورد نیاز را فراخوانی کنند.در نمودار UML زیر نیز می توانید آن را مشاهده کنید.با توجه به عملکرد Observer Pattern می توان گفت Rampage بازی ما همان Subject و دشمنان، UI و Health نیز Observer می باشند.مثال عملیحال برای اینکه با این الگوی طراحی بهتر آشنا بشوید به سراغ یک مثال عملی هم میرویم.می خواهیم راجب یک بازی کوتاه صحبت بکنیم که در آن ما می توانیم  امتیازی تحت عنوان تجربه بدست بیاوریم و به واسطه آن سطح خود را داخل این بازی بالا ببریم.در این برنامه ما سه کلاس به نام های Level، Health و Debugger داریم که به شرح زیر می باشند.public class Level : MonoBehaviour
{
        [SerializeField] int pointsPerLevel = 200;
        int experiencePoints;
        IEnumerator Start()
        {
            while (true)
            {
                yield return new WaitForSeconds(0.5f);
                GetExperience(10);
            }
        }
        public void GetExperience(int points)
        {
            int levl = GetLevel();
            experiencePoints += points;
        }
        public int GetExperience()
        {
            return experiencePoints;
        }
        public int GetLevel()
        {
            return experiencePoints / pointsPerLevel;
        }
}public class Health : MonoBehaviour
{
        [SerializeField] float fullHealth = 100f;
        [SerializeField] float drainPerSecond = 2f
        float currentHealth = 0;
        int lastLevel;
        void Awake()
        {
            RestHealth();
            StartCoroutine(HealthDrain());
        }
        public float GetHealth()
        {
            return currentHealth;
        }
        void RestHealth()
        {
            currentHealth = fullHealth;
        }
        IEnumerator HealthDrain()
        {
            while (currentHealth &gt; 0)
                {
                    currentHealth -= drainPerSecond;
                    yield return new WaitForSeconds(1f);
                }
        }
}public class Debugger : MonoBehaviour
{
        IEnumerator Start()
        {        
            Level level = GetComponent&lt;Level&gt;();
            Health health = GetComponent&lt;Health&gt;();
            while (true)
            {
                yield return new WaitForSeconds(1f);
                Debug.Log($&amp;quotExp: {level.GetExperience()}, Level: {level.GetLevel()}, Health {health.GetHealth()}&amp;quot);

            }
        }
}حال می خواهیم که هروقت سطح بازی بالا رفت، میزان Health نیز reset شود.راه حل اول: در این راه کد زیر را به تابع  GetExperience اضافه میکنیم و تابع  ResetHealth را در کلاس Health هم public میکنیم.int level = GetLevel();
if (GetLevel() &gt; level)
{
    GetComponent&lt;Health&gt;().RestHealth();
}یکی از برگ ترین مشکلات راه اول این هست که ما تمام کامپوننت Health را داریم در کلاس Level دریافت میکنیم در صورتی که ما تنها به یک تابع از کلاس Health نیاز داریم.راه حل دوم: در این راه به کلاس Health یک متغیر از جنس int به نام lastLevel و توابع زیر را اضافه میکنیم.void Start()
{
    lastLevel = GetComponent&lt;Level&gt;().GetLevel();
}
void Update()
{
    int currentlevel = GetComponent&lt;Level&gt;().GetLevel();
    if (currentlevel &gt; lastLevel)
    {
        lastLevel = currentlevel;
        RestHealth();
    }
}از مشکلات بزرگ این راه نیز می توان به تابع آپدیت این کلاس اشاره کرد که حتی در فریم هایی از بازی که ما نیازی به چک کردن level نداریم هم  level را چک میکند.راه سوم با استفاده از Observer Pattern: ابتدا تمام مواردی که در راه های گذشته به کد خود اضافه کرده اییم را حذف میکنیم سپس در بالای کلاس Level  دستور زیر را وارد میکنیم.Using UnityEngine.Events;بعد از وارد کردن دستور بالا دو متغیر زیر را نیز در بالای کلاس تعریف میکنیم.UnityEvent onLevelUp;
public event Action onLevelUpAction;سپس کد های زیر را به تابع GetExperience  اضافه مکنیم.if (GetLevel() &gt; levl)
{
    onLevelUp.Invoke();
    if (onLevelUpAction != null)
    {
        onLevelUpAction();
    }
}و در نهایت نیز تابع زیر را به کلاس Health اضافه میکنیم.private void OnEnable()
{
    GetComponent&lt;Level&gt;().onLevelUpAction += RestHealth;
}با استفاده از مراحلی که در راه سوم طی کردیم ما توانستیم از Observer Pattern در بازی خود استفاده بکنیم و همانطور هم که میبینید مشکلات دو راه قبلی را ندارد، تمیز تر و کارایی بالاتری هم دارد.در مثال عملی بالا کلاس Health همان Observer  است که به کلاس Level  وابسته می باشد و کلاس Level نیز Subject است که با استفاده از Event ها و زمانی که آن Event احضار یا invoked  می شود به Observer اطلاع میدهد که الا باید onLevelUpAction را اجرا بکند، در کلاس Health نیز مشاهده میکنید که به Action مورد نظر به نام onLevelUpAction تابع ResetHealth را اضافه میکند تا زمانی که این Action در کلاس Level صدا زده میشود تابع ResetHealth اجرا بشود .امیدوارم که مثال های فوق توانسته باشند که این الگوی طراحی را برای شما به خوبی شرح بدهند و بتوانید از این الگو در بازی های خود استفاده بکنید.سینا کریمی</description>
                <category>sina karimi</category>
                <author>sina karimi</author>
                <pubDate>Fri, 12 Aug 2022 00:00:07 +0430</pubDate>
            </item>
            </channel>
</rss>