دستورات اجرای کد

متدهای Invoke

متدهای Invoke متدهایی هستند که می‌توانند متد دیگری را در زمان دلخواه توسعه‌دهنده فراخوانی کنند.

متد Invoke

متد Invoke می‌تواند پس از طی یک بازه‌ی زمانی متد دیگری را فراخوانی کند. برای استفاده از Invoke ابتدا متد جدیدی (در همان اسکریپت) تعریف کرده و کدهای موردنظر را درون آن می‌نویسیم. سپس از دستور زیر استفاده می‌کنیم:

Invoke(“MyMethod”, 5.0f);

پارامتر اول: نام متد / پارامتر دوم: مدت زمان تاخیر از زمان اجرای Invoke

نکته

اگر از Invoke در متدهایی که چندین بار تکرار می‌شوند (مثل Update) استفاده شود، دستورات درون متد MyMethod پس از طی شدن زمان Invoke مطابق با تعداد دفعات اجرای متدی که درون آن قرار دارند (مثل Update) اجرا خواهند شد.

متد InvokeRepeating

متد InvokeRepeating می‌تواند متد دیگری را در بازه‌های زمانی منظم فراخوانی کند. برای مثال در صورتی که قصد داشته باشیم یک تفنگ هر 5 ثانیه یک بار شلیک کند کد شلیک را درون متدی به نام Shoot (در همان اسکریپت) نوشته و آن را توسط InvokeRepeating فراخوانی می‌کنیم:

InvokeRepeating(“Shoot”, 2.0f, 5.0f);

پارامتر اول: نام متد / پارامتر دوم: مدت زمان اولین تاخیر / پارامتر سوم: بازه‌های زمانی وقفه‌های بعدی

نکته

متد InvokeRepeating در توابعی که تنها یک بار اجرا می‌شوند به درستی عمل می‌کند. یعنی برای مثال اگر این متد در Update اجرا شود پس از گذشت مدت زمان اولین تاخیر متد Shoot متناوباً شروع به اجرا خواهد کرد و عملکرد صحیحی نخواهد داشت.

استفاده از متدهای Invoke دارای معایب زیادی است. از جمله عدم امکان متوقف کردن آن‌ها به صورت جداگانه و به تفکیک نام (برای متوقف کردن تمام Invokeهای در حال اجرا از قطعه کد CancelInvoke() استفاده می‌کنیم) و همچنین خطاهایی که در نکته‌ها بررسی کردیم. به همین منظور در توسعه‌ی بازی معمولاً از متدهای Invoke استفاده نکرده و به ساختارهایی مانند Coroutineها روی می‌آوریم.

Coroutineها

در صورتی که در اسکریپت‌های MonoBehaviour قصد داشته باشیم کدی را در خارج از چرخه‌ی عمر گیم آبجکت اجرا کنیم از Coroutine استفاده می‌کنیم. Coroutine نوعی متد است که این امکان را فراهم می‌کند تا چندین کد به صورت همزمان اجرا شوند (مالتی تسکینگ).

برای مثال فرض کنید در یک صحنه از بازی قصد داریم با وارد شدن پلیر به درون collider قلمروی دشمن، گیم آبجکت دشمن شروع به حرکت کرده و به پلیر نزدیک شود. برای پیاده‌سازی این قابلیت باید کامپوننت Transform گیم آبجکت دشمن را دریافت کرده و با دسترسی مستقیم به پراپرتی localPosition اقدام به جابجایی آن به سمت پلیر کنیم. بدیهی است که این عمل چند ثانیه به طول می‌انجامد و اجرایی شدن آن نیازمند اجرای کد مربوطه در چند صد فریم می‌باشد. در حالی که متد OnTriggerEnter2D مربوط به قلمرو تنها یک بار اجرا می‌شود. برای حل این مشکل کد مربوط به حرکت دشمن را در یک Coroutine تعریف کرده و در متد نفوذ آن را صدا می‌زنیم. در این حالت محتویات درون Coroutine مستقل از کدهای MonoBehaviour و در یک نخ مجزا شروع به اجرا می‌کنند.

همچنین در صورتی که بخواهیم یک کد پس از مدت زمان معینی اجرا شود از Coroutine استفاده می‌کنیم.

ساختار یک Coroutine

ساختار یک Coroutine به صورت زیر است:

IEnumerator myCoroutine()
{
//Coroutine codes
yield return null;
}

خروجی متدهای Coroutine از نوع IEnumerator بوده و با استفاده از کلمه‌ی کلیدی yield که درون بلوک نوشته می‌شود می‌توان اجرای دستورات را در آن نقطه تعلیق کرد.

دستورات تعلیق

دستورات تعلیق دستوراتی هستند که با ایجاد وقفه‌های مناسب کارکرد دلخواه را در بازی پیاده‌سازی کرده و یا باعث جلوگیری از کرش کردن بازی می‌شوند. دستورات تعلیق مهم عبارتند از:

yield return null;

تعلیق اجرای دستورات نخ در این نقطه تا پایان فریم

yield return new WaitForSeconds(2.0f);

تعلیق اجرای دستورات نخ در این نقطه به مدت 2 ثانیه

کاربرد دستورات تعلیق

  1. تعلیق تا پایان فریم (yield return null):

    در بسیاری از موارد، قصد داریم که دستورات درون Coroutine بیش از یک بار اجرا شوند (مثل متد Update). به این منظور از یک حلقه‌ی تکرار همیشه صحیح مثل while(true) استفاده می‌کنیم. اما از آن‌جایی که در حالت عادی یک حلقه‌ی تکرار همیشه صحیح موجب کرش کردن برنامه می‌شود با نوشتن yield return null درون حلقه به بازی این امکان را می‌دهیم تا پس از اجرای بلوک حلقه به فریم بعدی رفته و سپس بلوک حلقه دوباره اجرا شود.

    IEnumerator myCoroutine()
    {
    while (true)
    {
    Debug.Log("Hello");
    yield return null;
    }
    }
  2. تعلیق به مدت زمان معین (yield return new WaitForSeconds):

    برای این که یک کد در بازی پس از مدت زمانی معین اجرا شود می‌توان از Coroutine و دستور yield return new WaitForSeconds استفاده نمود. به عنوان مثال صدا زدن این Coroutine باعث می‌شود که پس از 5 ثانیه پیام Hello در پنجره‌ی کنسول ادیتور نمایش داده شود:

    IEnumerator myCoroutine()
    {
    yield return new WaitForSeconds(5.0f);
    Debug.Log("Hello");
    }

دستورات مدیریت Coroutineها

در نهایت با استفاده از این دستورات می‌توان نسبت به فراخوانی و متوقف کردن Coroutineها اقدام نمود:

StartCoroutine(MyCoroutine());

شروع اجرای MyCoroutine

StopCoroutine(MyCoroutine());

متوقف کردن MyCoroutine

StopAllCoroutines();

متوقف کردن تمام Coroutineهای در حال اجرا

تمرین

تمرین: کارکرد این Coroutine را توضیح دهید و در صورت لزوم آن را اجرا کنید.

IEnumerator myCoroutine()
{
while (true)
{
Debug.Log("Hello");
yield return new WaitForSeconds(2.0f);
}
}