بسم الله الرحمن الرحیم
سلام. حالتون چطوره؟ ترم 6 دانشگاه بودم که ایده ساخت یه بازی دوبعدی برای یک پروژهی درسی تو ذهنم بود. اون موقع نه مدلسازی سهبعدی بلد بودم و نه تجربهی برنامه نویسی بازی با یونیتی؛ اما تا دلتون بخواد بدون اینکه دانش نظری تو زمینهی انیمیشن و طراحی داشته باشم، توی نرم افزار Anime Studio ، انیمیشن درستمیکردم و از نظر خودم شایسته دریافت اسکار بودن :)
اون موقع تجربهی مدلسازی سهبعدی رو سخت میدیدم و از وجود Blender اطلاعی نداشتم؛ از طرفی نرمافزارهایی مثل Maya یا 3dsMax واقعا شکنجهی سختی برای لب تاپ نحیف من بود. تو ذهنم داشتم که چطور میتونم تو محیط دوبعدی، یه بازی سهبعدی بزنم. طرح اولیه بازی با کاراکتراش رو زده بودم و اسماش رو افتخارِ سربازی ( Honor Of Soldiership ) گذاشته بودم. با اولین انیمیشن کوچولوی تفننی که براش زدم، کمکم تو ذهنم اومد که میشه یه کارایی کرد.
وقتی دیدم میتونم سر سرباز رو بالا پایین کنم، گفتم با صرف اندکی وقت هم می تونم کامل بچرخونم اش و از چرخش اش خروجی بگیرم. اما تجربهی اندک و رویاپردازی هام اجازه نمیداد مشکلات پروژهای که قرار بود وقت زیادی ازم بگیره، ببینم.
تو مسیر رفت و آمد با سرویس دانشگاه، یه دفترچه کوچیک داشتم که میشستم و طرح بازی رو از جهات مختلف بررسی میکردم. مثلا موقع درست کردن انیمیشنِ چرخشها، چه چالش هایی برام پیش خواهد اومد؛ یا مثلا اگه بخوام چندتا تفنگ تو بازی داشته باشم چه چالش هایی دارم و . . .
بازی دوبعدی، شوتر و چندنفره تحت شبکه LAN ، ایدهی اصلی بازی بود که در نهایت با کمالگراییهای بنده برای پیادهسازی گیمپلی اصلی بازی، بخش شبکه بازی ناقص موند. چون بیشتر مدت ساخت بازی، به یادگرفتن مبحثهای مختلف یونیتی و ساخت انیمیشنها گذشت. برای بخش شبکه بازی هم قرار بود از UNet خود یونیتی استفاده کنم.
پیاده سازی انیمیشن ها
ساخت انیمیشنها برای منی که رشتهام هنر نبود، خیلی گرون تموم شد. ماجرا با انیمیشن های سادهی cutout که قبلا می ساختم، فرق داشت. بخش زیادی از انیمیشنِ چرخشها به صورت pose to pose اجرا شد و بخش کمی به صورت frame by frame. ولی در واقع اون بخش اندکِ ماجرا بود که وقت زیادی رو گرفت.
چرخش سر و شکم، با بزرگ و کوچیک کردن پیاده سازی شد. چون تو حالت نیم رخ نسبت به جلو یا عقب، سر عریض تر دیده میشه و بدن باریک تر. برای چشم و دهن هم یه چرخش ریزی همراه با کوچیک کردن دادم. چرخش پاها هم که خیلی راحت تر بود؛ چون فقط به هم نزدیک و دور میشدن ولی در عمل به صورت چرخش دیده میشد.
بعد از طراحی تفنگ متوجه شدم که آخرسر، چرخش تفنگ مثل چرخوندن یه تیکه کاغذ دیده میشه. اما با Extrude کردن اش تو همون Anime Studio تونستم بهش حجم بدم که از حالت کاغذی بودن دربیاد. و در نهایت سخت ترین قسمت کار، درست کردن چرخش دستها هماهنگ و همراه با تفنگ بود که بعضی جاها به صورت frame by frame اجرا شد و کار زجرآوری برای من بود.
قسمتهای شیرین تر مربوط بود به طراحی و انیمیشن المانهای محیطی که تجربهی هیجان انگیزی برای من بود. درخت، چمن، بوته، چاله چولههای زمین و انیمیشن های مربوط به اونها.
پیاده سازی چرخش سرباز با ماوس در یونیتی
برای راه رفتن، نیاز به انیمیشن هایی بود که جدا از انیمیشن های شکم و سر اجرا بشن. از طرف دیگه، چون انیمیشن چرخش سر رو راحت تونسته بودم اجرا کنم، حالت های دیگه ای هم ساخته بودم. مثلا چرخش سر وقتی که داره می خنده یا وقتی که عصبانیه. بنابراین خروجی اسپرایتهای سر، شکم و پاها رو جدا کردم و در نهایت کاراکتر بازی از سه تا آبجکت سر، شکم و پاها ساخته شد.
انیمیشن چرخشها، برای بدن 360 فریم و برای سر و پاها 180 فریم بودند که برای پوشش تمام 360 درجه، flip میشدن. مکان ماوس در صفحه، زاویه ی چرخش رو می ساخت و به ازای هر زاویه، اسپرایت آبجکت رو به اسپرایت مناسب اش تغییر می دادم.
کابوس پروژه های نیمه تمام !
خدا هیچ بازی سازی رو به فکر پروژه های مسخره ی نیمه تموماش نندازه. این پروژه رو تقریبا از دو ماه پیش هوس کردم دوباره بالا آوردم و بین کارام دستی به سر و روش کشیدم. محیط به کمک Tilemap دوباره طراحی شد و برای اسپرایت های کاراکتر بازی، از SpriteAtlas استفاده کردم. ترتیب نمایش اسپرایتها رو هم درست کردم تا اگه مثلا سرباز از جلو یا پشتسرِ درخت رد میشه، ترتیب اسپرایت ها درست باشه و شاهد تو شکم همدیگه رفتن نباشیم. یه سری گرد و غبار هم با particle بهش اضافه کردم.
چالش مکانِ شلیک گلوله
از این مشکلات که رد شدم، دیدم با این وضعیت چرخش که هر لحظه نوک تفنگ جاش عوض میشه، شلیک گلوله رو کجای دلم بذارم ؟! بدین منظور :) رفتیم و یه صحنه درست کردیم با آبجکت بدن سرباز. یه کامپوننت به همراه کلاس Editorاش نوشتیم که وظیفهاش بدین شرح بود :
محل شلیک رو می تونستیم تعیین کنیم و تند تند با دکمه می رفتیم اسپرایت بعدی. محل شلیک ها تو دیکشنری کامپوننت مون میرفت و در نهایت می تونستیم داخل یه آبجکت از کلاس ScriptableObject ای برای استفاده ذخیره کنیم یا دوباره ازش لود کنیم. البته امکان این رو هم داشتیم که هر زاویه ای که دلمون می خواست تعیین و لود کنیم، یا اسپرایت قبلی هم بریم.
در کل تعیین تمام محل شلیک ها با این روش خوشبختانه فقط چیزی حدود 20 دقیقه وقت برد؛ ولی چالش هایی که تو پیاده سازی از روی کم تجربگی باهاش مواجه شدم، وقت بیشتری برد. مثلا محل شلیکها به خاطر اینکه به کمک اسکریپت Editor ای تولید شده بود، بعد از بستن و باز کردن یونیتی، همه از بین می رفتن؛ بعدا فهمیدم که باید Set as dirty شون کنم ! حالا شما صداشو درنیارید که چقدر بابتش اعصابم خورد شده بود.
معایب و چالش های این نوع پیاده سازی
خب پیاده سازی همچین جریانی مطمئنا به غیر از جالب بودنش که تنها حسناشه، یه سری معایبی داره که خدمتتون عرض میکنم.
اندازه اسپرایت هایی که خروجی گرفته بودم 600*600 پیکسل بود. برای چرخش ها هم که از 360 تا اسپرایت استفاده کرده بودم؛ پس واقعا رم زیادی مصرف می شد.
راه حل : استفاده از آرتِ پیکسلی با اسپرایت در اندازه هایی مثل 32*32 پیکسل و کم کردن تعداد اسپرایت های چرخش، راه حل مناسبیه. حتی کانسپت آرتی که بتونه محدودیت های بیشتری رو در عین زیبایی و پختگی برای کارکتر بازی اعمال کنه، خیلی می تونه تاثیر داشته باشه.
با این روش حجم کار هنری تو بازیهایی مثل سبک شمشیر که یک سری اکشن ها اجرا میشه، خیلی بالا میره. برای مثال تو همهی زاویه ها که مثلا نمیشه انیمیشنِ شمشیر زدن رو پیاده کرد.
راه حل : ساخت انیمیشن ها برای یک اکشن، می تونه تنها در 8 جهت اصلی خلاصه بشه.
خنگ بازیهای کمال گرایانه و عاشقانه !
خیلی احساس گناه و هدر رفتن وقت می کنم وقتی دارم واسه همچین چیزی پست می نویسم. موقع نوشتناش هر مقدار خواستم خلاصه تر بنویسم نشد. خود این ماجرا یه حرکت کاملا اشتباه و سوخته اس. حالا توضیح دادنش به صورت نوشتاری هم که دیگه نور علی نور هستش. البته خیلی خودم رو راضی کردم که نشینم قدم به قدم با کُد و تصویر توضیح بدم.
واقعا عالم و آدم همه متفق القول هستن که آقا جان ! بازی سه بعدی می ساختی که راحت تر بود. چه کاریه داری می کنی ؟! میشه گفت این ماجرا یه جور دیونه بازی کمال گرایانه و البته عاشقانه با صرف وقت زیاد بود.
- آه ! این حق من نبود ! من آن را عاشقانه ساخته بودم !
- خب که چی حالا ؟! چیکار کنیم ؟! آفرین !
واقعیت امر اینه که با صرف این حجم از وقت تو اون ترم، من می تونستم روی موضوعات مهمتر رشته ام تمرکز بیشتری داشته باشم و مبحثهای اولویت داری که الان نیازمندش هستم رو یاد بگیرم. با این حال خدا رو شکر می کنم.
با اینکه پروژهی سوخته ایه اما تونستم زبان تیم هنری رو، بدون حضور در تیمِ بازیسازی بهتر درک کنم.
شرحی بر تکنیک Sprite Stacking
وقتی از من دیونه ترم هست ! تکنیک Sprite Stacking مختص کسایی هستش که مثل من برای یادگیری سهبعدی ادای حال بدها رو درمیاوردن. اینطوریه که به صورت پیکسلی، هر اسپرایت رو به فاصله ی 1 پیکسل بالاتر از اسپرایتِ قبلی طراحی می کنید. خروجی که دیده میشه سهبعدی هستش ولی در واقع اسپرایتهای دوبعدی هستن که بالای همدیگه قرار گرفتن. برای اینکه بهتر متوجه شید، سرچ کنید و یه ویدیو ازش ببینید.
به خاطر اینکه مدل از اسپرایت های پیکسلی ساخته میشه، حجم کمی داره و خیلی بهتر از شیوه من یعنی اسپرایت به ازای هر زاویه است. قابلیت گرفتن خروجی به صورت voxel هم هست. اما به صورت مجموعه اسپرایت های دوبعدی هم میشه استفاده کرد. ولی واقعا چه خبرتونه ؟! طراحی مدل های گوگولی سهبعدی که خیلی راحت تره و ابتکار عمل بیشتری بهمون میده !
از اینجا کجا بریم ؟
از اینجا مختارید هر جا که می خواید برید :) فقط مثل من سمت دیونه بازی های عاشقانه نرید !
میشه ایده چرخش اسپرایت رو یه طور دیگه ای پیاده کرد مثلا :
- کاهش تعداد اسپرایت و استفاده از scale
- یا شاید هم shader
- و یا یه جور interpolate
ولی بیخیال :) باز دارم زیاد حرف می زنم.
ویدیو بازی Honor Of Sodiership : اگه خواستید ویدیو بازی رو ببینید، از این لینک استفاده کنید.
لینک بازی Honor Of Sodiership : اگه خواستید بازی رو امتحان کنید، از این لینک استفاده کنید.
سورس پروژه Honor Of Sodiership : و اگه خواستید نگاهی به پروژه بندازید یا احیانا مشارکت کنید، از این لینک.
اگه برنامهنویس هستید تونستید برام ستاره بچینید :) پروژه open source هست.
اگرهم هنرمند هستید و دوست داشتید که برای بازی آرت و انیمیشن پیکسلی بزنید، خیلی خوشحال میشم باهم گپ بزنیم. راه ارتباطی تو بیوام هستش. در پناه خدای مهربان موفق باشید !