🎮 جزوه حرفهای گودوت | جلسه اول
قدمبهقدم از نصب تا حرکت بازیکن + تحلیل خط به خط کد و آشنایی با مختصات (X , Y)
🔰 پیشنیازها: گودوت، گرهها و مفهوم مختصات
گودوت یک موتور بازیسازی مدرن و متنباز است. در این جزوه فرض میکنیم تازهکار هستید، پس همه مفاهیم را از صفر توضیح میدهیم. اولین چیزی که باید درک کنید دستگاه مختصات در صحنه ۲ بعدی است. در گودوت مانند یک صفحه شطرنج، هر نقطه دارای یک موقعیت (x,y) میباشد.
📐 محور X (افقی) :
محور X از چپ به راست حرکت میکند. مقادیر مثبت → سمت راست صفحه، مقادیر منفی → سمت چپ صفحه. فرض کنید بازیکن شما در مختصات (۰,۰) وسط صحنه است، با افزایش X به سمت راست میرود.
📐 محور Y (عمودی) :
محور Y از بالا به پایین افزایش مییابد. مقادیر مثبت → پایین صفحه، مقادیر منفی → بالای صفحه. برخلاف ریاضیات معمول، در موتورهای بازی، Y مثبت به سمت پایین است.
(Y-) بالا ↑
↓ پایین (Y+)
توصیه عملی: در گودوت یک گره Sprite2D اضافه کنید و در Inspector مقدار Position را تغییر دهید. هرچه X بیشتر شود به راست، Y بیشتر شود به پایین حرکت میکند. این پایهٔ حرکت بازیکن است.
🛠️ گام اول: ساخت پروژه و اولین صحنه (CharacterBody2D)
بعد از نصب گودوت، پروژه جدید با نام MyFirstGame بسازید. در پنجره اصلی، روی + کلیک کرده و گره CharacterBody2D را انتخاب کنید – این گره پایهی کاراکتری است که قرار است حرکت کند. نام آن را Player بگذارید. حالا دو فرزند به Player اضافه کنید: Sprite2D برای ظاهر و CollisionShape2D برای تشخیص برخورد. مراحل تصویری:
📎 اتصال اسکریپت – نوشتن اولین کد حرکت
روی گره Player راست کلیک → Attach Script. نام فایل player.gd خواهد بود. کد زیر را تایپ کنید. نگران نباشید، هر خط را با جزئیات کامل توضیح میدهیم.
extends CharacterBody2D
@export var speed = 300
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 = input_dir * speed
move_and_slide()
✍️ تحلیل خط به خط (برای مبتدیان کامل)
extends CharacterBody2D : یعنی این اسکریپت به گره CharacterBody2D متصل میشود و تمام قابلیتهای آن را به ارث میبرد. (دسترسی به velocity , move_and_slide)
@export var speed = 300 : یک متغیر به نام سرعت تعریف میکند. @export باعث میشود در بخش Inspector (پنل سمت راست) بتوانید مقدار سرعت را بدون نیاز به ویرایش کد تغییر دهید. واحد: پیکسل بر ثانیه. سرعت ۳۰۰ یعنی در هر ثانیه ۳۰۰ پیکسل جابجا شود.
func _physics_process(delta): : این تابع هر فریم فیزیک (به طور پیشفرض ۶۰ بار در ثانیه) اجرا میشود. ورودی delta یعنی زمان سپری شده از فریم قبلی، ولی اینجا مستقیماً استفاده نمیکنیم چون move_and_slide آن را درونی مدیریت میکند.
var input_dir = Vector2.ZERO : یک بردار دو بعدی میسازد با مقدار (۰,۰). این بردار جهت حرکت را ذخیره میکند.
input_dir.x = Input.get_action_strength(“ui_right”) – Input.get_action_strength(“ui_left”) : input_dir.x مربوط به حرکت افقی است. Input.get_action_strength برای کلیدهای راست و چپ مقدار ۰ یا ۱ برمیگرداند. اگر راست فشرده شود، مقدار ۱ منهای ۰ = ۱ (یعنی حرکت به راست). اگر چپ فشرده شود، ۰ منهای ۱ = -۱ (یعنی حرکت به چپ). هر دو را همزمان صفر میشود.
input_dir.y = Input.get_action_strength(“ui_down”) – Input.get_action_strength(“ui_up”) : مشابه برای محور Y: پایین مثبت و بالا منفی (زیرا در گودوت Y+ پایین است).
if input_dir.length() > 1: input_dir = input_dir.normalized() : وقتی دو کلید مورب (مثلاً راست+پایین) فشرده شود، طول بردار به ۱.۴ میرسد که باعث میشود حرکت مورب سریعتر شود. نرمال کردن یعنی طول بردار را برابر ۱ میکند تا سرعت در همه جهات یکسان بماند.
velocity = input_dir * speed : متغیر velocity (که از CharacterBody2D به ارث رسیده) را برابر حاصلضرب جهت در سرعت قرار میدهد. مثلاً اگر جهت (۱,۰) و سرعت ۳۰۰ باشد، velocity.x=300 و velocity.y=0.
move_and_slide() : این تابع جادویی باعث میشود گره براساس velocity حرکت کند و با collisionها برخورد داشته باشد (دیوارها، سقف و …). حتماً باید بعد از مقداردهی velocity فراخوانی شود.
🏃 بخش دوم: تست حرکت و اضافه کردن دوربین
صحنه Player را با Ctrl+S ذخیره کنید. حالا آن را به عنوان صحنه اصلی (Main Scene) تنظیم کنید (کلیک راست روی player.tscn → Set as Main Scene). کلید F5 را بزنید. پنجره بازی باز میشود و با کلیدهای جهتها (↑ ↓ ← →) بازیکن حرکت میکند. اگر حرکت نکرد، چک کنید که CollisionShape2D فعال باشد و بازیکن از لبه های صفحه خارج نشود. برای اینکه دوربین به دنبال بازیکن برود، یک گره Camera2D به Player اضافه کنید (Add Child Node → Camera2D). سپس در Inspector گزینه Current را فعال کنید. حالا دوربین همیشه بازیکن را دنبال میکند. تصویر زیر:
📡 سیگنالها: ارتباط بین گرهها (بدون کدنویسی پیچیده)
سیگنالها مانند یک زنگ اخبار هستند: هرگاه اتفاق خاصی بیفتد (مثل ورود بازیکن به یک منطقه)، سیگنال به بقیه اطلاع میدهد. بیایید یک “خط پایان” بسازیم که با ورود بازیکن پیام «برنده شدی» چاپ کند.
ساخت منطقه پایان (Area2D)
- در Scene اصلی (مثلاً صحنه Game) یک گره Area2D بسازید و نام FinishZone بگذارید.
- دو فرزند: CollisionShape2D (یک مستطیل سبز) و Sprite2D (یک پرچم ساده).
- روی گره Area2D کلیک کنید، سپس در تب بالای Inspector، گزینه Node را انتخاب کنید (کنار Inspector). لیست سیگنالها را ببینید، روی body_entered دوبار کلیک کنید. در پنجره باز شده، گره خود Area2D را انتخاب و تأیید کنید. کد زیر در اسکریپت FinishZone ایجاد میشود:
extends Area2D
func _on_body_entered(body):
if body.name == "Player":
print("🎉 برنده شدی! به خط پایان رسیدی.")
# میتوانید بازی را ریست کنید یا صحنه بعد را بار کنید
# get_tree().reload_current_scene()
🧪 تمرین عملی اجباری (برای تثبیت یادگیری)
🥇 تمرین ۱ – جمعآوری سکه
یک صحنه Coin بسازید (ریشه Area2D). سیگنال body_entered را متصل کنید، به ازای برخورد با Player، سکه حذف شود و در خروجی +۱ امتیاز چاپ شود. چند نسخه از Coin در صحنه کپی کنید.
⚠️ تمرین ۲ – دشمن ساده
یک Area2D به عنوان Enemy طراحی کنید. با ورود بازیکن، پیام Game Over چاپ کند و بازی را ریست کند (get_tree().reload_current_scene()).
💡 خلاصه و گام بعدی
در این جزوه یاد گرفتید که محورهای X و Y در گودوت چگونه کار میکنند (X+ راست، Y+ پایین). یک کاراکتر متحرک با کد خط به خط ساختی و معنی هر بخش از کد را فهمیدی. همچنین سیگنالها را عملاً پیادهسازی کردی. این جلسه پایه و اساس تمام بازیهای دو بعدی شما خواهد بود.
🎯 گودوت را گام به گام یاد بگیر – این جزوه به صورت رایگان برای وبسایت آموزشی طراحی شده است. برای مشاهده تصاویر واقعی، از محیط گودوت اسکرینشات بگیرید و در img placeholder قرار دهید.
