بعد از مدتها فرصتی پیدا شد تا بتونم نوشتهای به وبسایت اضافه کنم که هم مفید و هم مرتبط با موضوع واقعیت مجازی باشه. به فکرم رسید که پرداختن به موضوع برنامه نویسی سی شارپ در موتور بازی یونیتی شاید ایدهی خوبی باشه. بنابراین در این نوشته و نوشتههای بعدی سعی میکنم از طریق پروژههای ساده به این موضوع بپردازم.
اگه بخوام با یک مقدمهی کوتاه شروع کنم باید بگم که توسعه سی شارپ توسط مایکروسافت از سال ۲۰۰۲ شروع شد و تا الان ادامه داره. استفاده از اون به عنوان زبان اصلی برنامه نویسی در موتور بازی یونیتی هم از سال ۲۰۰۵ شروع میشه و تا الان بعد از حدود ۲۰ سال پروژههای بزرگ زیادی از طریق اون اجرا شدن و از آن جایی که در حال حاضر بخش زیادی از پروژههای واقعیت مجازی و افزوده با یونیتی انجام میشن اهمیت یادگیری اون رو برای افراد فعال در این حوزه بسیار پر رنگ میکنه. یک دلیل دیگه هم شاید این باشه که توسعه محتوا برای ویآر و ایآر هنوز در ابتدای راه خودش قرار داره و امکانات زیادی بدون نیاز به کد نویسی هنوز در اختیار کاربر نیست. هر چند خیلی زود این وضعیت تغییر میکنه ولی باز هم برنامه نویسی مثل یه شبح دنبال شما میاد، حالا با این شرایط بهتره یه نگاهی بهش بندازیم. شاید در ابتدا کمی به نظر پیچیده بیاد ولی به مرور زمان با تمرین و اجرای پروژههای کوچک متوجه میشید که میشه باهاش کنار اومد.
در این مطلب همانطور که از عنوانش هم تا حدی مشخصه قراره با چند خط کد ساده کاری کنیم که رنگ یه لیوان تغییر کنه مثلا قرمز بشه. برای همین کار من یه پروژهای رو آماده کردم که از طریق این لینک میتونید از گیت هاب دانلودش کنید که همین پروژهایه که اینجا میبینید. این پروژه رو هم به مرور که مطالب بیشتری میزارم آپدیت میکنم پس بهتره که نرم افزار گیت هاب دسکتاپ رو روی سیستم تون داشته باشید تا راحت بتونید تغییرات رو بگیرید. بدون دانلود پروژه هم میتونید ادامه بدید و بجای لیوان مثلا یه مکعب بسازید.
در ادامه شاید خوب باشه که کارهایی که قراره شما انجام بدید رو به ترتیب بنویسم:
۱- یک مکعب بسازید و اسمش رو هر چی دوست داشتید بزارید برای من که یه لیوانه گذاشتم Mug
۲- یه GameObject ساده هم با کلیک روی گزینه Create Empty ایجاد کنید که هر دوی این مراحل در تصویر زیر هم مشخص شده
۳- در قسمت Assets یه سکریپت سی شارپ بسازید و یه اسم قابل تشخیص براش تعیین کنید که من setColorForTestObject رو انتخاب کردم این هم در تصویر زیر مشخصه. شاید گفتن این مراحل به این شکل برای کسانی که با یونیتی کار میکنند جالب نباشه ولی خب چون مطلب اوله میخوام جوری باشه که همه بتونن دنبال کنن ولی اگه سوالی بود در قسمت زیر بپرسید.
۴- حالا با دابل کلیک کردن روی اون نرمافزار ویژوال استودیو کِمیونیتی باز میشه و کدهای زیر داخلش دیده میشن. اسمی که برای فایل سکریپت در یونیتی مشخص کرده بودیم در خط پنجم بعد از public class باید قرار گرفته باشه و در اصل تنها چیزیه که ما تعیین کردیم بقیه اون کلمات به طور پیش فرض اضافه شدن.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class setColorForTestObject : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
یه توضیح کوتاه اینکه سه خط اول که با using شروع میشن مهمن ولی در نوشتههای بعدی در موردشون توضیح میدم. اما در خط پنجم که با public class شروع میشه سکریپت ما یک کلاس تعریف کرده. کلاس چیه حالا؟ اسمش که به نظر مهم میاد پس حتما هم مهمه. بزارید یه مثال بزنم، فرض کنید شما یه قطعه زمین دارید و حالا تصمیم گرفتید داخل اون یک خونه بسازید پس میرید پیش دوست مهندس تون و بهش میگید که براتون یه نقشه بکشه و اون هم همین کار رو میکنه و برای اینکه نقشهی شما رو راحت از بین نقشههای دیگه تشخیص بده اسم شما رو هم روش میزاره. حالا شما وقتی نقشه رو نگاه میکنید میبینید که داخلش چند تا اتاق، آشپزخونه و غیره هست و از کل زمین چقدرش بنا شده و چقدرش حیاط. اولش بنظرتون خوب میاد ولی بعدش تصمیم میگیرید یه تغییراتی توش بدید مثلا تعداد اتاقها رو کم کنید و به فضای هال اضافه کنید و مهندس هم انجام میده چون مهندس خوب قصهی ماست. در مثال ما نقشه همون کلاسه که داخلش نحوهی اجرای چیزهایی مشخص شده و برای اینکه از بقیه کلاسها قابل تشخیص باشه یه اسم داره و مثل یه نقشه هر تغییری هم که خواستیم میتونیم داخلش بدید. برای اینکه محدودهاش هم مشخص باشه مثل یه قطعه زمین اول و آخرش یه علامت براکت داره مثل مثال پایین.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class setColorForTestObject : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
کلمه public هم نوع دسترسی به کلاس رو مشخص میکنه یعنی کارش اینه که دسترسی سایر کدها و خود محیط یونیتی رو به کلاس کنترل میکنه. حالا که دسترسی به کلاس از نوع public ـه یعنی همه اجازه دارن به این کلاس دسترسی داشته باشن. به اینها که شش نوع دسترسی متفاوت رو تعیین میکنن اصطلاحا Access Modifiers میگن که در نوشته دیگهای توضیح میدم.
به انتهای خط پنجم یعنی MonoBehaviour هم باید یه اشارهای کنم. در واقع این خودش هم یه کلاسه که یه کاربرد خیلی مهم داره. اگه برگردیم به مثال بالا و فرض کنید مهندس ما چند تا مهر ویژه داره که با توجه به نوع و کاربرد نقشهی نهایی یکی از مهرها رو روی اونها میزنه مثلا یه نقشهای کاربرد تجاری داره و یکی دیگه مسکونی و بعضیها هم هر دو. اینجا هم MonoBehaviour میگه که کلاس ما به اسم setColorForTestObject یه کِمپوننته. این کِمپوننت بودن یه معنی سادهش اینه که میزاره کلاس ما در محیط یونیتی به سایر موضوعات بچسبه مثلا اگه فایل سکریپت خودمون رو در محیط یونیتی بگیریم، بکشیم و بندازیم زیر یه مکعب در قسمت Inspector به انتهای اون اضافه میشه و در ضمن این که اون دو تا خط ۸ و ۱۴ که کلمههای void Start و void Update دارن رو هم همین کلاس MonoBehaviour به کلاس ما اضافه کرده.
خط ۷ هم در اصل یه توضیح در مورد چیزیه که بعدش قراره بیاد و بهش میگن کامِنت comment کلا هر خطی که با دو تا علامت // شروع بشه برنامه اون خط اجرا نمیکنه و ازش میگذره. به این علامت / هم میگن forward slash و حتما هم مهمه که دو تا پشت سر هم باشه. اگه هم یه خط کد رو نخواستید اجرا بشه میتونید دو تا از اینها رو بزارید جلوی خط.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class setColorForTestObject : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
خط هشتم با کلمه void شروع میشه که یه معنی سادش اینه که کاری که قراره اینجا انجام بشه در نهایت انجام میشه ولی مقداری رو قرار نیست بگردونه. اگه قدیمها رو یادتون باشه یا شنیده باشید یکی آشی یا چیزی میپخت و با یه کاسه میفرستاد برای همسایهش یا فامیلش اون هم یا آش رو با جاش بر میداشت یا یه چیزی میزاشت داخل کاسه به عنوان تشکر و پس میفرستاد. حالا void همونه که قرار نیست چیزی رو پس بفرسته.
حالا در مورد کلمه Start که دو تا پرانتز باز و بسته بعدش داره که گفتیم از کجا میاد، کارش اینه که یه سری چیزها رو قبل از شروع بازی تنظیم یا تعیین کنه. اینجا همون جاییه که ما قراره کد خودمون رو بزاریم چون قراره لیوان ما وقتی بازی اجرا شد رنگش مثلا قرمز باشه. در مورد آپدیت هم بگم هر چند با Update در این مرحله کاری نداریم ولی کارش اینه که کدی که داخلش قرار میگیره در طول اجرای بازی مدام اجرا کنه که بعدن در یه مثال دیگه با هم میبینیم. به این دو تا هم میگن Method که اینجا توضیح دادم.
برگردیم به شمارهها
۵- کل خطهای ۱۳ تا ۱۷ رو پاک کنید چون در این مرحله کاری با Update نداریم
۶- جلوی براکت خط ۶ کلیک کنید بعد یه اینتر بزنید تا بیاد خط ۷ و کد زیر رو اضافه کنید:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class setColorForTestObject : MonoBehaviour
{
public GameObject myTestObject;
// Start is called before the first frame update
void Start()
{
}
}
این خط یه متغیر به اسم myTestObject تعریف میکنه که دسترسیش از نوع public ـه که بالا توضیح دادم. GameObject هم یه کلاسه که اجازه میده متغیر ما به بعضی چیزهای مرتبط به مدل لیوان دسترسی داشته باشه که بعدن بتونیم تغییر بدیم.
۷- تا همین جا رو ذخیره کنید و برگردید به محیط یونیتی
۸- اول GameObject که قبلا ساختید رو از پنجره Hierarchy انتخاب کنید و بعد فایل سکریپت رو از پنجره Assets بگیرید، بکشید و بندازید در پنجره Inspector حالا سکریپت ما مانند یه کِمپوننت به زیر Transform اضافه میشه و متغییری که تعریف کرده بودیم چون از نوع public بود حالا اینجا در دسترسه و میتونیم مدل لیوان رو اینجا بهش وصل کنیم.
۹- مدل لیوان رو از قسمت Hierarchy بگیرید، بکشید و بندازید در قسمت My Test Object که خالیه یعنی همون جاییه که نوشته None (Game Object). از این جا به بعد چون اسکرپیت به مدل لیوان وصل شده ما میتونیم روی مدل تغییراتی بدیم.
۱۰- برگردید به ویژوال استودیو و دو خط زیر رو هم اضافه کنید به قسمت start دقیقا مثل نمونه زیر:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SetColorForTestObject : MonoBehaviour
{
public GameObject myTestObject;
// Start is called before the first frame update
void Start()
{
var myPubRenderer = myTestObject.GetComponent<Renderer>();
myPubRenderer.material.SetColor("_Color", Color.red);
}
}
۱۱- تغییرات رو ذخیره کنید و برگردید محیط یونیتی و دکمه play رو بزنید بعد از اجرا شدن، شما لیوان رو باید قرمز ببینید اگه نه مراحل رو یه بار مرور کنید ببینید کدوم قسمت رو انجام ندادید.
یه توضیح در مورد این دو خط. در خط اول که ابتدا با var شروع میشه و بعدش یه اسم دلخواه ما در اصل داریم یه متغیر تعریف میکنیم خوبیش هم اینه که نیازی نیست بگیم نوعش چیه و خود کامپایلر زحمتش رو میکشه. حالا قراره چیزی به این متغیر نسبت بدیم که بعد از مساوی میاد. هر چی که بعد از مساوی اومده اینجا شبیه به یه آدرسه که اجازه دسترسی شما رو به جایی میده چون آدرسش رو دارید.
var myPubRenderer = myTestObject.GetComponent<Renderer>();
myTestObject ما که به مدل لیوان وصله و حالا GetComponent که یه متده (توصیح متد رو اینجا بخونید) اجازه دسترسی ما رو به کِمپوننت renderer میده که اگه این کِمپوننت رو در یونیتی نگاه کنید میبینید که کنترل زیادی روی لیوان داره مثل کنترل متریال و سایه. خب تا اینجا دسترسی ما به متریال لیوان برقرار شد.
حالا در خط بعدی با دسترسی که به متغیر myPubRenderer نسبت دادم می تونم متریال لیوان رو با SetColor که یه متده تغییر بدم، در این متد رنگ اصلی متریال با Color_ کنترل میشه و مقدار دهی به آن با Color انجام میشه که در این جا به red تغییر میکنه. این رو هم بگم که در یه متریال ممکنه رنگهای دیگهای هم باشه مثل رنگ قسمت Emission که اگه بخواید اون رو تغییر بدید به جای Color_ در این خط EmissionColor_ رو وارد کنید.
myPubRenderer.material.SetColor("_Color", Color.red);
در ضمن برای این کد فرقی نمیکنه متریال چی باشه و اگه متریال رو تغییر بدید و اون متریال رنگ اصلی داشته باشه این کد همچنان کار میکنه مثلا اگه متریال standard رو در قسمت Shader به Unlit > Color تغییر بدم چون این متریال هم رنگ اصلی داره تغییر رنگ انجام میشه.
در آخر این رو هم اضافه کنم که ممکنه این سوال پیش بیاد که نمیشه بدون اینکه مدل لیوان رو به یه متغیر در GameObject وصل کنیم مستقیم سکریپت رو بندازیم زیر مدل لیوان و کار کنه. جوابش اینه که بله میشه با کد زیر. ولی این رو در نظر بگیرید که روش بالا رو در آینده بیشتر استفاده خواهید کرد.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SetColorForTestObject : MonoBehaviour
{
Renderer myTestObject;
// Start is called before the first frame update
void Start()
{
myTestObject = GetComponent<Renderer>();
myTestObject.material.color = Color.red;
}
}
این نوشته رو هم که در مورد تغییر رنگ همین مدل بوسیله یه دکمه ست رو بخونید.