دوره آموزش یونیتی مقدماتی (بخش چهارم)
آخرین به روزرسانی در 21/10/2022
در بخش چهارم آموزش مقدماتی یونیتی به مباحث تخریب کننده ها ، Coroutine ها در یونیتی ، کوروتین ها در یونیتی ، کنسول در یونیتی و شروع کار با صداها در یونیتی خواهیم پرداخت.
پیش نیاز این سری از دوره های آموزشی تسلط به زبان برنامه نویسی سی شارپ می باشد.
تخریب کننده ها
از بین بردن GameObjects به اندازه نمونه سازی که در بخش سوم به آن پرداختیم مهم است.
در این بخش آموزشی یاد می گیریم که چگونه GameObject ها را از بین ببریم.( درواقع ما در بخش سوم آموزش مقدماتی یونیتی به شما اهمیت از بین بردن گیم آبجکت ها را آموختیم که از سنگین شدن بازی و درگیر کردن بی دلیل حافظه ی رم جلوگیری می کند.)
خبر خوب این است که ، از بین بردن GameObjects به همان اندازه ی ایجاد آنها آسان است.
شما به سادگی به یک رفرنس (مرجع) برای شیئی که باید از بین برود نیاز دارید و متد () Destroy را با این مرجع به عنوان پارامتر فراخوانی کنید.
حالا بیایید سعی کنیم 5 شش ضلعی بسازیم که با فشردن یک کلید اختصاص داده شده خود را از بین ببرند.
اجازه دهید در ابتدا یک اسکریپت جدید به نام HexagonDestroyer بسازیم و آن را در ویژوال استودیو باز کنیم.
ما با ایجاد یک متغیر عمومی KeyCode شروع خواهیم کرد.
یک KeyCode برای تعیین یک کلید در صفحه کلید استاندارد استفاده می شود و کلاس Input در متدهای خود از آن استفاده می کند.
با public کردن این متغیر، همانطور که قبلاً با Rigidbody و Prefabs انجام دادیم، میتوانیم آن را از طریق ویرایشگر در دسترس قرار دهیم.
هنگامی که متغیر عمومی می شود، ما نیازی به مقادیری مانند “KeyCode.A” در کد نداریم.
در واقع کد را می توان با هر تعداد که ما بخواهیم انعطاف پذیر کرد.
public class HexagonDestroyer : MonoBehaviour {
public KeyCode keyToDestroy;
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(keyToDestroy)) {
Destroy (gameObject);
}
}
}
مشاهده کنید که چگونه از متغیری به نام “gameObject” (g کوچک، O بزرگ) در این متد استفاده کردیم.
این متغیر gameObject جدید (از نوع GameObject ) برای اشاره به GameObject که این اسکریپت به آن پیوست شده است استفاده می شود.
اگر این اسکریپت را روی چندین شیء ضمیمه کنید، هر زمان که این متغیر درگیر شود، همه آنها یکسان واکنش نشان خواهند داد.
با این حال، این دو را با یکدیگر اشتباه نگیرید.
GameObject با G و O بزرگ کلاسی است که تمام گیم آبجکت ها را در بر می گیرد و متدهای استانداردی مانند Instantiate، Destroy و متدهایی را برای واکشی کامپوننت ها ارائه می دهد.
gameObject با g کوچک و O بزرگ نمونه خاصی از GameObject است که برای اشاره به GameObject که این اسکریپت در حال حاضر به آن پیوست شده است استفاده می شود.
اجازه دهید اکنون کد خود را کامپایل کرده و به Unity برگردیم.
اکنون، یک sprite شش ضلعی جدید ایجاد می کنیم و اسکریپت خود را به آن متصل می کنیم.
سپس روی gameObject در hierarchy کلیک راست کرده و Duplicate را انتخاب کنید.
یک اسپرایت جدید در hierarchy ایجاد می شود.
برای تغییر موقعیت باید از ابزار Move استفاده کنید.
(این مراحل را برای ایجاد شش ضلعی مشابه تکرار کنید.)
روی هر یک از شش ضلعی ها کلیک کنید و به کامپوننت های اسکریپت آنها نگاه کنید.
اکنون می توانید کلیدهای جداگانه را طوری تنظیم کنید که یک GameObject با فشار دادن آن کلید، خود را از بین ببرد.
به عنوان مثال، اجازه دهید 5 شش ضلعی ایجاد کنیم، و آنها را طوری تنظیم کنیم که با فشار دادن کلیدهای A، S، D، F و G از بین بروند.
شما می توانید یک کلید را روی چندین شش ضلعی تنظیم کنید و با فشار دادن کلید همه آنها به طور همزمان خود را از بین می برند.
این نمونه ای از استفاده از مرجع gameObject است که می توانید از آن برای ارجاع به اشیاء جداگانه با استفاده از اسکریپت بدون نیاز به تنظیم جداگانه آنها استفاده کنید.
کلید یکسان را می توان روی چندین شش ضلعی تنظیم کرد و با فشار دادن کلید، همه آنها به طور همزمان خود را از بین می برند.
درک این نکته مهم است که از بین بردن GameObject به این معنی نیست که یک شیء شکسته یا منفجر می شود.
از بین بردن یک شی به سادگی (و بلافاصله) تا آنجا که به بازی (و کد آن) مربوط می شود، وجود آن متوقف می شود.
پیوندهای این شی و مراجع آن اکنون شکسته شده اند و تلاش برای دسترسی یا استفاده از هر یک از آنها معمولاً منجر به خطا و خرابی برنامه می شود.
Coroutines
Coroutine ها در یونیتی از مفیدترین ابزارها هنگام ساخت بازی در Unity هستند.
اجازه دهید قطعه کد نشان داده شده در زیر ما را بیشتر با مفهوم coroutines آشنا کند.
IEnumerator MyCoroutineMethod() {
// Your code here…
yield return null;
}
به طور کلی، اگر تابعی را در Unity (یا C#) فراخوانی کنید، تابع از ابتدا تا انتها اجرا می شود.
این همان چیزی است که تا آنجا که به کد شما مربوط می شود، رفتار “نرمال” را در نظر می گیرید.
با این حال، گاهی اوقات میخواهیم عمداً سرعت یک تابع را کاهش دهیم یا زمان اجرای آن را به تعویق بیندازیم.
یک کوروتین دقیقاً قادر به انجام اینکار است :
یک کوروتین تابعی است که قادر است فرآیند خود را زمان بندی کند و یا همچنین به طور کامل آن را متوقف کند.
اجازه دهید مثالی را برای درک نحوه عملکرد یک کوروتین در نظر بگیریم.
فرض کنید می خواهیم مربعی بسازیم که در فواصل 1 ثانیه ای رنگ آن بین قرمز و آبی تغییر کند.
برای شروع، ما یک sprite ایجاد می کنیم.
سپس یک اسکریپت جدید ایجاد کنید و نام آن را ColorChanger بگذارید.
در این اسکریپت، ما به Sprite Renderer Sprite اشاره می کنیم.
با این حال، ما از روش دیگری برای دریافت کامپوننت استفاده خواهیم کرد.
به جای کشیدن و رها کردن کامپوننت در یک اسلات مانند آنچه تاکنون انجام دادهایم، از کد میخواهیم تا خود مؤلفه را شناسایی کند.
این کار از طریق متد GetComponent انجام میشود که اولین مؤلفه منطبقی را که شناسایی میکند، برمیگرداند.
از آنجایی که ما فقط از یک Sprite Renderer برای هر شی استفاده می کنیم، می توانیم از این روش برای شناسایی خودکار و دریافت یک مرجع در هر بار استفاده کنیم.
به یاد داشته باشید که اسپرایت رندر مسئول این است که اسپرایت را واقعاً روی صفحه نمایش دهد.
اسپرایت رندر دارای ویژگی رنگی است که بر رنگ سراسری اسپرایت تأثیر می گذارد.
این مقداری است که باید اصلاح شود.
public کردن مقادیر Color به ما این امکان را می دهد که آنها را از طریق ویرایشگر در برنامه انتخاب رنگ پیش فرض سیستم عامل شما انتخاب کنیم.
private SpriteRenderer sr;
public Color color1;
public Color color2;
void Start () {
sr = GetComponent();
StartCoroutine(ChangeColor());
}
IEnumerator ChangeColor() {
while (true) {
if (sr.color == color1)
sr.color = color2;
else
sr.color = color1;
yield return new WaitForSeconds(3);
}
}
اکنون، تابع کوروتین خود را در یک حلقه while ایجاد می کنیم.
برای ایجاد یک کوروتین در سی شارپ، به سادگی متدی ایجاد می کنیم که IEnumerator را برمی گرداند.
همچنین به یک yield return statement نیاز دارد.
yield return statement یک ویژگی خاص است.
و در واقع همان چیزی است که در واقع به یونیتی می گوید که اسکریپت را متوقف کند و در فریم بعدی ادامه دهد.
چندین راه وجود دارد که می توان از آنها برای بازدهی استفاده کرد.
یکی از آنها ایجاد یک نمونه از کلاس WaitForSeconds است.
این باعث میشود که کوروتین قبل از ادامه، برای مقدار مشخصی از ثانیههای ریل تایم منتظر بماند.
اجازه دهید کد خود را کامپایل کرده و به Unity برگردیم.
ما به سادگی رنگ های متناوب خود را انتخاب می کنیم و گزینه ی play را می زنیم.
اکنون شی ما باید بین دو رنگ در فواصل 3 ثانیه جابجا شود.
می توانید فاصله را به یک متغیر public تبدیل کنید و فرکانس تغییرات رنگ را نیز تنظیم کنید.
کوروتین ها در یونیتی به طور گسترده برای روش های زمان بندی شده استفاده می شوند، مانند روشی که ما انجام دادیم. انواع روش های WaitForX کاربردهای خاص خود را دارند. کوروتین ها در یونیتی همچنین برای اجرای فرآیندهای ” on the side ” استفاده می شوند که در حالی که بازی به طور ریل تایم اجرا می شود به تنهایی اجرا می شوند.
به عنوان مثال، برای بارگذاری بخش های خارج از صفحه نمایش در یک لول بزرگ در حالی که پلیر از یک نقطه شروع می شود، مفید است.
کنسول در یونیتی
کنسول جایی است که ما خروجی های Developer را از آن می خوانیم.
این خروجی ها را می توان برای آزمایش سریع بیت های کد بدون نیاز به ارائه عملکرد اضافی برای آزمایش استفاده کرد.
سه نوع پیام وجود دارد که در کنسول پیش فرض ظاهر می شوند. این پیام ها می توانند با اکثریت استانداردهای یک کامپایلر مرتبط باشند :
- خطاها (Errors)
- هشدارها (Warnings)
- پیام ها (Messages)
خطاها (Errors)
خطاها مشکلاتی هستند که از اجرای کد جلوگیری می کنند.
هشدارها (Warnings)
هشدارها مسائلی هستند که اجرای کد شما را متوقف نمی کنند، اما ممکن است در طول زمان اجرا مشکلاتی ایجاد کنند.
پیام ها (Messages)
پیام ها خروجی هایی هستند که پیامی را به کاربر منتقل می کنند.
ما حتی میتوانیم از کنسول پیامها، هشدارها و خطاهای خود را خروجی دهیم.
برای این کار از کلاس Debug استفاده می کنیم.
کلاس Debug بخشی از MonoBehaviour است که روش هایی را برای نوشتن پیام ها در کنسول به ما می دهد، کاملا مشابه نحوه ایجاد پیام های خروجی معمولی در برنامه های starter.
میتوانید Console را در تب labelled بالای بخش Assets پیدا کنید.
خروجی های کنسول تنها برای برنامه نویسی و برنامه نویسان مفید است نه برای کاربران.
به عنوان مثال اجازه دهید سعی کنیم یک پیام ساده در کنسول بنویسیم.
هنگامی که کلید Space را فشار داده اید، به ما اطلاع می دهد.
برای این کار از متد Log استفاده می کنیم که یک Object را به عنوان پارامتر می گیرد و از یک رشته در آن استفاده می کنیم.
می توانید با یک اسکریپت جدید شروع کنید یا یک اسکریپتی که از قبل موجود است را تغییر دهید.
void Update() {
if (Input.GetKeyDown(KeyCode.Space))
Debug.Log(“Space key was pressed!”);
}
با ذخیره، کامپایل و اجرای این کد (البته با پیوست کردن آن به یک GameObject)، سعی کنید کلید اسپیس را بزنید.
توجه داشته باشید که پیام در پایین ویرایشگر نمایش داده می شود.
اگر روی تب Console کلیک کنید، پیام خود را چاپ شده خواهید دید.
به همین ترتیب، میتوانید با استفاده از متد LogWarning اخطارها و با متد LogError خطاها را خروجی بگیرید.
همانطور که در ادامه خواهید دید، این پروسه برای آزمایش بیت های کوچک کد بدون نیاز به پیاده سازی آنها مفید خواهند بود.
صداها در یونیتی
صداگذاری در بازی مبحث بسیار پر اهمیتی می باشد و بسیاری از بازی ها موفقیت خود را مدیون موسیقی های فوق العاده ی درون بازی هستند.
صداگذاری در بازی به دسته بندی های زیادی تقسیم می شود ، از صداهای محیط تا موسیقی متن و صدای آبجکت ها.
به علت اهمیت این موضوع ما قبلا در مقاله ای به صورت کاملا تخصصی به مبحث صداگذاری در بازی پرداخته ایم.
در زندگی واقعی، چیزهای زیادی بر نحوه درک شما از صدا تأثیر می گذارد.
سرعت جسم، در چه نوع سناریویی قرار دارد و از چه جهتی می آید.
تعدادی از عوامل وجود دارد که می تواند بار غیر ضروری را بر روی موتور ما ایجاد کند.
در عوض، ما سعی میکنیم ایدهای درباره نحوه عملکرد صدایمان در بازی ایجاد کنیم و بر اساس آن پروسه ی ساخت را شروع کنیم.
در یونیتی، ما کامپوننت های اختصاصی برای درک و پخش صدا را در دسترس داریم.
این کامپوننت ها با یکدیگر کار می کنند تا یک سیستم صوتی باورپذیر را ایجاد کنند که برای بازی احساس طبیعی می کند.
Unity مجموعهای از ابزارها و افکتهای مفید مانند Reverb، افکت داپلر، میکس و افکتهای Real Time و … را در اختیار ما قرار میدهد.
در بخش های بعدی با این موارد آشنا خواهیم شد.
کامپوننت صدا
در این قسمت با 3 کامپوننت اصلی مرتبط با صدا در یونیتی آشنا می شویم.
AudioSource
کامپوننت AudioSource یک کامپوننت اصلی و پر اهمیت است که برای پخش صدا به GameObject متصل می شود.
زمانیکه از طریق میکسر، از طریق کد یا به طور پیش فرض، توسط کاربر فراخوانده می شود، یک AudioClip را پخش می کند.
AudioClip به سادگی یک فایل صوتی است که در یک AudioSource بارگذاری می شود.
این می تواند هر فایل صوتی استانداردی باشد، مانند mp3، .wav و … AudioClip یک کامپوننت درون خود نیز دارد.
AudioListener
AudioListener قطعه ای است که به تمام صدای پخش شده در صحنه گوش می دهد و آن را به بلندگوهای رایانه منتقل می کند.
در واقع این کامپوننت مثل گوش های بازی عمل می کند.
تمام صدایی که می شنوید در منظر موقعیت این AudioListener است.
فقط یک AudioListener باید در یک صحنه باشد تا به درستی کار کند.
به طور پیش فرض، main camera (دوربین اصلی) به آن متصل است.
Listener هیچ ویژگی آشکاری ندارد که طراح بخواهد به آن اهمیت دهد.
Audio Filters
خروجی یک منبع صوتی یا ورودی یک AudioListener را می توان با کمک فیلترهای صوتی تغییر داد.
اینها کامپوننت های خاصی هستند که می توانند reverb ، chorus ، filtering و … را در صدا تغییر دهند.
هر فیلتر خاص به عنوان کامپوننت خاص خود با مقادیر در معرض نمایش قرار می گیرد تا نحوه صدای آن را تغییر دهید.
پلی کردن یک صدا
بیایید سعی کنیم دکمه ای بسازیم که با کلیک روی آن صدا پخش شود.
برای شروع، یک Circle sprite ایجاد می کنیم و رنگ آن را قرمز می کنیم.
حال، اجازه دهید یک منبع صوتی را به این sprite متصل کنیم.
برای اینکه شیء بتواند صدایی را پخش کند، باید صدا را به آن بدهیم.
یک جلوه ی صوتی به دلخواه انتخاب و دانلود کنید.
پس از دانلود آن را به قسمت Assets بکشید.
وقتی Unity این Assets را به عنوان فایل صوتی وارد می کند، به طور خودکار به AudioClip تبدیل می شود.
بنابراین، میتوانید این کلیپ صوتی را از Assets مستقیماً روی اسلات Audio Clip در منبع صوتی Sprite ما بکشید.
پس از اینکه کلیپ صدا را از Assets مستقیماً روی اسلات Audio Clip در منبع صوتی Sprite ما کشیدید، به یاد داشته باشید که “Play on Awake” را در ویژگی های منبع صوتی حذف کنید.
انجام ندادن این کار باعث می شود که صدا در لحظه شروع بازی پخش شود.
حالا قصد داریم وارد کد خود شویم. یک اسکریپت جدید به نام “BellSound” ایجاد کنید و آن را باز کنید.
از آنجایی که منبع صوتی ما از طریق کد کنترل می شود، می خواهیم ابتدا یک مرجع به آن دریافت کنیم.
مانند قبل از متد GetComponent استفاده خواهیم کرد.
public class BellSound : MonoBehaviour {
AudioSource mySource;
// Use this for initialization
void Start () {
mySource = GetComponent();
}
اکنون، باید متدی را برای تشخیص شی مورد کلیک تنظیم کنیم.
MonoBehaviour فقط متدی را که برای آن نیاز داریم به ما می دهد که OnMouseDown نام دارد.
این متد زمانی فراخوانی می شود که ماوس در محدوده برخورد دهنده (کالوژن) آن gameObject کلیک کند.
از آنجایی که ما هنوز یک برخورد دهنده را به دکمه خود وصل نکرده ایم، اکنون این کار را انجام می دهیم.
ما برای این مورد نیازی به Rigidbody نخواهیم داشت.
همچنین نیازی نیست که با کد به این برخورد دهنده دسترسی داشته باشیم.
فقط باید وجود داشته باشد تا متد کار کند.
اجازه دهید متد را آزمایش کنیم و ببینیم که آیا کار می کند یا خیر.
کد زیر را در اسکریپت خود بنویسید و آن را به دکمه وصل کنید.
void OnMouseDown() {
Debug.Log(“Clicked!”);
}
پس از ذخیره اسکریپت و پیوست آن، بازی را پلی کنید.
با کلیک بر روی دکمه باید یک پیام در کنسول ایجاد شود.
اکنون یک قدم با پخش صدا فاصله دارید.
و تنها کاری که باید انجام دهید این است که متد Play را در نمونه منبع صوتی فراخوانی کنید.
void OnMouseDown() {
mySource.Play();
}
اسکریپت خود را ذخیره کنید و آن را در بازی اجرا کنید. روی دکمه کلیک کنید، و باید صدای پخش را بشنوید.
مهرشاد شادان مهر
مدرس سئو ، طراح سایت ، انیماتور
قهرمان زندگی شما در چند سال آینده ی شما می باشد