🎮 جلسه اول: قدم به دنیای ساخت بازی
به اولین جلسه از دورهی جامع موتور بازیسازی گودوت (Godot 4) خوش آمدید! این جزوه طوری طراحی شده که بدون پیشزمینه برنامهنویسی یا بازیسازی، بتوانید اولین قدمهای محکم را بردارید. در طول دو ساعت، یاد میگیرید که گودوت چیست، چطور یک صحنه بسازید، یک کاراکتر ساده حرکت دهید و با مفاهیم گرهها، سیگنالها و اسکریپت نویسی آشنا شوید. هر بخش به شکلی روان و عملی توضیح داده شده تا پس از مطالعه بتوانید یک بازی ساده اما واقعی بسازید. بیایید شروع کنیم!
🔰 بخش اول: گودوت را بهتر بشناسیم
۱-۱ گودوت چیست و چرا انقلابی در ساخت بازی ایجاد کرده؟
گودوت یک موتور بازی متنباز، رایگان و فوقالعاده قدرتمند است که بدون نیاز به پرداخت حق امتیاز، به شما اجازه میدهد بازیهای دو بعدی و سه بعدی بسازید. حجم نصب آن کمتر از ۱۰۰ مگابایت است اما قابلیتهای حرفهای مانند انیمیشن، فیزیک، نورپردازی و اسکریپتنویسی را دارد. زبان اصلی آن GDScript نام دارد که شباهت زیادی به پایتون داشته و یادگیری آن برای تازهکاران بسیار شیرین است. اگر به دنبال یک ابزار سبک، سریع و بدون هزینه هستید، گودوت بهترین انتخاب است.
بازیهای موفقی مانند Brotato، Cassette Beasts و Cruelty Squad با گودوت ساخته شدهاند و جامعه کاربری آن روزبهروز در حال رشد است. در این جلسه روی شاخه پایدار Godot 4.2 یا بالاتر تمرکز میکنیم. پس بیایید نصب را شروع کنیم.
به سایت رسمی godotengine.org بروید و نسخه استاندارد (Standard) را برای سیستمعامل خود دانلود کنید. نیازی به نصب .NET ندارید مگر اینکه قصد برنامهنویسی سیشارپ داشته باشید. فایل اجرایی را باز کنید، در پنجره Project Manager گزینه «New Project» را بزنید. نام پروژه را MyFirstGame بگذارید و یک پوشه خالی برای آن انتخاب کنید. سپس دکمه «Create & Edit» را بزنید. محیط اصلی گودوت را همین الان میبینید: پنج بخش اصلی شامل صحنه (Scene)، نمایش (Viewport)، فایل سیستم، بازرس (Inspector) و خروجی (Output). نگران نباشید، قدم به قدم با همه آشنا میشوید.
۱-۲ مفهوم گره (Node) و صحنه (Scene) – الفبای گودوت
در گودوت هر چیزی که در بازی میبینید (کاراکتر، دشمن، سکه، دوربین، موسیقی) یک «گره» است. گرهها مانند جعبههای کوچکی هستند که میتوانند ویژگیهایی مثل موقعیت، شکل، رفتار فیزیکی یا اسکریپت داشته باشند. یک صحنه در حقیقت درختی از گرههاست که با هم یک موجودیت بازی را میسازند. برای مثال یک بازیکن شامل گرههای Sprite2D (نمایش ظاهر)، CollisionShape2D (برخورد) و اسکریپت حرکت میشود. وقتی این درخت گره را ذخیره میکنید، یک «صحنه» با پسوند .tscn دارید.
برای ساخت اولین صحنه، روی دکمه «+» (یا Scene → New Scene) کلیک کنید و گره CharacterBody2D را انتخاب کنید. سپس نام آن را Player بگذارید. حالا یاد میگیرید که به این بازیکن ظاهر و برخورد بدهید.
🏃♂️ بخش دوم: تولد اولین کاراکتر متحرک
۲-۱ اضافه کردن Sprite و Collision (شکل و فیزیک)
روی گره Player کلیک راست کرده و Add Child Node را بزنید. در لیست جستجو عبارت Sprite2D را وارد کنید. اکنون یک گره Sprite2D زیرمجموعه Player دارید. حالا در بخش بازرس (Inspector) سمت راست، برای ویژگی Texture یک تصویر انتخاب کنید. اگر تصویری ندارید، نگران نباشید! میتوانید به جای آن از ColorRect استفاده کنید یا به سادگی روی دکمه پایین کادر Texture کلیک کرده و New RectangleShape را بزنید؟ نه بهتر است یک شکل رنگی ساده بسازید. در پنل پایین «FileSystem» کلیک راست کرده → New → Resource → New Resource و نوع RectangleShape2D را انتخاب کنید. اما روش آسانتر: برای ظاهر از Sprite2D و یک مربع رنگی میتوانید از گره ColorRect استفاده نکنید، پیشنهاد من این است: به جای Sprite2D میتوان از Sprite2D با Texture خودکار استفاده کرد؟ بیایید ساده بگوییم: به کمک بازرس، در قسمت Texture، گزینه «New Image» را انتخاب کرده و یک تصویر ۳۲×۳۲ رنگی (مثلاً آبی) بسازید. اما برای سرعت تمرین، یک تصویر ساده از فایل سیستم بکشید. اگر هیچ فایلی ندارید، گودوت به شما اجازه میدهد یک NoiseTexture ساده بسازید. در کل فرض کنید یک شکل شبیه جعبه قرمز اضافه کردهاید. حالا اندازه آن را با مقیاس (Scale) در بازرس تنظیم کنید.
سپس دوباره روی Player کلیک راست کرده و گره CollisionShape2D را اضافه کنید. در بازرس، کنار گزینه Shape، روی [empty] کلیک کرده و New RectangleShape2D را بزنید. ابعاد مستطیل برخورد را حدوداً ۴۰ در ۴۰ پیکسل تنظیم کنید تا با ظاهر بازیکن هماهنگ باشد. حتماً ذخیره کنید (Ctrl+S) و نام صحنه را player.tscn بگذارید.
۲-۲ نوشتن اولین اسکریپت (کد حرکت با کیبورد)
روی گره Player کلیک راست کرده و Attach Script را انتخاب کنید. نام پیشفرض player.gd را قبول کرده و دکمه ایجاد را بزنید. حالا ویرایشگر کد باز میشود. کد زیر را خط به خط تایپ کنید (ما هر خط را توضیح میدهیم):
extends CharacterBody2D
# سرعت حرکت بر حسب پیکسل در ثانیه
@export var speed = 300
# تابع physics_process هر فریم فیزیک (۶۰ بار در ثانیه) اجرا میشود
func _physics_process(delta):
# بردار جهت حرکت (صفر اولیه)
var input_dir = Vector2.ZERO
# گرفتن ورودی از صفحه کلید (کلیدهای پیشفرض جهتها)
input_dir.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
input_dir.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
# نرمال کردن برای جلوگیری از حرکت مورب سریعتر
if input_dir.length() > 1:
input_dir = input_dir.normalized()
# اعمال سرعت به بردار velocity
velocity = input_dir * speed
# حرکت و مدیریت برخورد
move_and_slide()
حالا Ctrl+S را بزنید و اسکریپت را ذخیره کنید. توضیح: @export باعث میشود در بازرس بتوانید مقدار سرعت را بدون ویرایش کد تغییر دهید. تابع _physics_process با فریم فیزیک هماهنگ است و حرکت صافی دارد. تابع move_and_slide() باعث میشود بازیکن به دیوارها برخورد کند و لغزنده نباشد.
۲-۳ تست بازی و اجرا
حالا باید صحنه Player را به عنوان صحنه اصلی معرفی کنید. در پنل FileSystem روی فایل player.tscn راست کلیک کرده و گزینه Set as Main Scene را بزنید. سپس کلید F5 را فشار دهید یا روی دکمه پلی (▶) در گوشه بالا سمت راست کلیک کنید. پنجره بازی باز میشود و با فشردن کلیدهای جهتها (بالا، پایین، چپ، راست) خواهید دید که جعبه آبی/قرمز شما حرکت میکند. اگر حرکت نکرد، مطمئن شوید CollisionShape2D فعال است (چشمک کنار آن خاموش نباشد) و گره اصلی همان CharacterBody2D باشد. تبریک میگویم! شما اولین بازی متحرک خود را ساختید.
📡 بخش سوم: سیگنالها – قلب ارتباط در گودوت
۳-۱ سیگنال چیست؟ واکنش به رویدادها
در بازیسازی، خیلی وقتها نیاز داریم وقتی دو شیء به هم برخورد کردند یا دکمهای فشرده شد، اتفاقی بیفتد. سیگنالها مانند پیامکهایی هستند که گرهها برای یکدیگر میفرستند. برای مثال گره Area2D میتواند سیگنال body_entered بفرستد تا بفهمیم بازیکن وارد منطقه شده است. بیایید یک «خط پایان» بسازیم:
- به صحنه اصلی (که میتواند یک صحنه خالی جدید به نام Game باشد) برگردید. یک گره Area2D اضافه کنید و نامش را FinishFlag بگذارید.
- زیر Area2D یک گره CollisionShape2D با شکل مستطیل و اندازه حدود ۶۰×۶۰ اضافه کنید.
- همچنین یک Sprite2D به عنوان ظاهر (یک ستاره ساده یا مستطیل سبز) به آن بدهید.
- روی گره Area2D کلیک کنید، به تب Node در کنار Inspector بروید و دنبال سیگنال body_entered بگردید. روی آن دوبار کلیک کنید. یک پنجره باز میشود که از شما میخواهد تابع را به کدام گره متصل کنید. همان Area2D را انتخاب کنید و نام تابع را تأیید کنید.
- کد زیر در اسکریپت FinishFlag نوشته میشود:
extends Area2D
func _on_body_entered(body):
if body.name == "Player": # اگر جسم وارد شده بازیکن باشد
print("🏆 برنده شدی! به خط پایان رسیدی.")
# در آینده میتوانید صحنه بعدی را بارگذاری کنید
get_tree().reload_current_scene() # برای تمرین بازی رو ریست میکند
حالا اگر بازیکن به منطقه برخورد کند، پیام در خروجی چاپ میشود. این قدرت سیگنالهاست: بدون وابستگی زیاد، گرهها با هم ارتباط برقرار میکنند.
۳-۲ تفاوت گرههای اصلی (بدنها)
برای اینکه در آینده گیج نشوید، بهتر است تفاوت این گرههای پایه را بدانید:
- CharacterBody2D: مناسب برای کاراکترهایی که شما حرکت آنها را با کد کنترل میکنید (بازیکن، دشمن ساده).
- RigidBody2D: تحت تأثیر فیزیک موتور است (مانند توپها، اشیای قابل پرتاب).
- Area2D: تشخیص ورود، منطقههای آسیب یا جمعآوری آیتم. خودش گرانش و برخورد فیزیکی ندارد.
- StaticBody2D: برای موانع ثابت مثل دیوارها و زمین.
✍️ بخش چهارم: تمرین کلاسی – سکه و امتیاز
زمان آن رسیده که دست به کار شوید. تمرین زیر را انجام دهید تا مفاهیم کاملاً در ذهنتان تثبیت شود:
- یک صحنه جدید به نام Coin بسازید. گره ریشه از نوع Area2D باشد.
- زیر آن یک Sprite2D (ظاهر سکه، مثلاً یک دایره زرد) و CollisionShape2D قرار دهید.
- اسکریپت به Coin بچسبانید و سیگنال body_entered را متصل کنید.
- در تابع سیگنال، بررسی کنید اگر body.name == “Player” باشد، با دستور queue_free() سکه حذف شود و print(“+1 امتیاز”) را چاپ کنید.
- چند نسخه از سکه را در صحنه اصلی بازی (که Player در آن قرار دارد) کپی کنید و بچینید.
- بازی را اجرا کنید. هر بار به سکه برخورد کنید، ناپدید شده و پیام امتیاز میآید.
این کار شما را با منطق جمعآوری آیتم آشنا میکند. در جلسات بعدی یاد میگیریم که امتیاز را روی صفحه نمایش دهیم و افکتهای جذاب اضافه کنیم.
📌 جمعبندی و گامهای بعدی
در این جلسه دو ساعته، یاد گرفتید که گودوت چیست، یک صحنه CharacterBody2D ساختید، اسکریپت حرکت نوشتید، با سیگنالها آشنا شدید و یک آیتم جمعآوریکننده طراحی کردید. این پایههای اصلی برای ساخت هر بازی ۲D هستند. به خودتان افتخار کنید!
تکلیف جلسه اول: یک «دشمن ساده» طراحی کنید که با برخورد به بازیکن، پیام «Game Over» در خروجی چاپ کند. میتوانید از Area2D یا StaticBody2D استفاده کنید و سیگنال body_entered را مشابه سکه پیادهسازی کنید، با این تفاوت که بازیکن حذف نمیشود، فقط هشدار بدهید. برای چالش بیشتر، میتوانید با دستور get_tree().reload_current_scene() بازی را پس از برخورد مجدداً راهاندازی کنید.
