📚 راهنمای جامع و کامل موتور بازی‌سازی گودوت (Godot 4) --- بخش ۱: معرفی گودوت گودوت یک موتور بازی‌سازی رایگان، متن‌باز و قدرتمند برای ساخت بازی‌های دوبعدی و سه‌بعدی است. این موتور تحت لیسانس MIT منتشر شده و کاملاً رایگان است. مزایای گودوت: · کاملاً رایگان و بدون حق امتیاز · حجم کم (کمتر از ۱۰۰ مگابایت) · پشتیبانی از ویندوز، مک، لینوکس، اندروید، iOS و وب · زبان اختصاصی GDScript شبیه به پایتون · پشتیبانی از C# و C++ --- بخش ۲: مفاهیم بنیادین ۲-۱: Node (گره) Node واحد پایه در گودوت است. هر شیء در بازی یک Node است. انواع Nodeهای مهم: · Node2D: برای بازی‌های دوبعدی · Node3D: برای بازی‌های سه‌بعدی · Control: برای رابط کاربری · CharacterBody2D/3D: برای شخصیت‌های قابل کنترل · RigidBody2D/3D: برای اشیاء فیزیکی · StaticBody2D/3D: برای موانع ثابت · Area2D/3D: برای تشخیص برخورد ۲-۲: Scene (صحنه) صحنه مجموعه‌ای از Nodeهاست که با هم یک واحد قابل استفاده مجدد می‌سازند. مثال صحنه‌ها: · صحنه اصلی بازی (Main) · صحنه شخصیت بازیکن (Player) · صحنه دشمن (Enemy) · صحنه منو (Menu) ۲-۳: SceneTree (درخت صحنه) SceneTree ساختار سلسله‌مراتبی همه صحنه‌های در حال اجرا را مدیریت می‌کند. توابع مهم SceneTree: · get_tree().change_scene_to_file() - تغییر صحنه · get_tree().quit() - خروج از بازی · get_tree().paused - توقف بازی ۲-۴: Signal (سیگنال) سیگنال‌ها روشی برای ارسال پیام بین Nodeها هستند. مثال سیگنال‌های داخلی: · area_entered - وقتی چیزی وارد Area شود · timeout - وقتی تایمر تمام شود · body_entered - وقتی جسمی وارد شود --- بخش ۳: شروع کار با GDScript ۳-۱: ساختار اولیه یک اسکریپت ``` extends Node @export var speed: int = 200 @export var health: int = 100 func _ready(): print("سلام، گودوت!") health = 150 func _process(delta): pass func _physics_process(delta): pass ``` ۳-۲: متغیرها و نوع‌های داده ``` # متغیرها var player_name = "احمد" # رشته var score = 0 # عدد صحیح var health = 100.5 # عدد اعشاری var is_alive = true # بولی var position = Vector2(0, 0) # وکتور دو بعدی var position3d = Vector3(0, 0, 0) # وکتور سه بعدی # ثابت‌ها const MAX_HEALTH = 200 const GAME_NAME = "ماجراجو" # آرایه‌ها var items = ["شمشیر", "سپر", "معجون"] var numbers = [1, 2, 3, 4, 5] # دیکشنری var player_data = { "name": "احمد", "level": 5, "health": 100 } ``` ۳-۳: عملگرها ``` # ریاضی var a = 10 var b = 3 var result = a + b # 13 result = a - b # 7 result = a * b # 30 result = a / b # 3.333 result = a % b # 1 # مقایسه‌ای if a == b: # مساوی print("برابر") if a != b: # نامساوی print("نامساوی") if a > b: # بزرگتر print("بزرگتر") if a < b: # کوچکتر print("کوچکتر") # منطقی if a > 5 and b < 5: # و print("شرط ۱") if a > 5 or b < 5: # یا print("شرط ۲") if not a == 5: # نقیض print("شرط ۳") ``` ۳-۴: شرط‌ها ``` var health = 50 if health > 80: print("سلامت کامل") elif health > 50: print("سلامت متوسط") elif health > 20: print("سلامت پایین") else: print("در خطر!") ``` ۳-۵: حلقه‌ها ``` # حلقه for for i in range(5): print(i) # 0,1,2,3,4 for item in items: print(item) # حلقه while var i = 0 while i < 5: print(i) i += 1 ``` ۳-۶: توابع ``` func add_numbers(a: int, b: int) -> int: return a + b func greet_player(name: String) -> String: return "سلام " + name func update_health(new_health: int) -> void: health = new_health if health <= 0: die() func die(): print("بازیکن مرد!") ``` --- بخش ۴: پروژه عملی - بازی Dodge the Creeps ۴-۱: ایجاد پروژه جدید ۱. گودوت را باز کنید ۲. روی "New Project" کلیک کنید ۳. نام پروژه را "DodgeTheCreeps" بگذارید ۴. مسیر ذخیره را انتخاب کنید ۵. روی "Create Folder" و سپس "Create & Edit" کلیک کنید ۴-۲: ساخت صحنه اصلی (Main) مرحله ۱: صحنه اصلی را ایجاد کنید ``` - روی "Scene" کلیک کنید - "Node" را انتخاب کنید - نام آن را "Main" بگذارید - روی "Save" کلیک کنید ``` مرحله ۲: Nodeهای زیر را اضافه کنید ``` Main (Node) ├── Timer ├── ScoreLabel (Label) ├── Player (CharacterBody2D) └── MobSpawner (Timer) ``` ۴-۳: ساخت بازیکن (Player) مرحله ۱: صحنه Player را ایجاد کنید ``` - روی "Scene" کلیک کنید - "CharacterBody2D" را انتخاب کنید - نام را "Player" بگذارید - Save کنید ``` مرحله ۲: Nodeهای زیر را اضافه کنید ``` Player (CharacterBody2D) ├── CollisionShape2D └── AnimatedSprite2D ``` مرحله ۳: اسکریپت Player ``` extends CharacterBody2D @export var speed: float = 400.0 @export var max_health: int = 3 @export var invincible_time: float = 1.0 var current_health: int var is_invincible: bool = false var can_shoot: bool = true var screen_size: Vector2 signal health_changed(new_health: int) signal died() func _ready(): current_health = max_health screen_size = get_viewport_rect().size hide() position = screen_size / 2 show() func _process(delta): if Input.is_action_just_pressed("shoot"): shoot() func _physics_process(delta): var velocity = Vector2.ZERO if Input.is_action_pressed("move_right"): velocity.x += 1 if Input.is_action_pressed("move_left"): velocity.x -= 1 if Input.is_action_pressed("move_down"): velocity.y += 1 if Input.is_action_pressed("move_up"): velocity.y -= 1 if velocity.length() > 0: velocity = velocity.normalized() * speed $AnimatedSprite2D.play() else: $AnimatedSprite2D.stop() position += velocity * delta position = position.clamp(Vector2.ZERO, screen_size) move_and_slide() func shoot(): if not can_shoot: return can_shoot = false # ایجاد گلوله var bullet = preload("res://bullet.tscn").instantiate() get_parent().add_child(bullet) bullet.position = position bullet.direction = Vector2(0, -1) get_tree().create_timer(0.5).timeout.connect(_on_shoot_cooldown) func _on_shoot_cooldown(): can_shoot = true func take_damage(damage: int = 1): if is_invincible: return current_health -= damage health_changed.emit(current_health) if current_health <= 0: die() else: become_invincible() func become_invincible(): is_invincible = true $AnimatedSprite2D.modulate = Color(1, 0.5, 0.5) get_tree().create_timer(invincible_time).timeout.connect(_on_invincibility_end) func _on_invincibility_end(): is_invincible = false $AnimatedSprite2D.modulate = Color(1, 1, 1) func die(): hide() died.emit() get_tree().change_scene_to_file("res://game_over.tscn") ``` ۴-۴: ساخت دشمن (Mob) مرحله ۱: صحنه Mob را ایجاد کنید ``` - "RigidBody2D" را انتخاب کنید - نام "Mob" بگذارید - Save کنید ``` مرحله ۲: Nodeهای زیر را اضافه کنید ``` Mob (RigidBody2D) ├── CollisionShape2D ├── AnimatedSprite2D └── VisibleOnScreenNotifier2D ``` مرحله ۳: اسکریپت Mob ``` extends RigidBody2D @export var min_speed: float = 150.0 @export var max_speed: float = 350.0 signal squashed func _ready(): var mob_types = $AnimatedSprite2D.sprite_frames.get_animation_names() $AnimatedSprite2D.play(mob_types[randi() % mob_types.size()]) var direction = Vector2(randf_range(-1, 1), randf_range(-1, 1)).normalized() var speed = randf_range(min_speed, max_speed) linear_velocity = direction * speed $VisibleOnScreenNotifier2D.screen_exited.connect(_on_screen_exited) func _on_screen_exited(): queue_free() func _on_body_entered(body): if body is Player: body.take_damage() queue_free() elif body is Bullet: squashed.emit() queue_free() ``` ۴-۵: اسکریپت Main ``` extends Node @export var mob_scene: PackedScene @export var score_increment: int = 10 var score: int = 0 var enemies_killed: int = 0 var game_over: bool = false signal score_updated(new_score: int) func _ready(): randomize() var player = $Player player.health_changed.connect(_on_player_health_changed) player.died.connect(_on_player_died) $ScoreLabel.text = "امتیاز: 0" $MobSpawner.timeout.connect(_on_mob_spawner_timeout) $MobSpawner.start() func _process(delta): if game_over: return func _on_mob_spawner_timeout(): if game_over: return var mob = mob_scene.instantiate() add_child(mob) var spawn_position = Vector2(randf_range(50, get_viewport_rect().size.x - 50), -50) mob.position = spawn_position var spawn_direction = Vector2(randf_range(-0.5, 0.5), randf_range(0.5, 1)).normalized() var spawn_speed = randf_range(150, 350) mob.linear_velocity = spawn_direction * spawn_speed mob.squashed.connect(_on_mob_squashed.bind(mob)) mob.tree_exited.connect(_on_mob_exited.bind(mob)) func _on_mob_squashed(mob): enemies_killed += 1 score += score_increment score_updated.emit(score) $ScoreLabel.text = "امتیاز: " + str(score) func _on_mob_exited(mob): if mob.linear_velocity.y > 0: return func _on_player_health_changed(new_health: int): # بروزرسانی نمایش سلامت pass func _on_player_died(): game_over = true $MobSpawner.stop() # نمایش صفحه پایان بازی get_tree().change_scene_to_file("res://game_over.tscn") func restart_game(): get_tree().reload_current_scene() ``` ۴-۶: سیستم امتیازدهی و سلامت اسکریپت HealthBar: ``` extends Control @export var health_icon: Texture2D @export var empty_icon: Texture2D @export var max_hearts: int = 3 var current_hearts: int = 3 func _ready(): update_health(current_hearts) func update_health(health: int): current_hearts = health for i in range(max_hearts): var icon = get_node("Heart" + str(i + 1)) if i < health: icon.texture = health_icon else: icon.texture = empty_icon ``` ۴-۷: منو و صفحه پایان اسکریپت Menu: ``` extends Control func _ready(): $StartButton.pressed.connect(_on_start_pressed) $QuitButton.pressed.connect(_on_quit_pressed) func _on_start_pressed(): get_tree().change_scene_to_file("res://main.tscn") func _on_quit_pressed(): get_tree().quit() ``` اسکریپت GameOver: ``` extends Control @export var final_score: int = 0 func _ready(): $ScoreLabel.text = "امتیاز نهایی: " + str(final_score) $RestartButton.pressed.connect(_on_restart_pressed) $MenuButton.pressed.connect(_on_menu_pressed) func _on_restart_pressed(): get_tree().change_scene_to_file("res://main.tscn") func _on_menu_pressed(): get_tree().change_scene_to_file("res://menu.tscn") ``` --- بخش ۵: مفاهیم پیشرفته ۵-۱: انیمیشن با AnimationPlayer مراحل ساخت انیمیشن: ``` ۱. Node AnimationPlayer را اضافه کنید ۲. تایم‌لاین را باز کنید ۳. روی "Animation" کلیک و "New" را انتخاب کنید ۴. نام انیمیشن را بگذارید (مثلاً "run") ۵. یک کلید (Key) در موقعیت ۰ ثانیه اضافه کنید ۶. یک کلید در موقعیت ۱ ثانیه اضافه کنید ۷. بین دو کلید، تغییرات را اعمال کنید ۸. انیمیشن را اجرا کنید ``` اجرای انیمیشن با کد: ``` $AnimationPlayer.play("run") $AnimationPlayer.stop() $AnimationPlayer.pause() $AnimationPlayer.seek(0.5) $AnimationPlayer.animation_finished.connect(_on_animation_finished) ``` ۵-۲: سیستم اتوماتای محدود (State Machine) ``` extends Node var current_state = null var previous_state = null var states = {} func _ready(): for child in get_children(): if child is Node: states[child.name] = child child.active = false func transition_to(state_name: String, data: Dictionary = {}): if current_state: current_state.exit() previous_state = current_state current_state = states.get(state_name) if current_state: current_state.enter(data) ``` ۵-۳: اینترفیس‌ها و کلاس‌های سفارشی ایجاد کلاس سفارشی: ``` class_name PlayerStats extends Resource @export var max_health: int = 100 @export var speed: float = 200.0 @export var damage: int = 10 @export var defense: int = 0 ``` استفاده از اینترفیس: ``` extends Area2D func interact(): # منطق تعامل pass ``` ۵-۴: سیستم ذخیره‌سازی (Save/Load) ذخیره بازی: ``` func save_game(): var save_data = { "player_position": player.position, "player_health": player.current_health, "score": score, "level": current_level } var file = FileAccess.open("user://savegame.dat", FileAccess.WRITE) var json_string = JSON.stringify(save_data) file.store_line(json_string) file.close() ``` بارگذاری بازی: ``` func load_game(): var file = FileAccess.open("user://savegame.dat", FileAccess.READ) if file: var json_string = file.get_line() var save_data = JSON.parse_string(json_string) if save_data: player.position = save_data["player_position"] player.current_health = save_data["player_health"] score = save_data["score"] current_level = save_data["level"] file.close() ``` ۵-۵: سیستم پارتیکل (Particles) نوع Particle System: ``` GPUParticles2D: برای جلوه‌های دوبعدی GPUParticles3D: برای جلوه‌های سه‌بعدی CPUParticles2D: نسخه سبک‌تر برای دوبعدی ``` تنظیمات پارتیکل: ``` - Amount: تعداد ذرات - Lifetime: عمر هر ذره - Speed: سرعت ذرات - Gravity: جاذبه - Direction: جهت حرکت - Spread: پراکندگی - Size: اندازه - Color: رنگ - Texture: بافت ``` ۵-۶: شیدرها (Shaders) شیدر ساده: ``` shader_type canvas_item; uniform float glow_intensity : hint_range(0, 10) = 1.0; uniform vec4 glow_color : source_color = vec4(1.0, 0.5, 0.0, 1.0); void fragment() { vec4 color = texture(TEXTURE, UV); float glow = color.r * glow_intensity; COLOR = color + glow * glow_color; } ``` ۵-۷: سیستم AI (Pathfinding) NavigationAgent2D: ``` extends CharacterBody2D @export var navigation_agent: NavigationAgent2D func _physics_process(delta): if navigation_agent.is_navigation_finished(): return var next_position = navigation_agent.get_next_path_position() var direction = (next_position - position).normalized() velocity = direction * speed move_and_slide() ``` ۵-۸: تایمرها ``` var timer = Timer.new() timer.wait_time = 2.0 timer.timeout.connect(_on_timer_timeout) add_child(timer) timer.start() # روش دیگر get_tree().create_timer(2.0).timeout.connect(_on_timer_timeout) ``` ۵-۹: ورودی و کلیدها تنظیمات ورودی در Project Settings: ``` - Input Map را باز کنید - Action جدید بسازید (مثلاً "jump") - کلید مورد نظر را به آن اختصاص دهید ``` استفاده از ورودی: ``` if Input.is_action_just_pressed("jump"): velocity.y = jump_strength if Input.is_action_pressed("move_right"): velocity.x = speed ``` ۵-۱۰: چندرسانه‌ای صوت: ``` var audio_player = AudioStreamPlayer2D.new() audio_player.stream = load("res://sound.wav") add_child(audio_player) audio_player.play() ``` موزیک پس‌زمینه: ``` func play_music(): var music = AudioStreamPlayer.new() music.stream = load("res://music.mp3") music.volume_db = -10 music.bus = "Music" add_child(music) music.play() ``` --- بخش ۶: بهینه‌سازی و رفع اشکال ۶-۱: دیباگ استفاده از print: ``` print("پیام ساده") print(health) print("سلامت: ", health) print("موقعیت: ", position) ``` استفاده از assert: ``` assert(health > 0, "سلامت نباید کمتر از صفر باشد") ``` استفاده از push_error: ``` if health < 0: push_error("سلامت منفی: ", health) ``` ۶-۲: پروفایلینگ ``` - Debug → Performance - مشاهده استفاده از CPU - مشاهده تعداد فریم - مشاهده استفاده از حافظه ``` ۶-۳: بهینه‌سازی عملکرد ``` - استفاده از Object Pooling برای اشیاء زیاد - کاهش Nodeهای اضافی - استفاده از Physics Layers برای برخوردها - کاهش بافت‌های بزرگ - استفاده از LOD (Level of Detail) - بهینه‌سازی Shaderها ``` ۶-۴: مدیریت حافظه ``` # حذف دستی object.queue_free() # بررسی وجود if is_instance_valid(object): object.do_something() # مدیریت سیگنال‌ها signal.disconnect(method) ``` --- بخش ۷: منابع و یادگیری بیشتر ۷-۱: مستندات رسمی · آموزش گام‌به‌گام: اسناد رسمی گودوت (بخش Getting Started) · راهنمای ارجاع: مستندات کامل API · کتاب آشپزی: حل مسائل رایج با کدهای آماده ۷-۲: ویدئوهای آموزشی · کانال رسمی گودوت: آموزش‌های ویدئویی · GDQuest: دوره‌های حرفه‌ای · HeartBeast: پروژه‌های عملی · KidsCanCode: آموزش مبتدی تا پیشرفته ۷-۳: انجمن‌ها · Discord رسمی گودوت: پشتیبانی فوری · Reddit r/godot: بحث و تبادل نظر · Stack Overflow: سوال و جواب تخصصی · گروه‌های تلگرام فارسی: آموزش به زبان فارسی ۷-۴: پروژه‌های منبع‌باز · Godot Demo Projects: پروژه‌های نمونه رسمی · Awesome Godot: لیست پروژه‌های برتر · GitHub: جستجوی پروژه‌های گودوت --- بخش ۸: جدول زمانی یادگیری (برنامه پیشنهادی) هفته ۱-۲: مبانی · آشنایی با محیط گودوت · یادگیری GDScript پایه · ساخت اولین پروژه (Move a character) هفته ۳-۴: مفاهیم اصلی · ساخت صحنه‌ها و Nodeها · کار با سیگنال‌ها · پروژه: بازی Dodge the Creeps هفته ۵-۶: فیزیک و انیمیشن · کار با PhysicsBodyها · ساخت انیمیشن با AnimationPlayer · پروژه: بازی پلتفرمر ساده هفته ۷-۸: UI و تعامل · ساخت منو و رابط کاربری · سیستم ورودی پیشرفته · پروژه: بازی با چند سطح هفته ۹-۱۰: پیشرفته · AI و Pathfinding · سیستم ذخیره‌سازی · پروژه: بازی کامل با داستان هفته ۱۱-۱۲: تخصصی · بهینه‌سازی · انتشار بازی · پروژه نهایی --- بخش ۹: نکات طلایی ۹-۱: نکات کدنویسی ۱. نام‌گذاری مناسب: · کلاس‌ها: PascalCase (PlayerController) · متغیرها: snake_case (player_health) · ثابت‌ها: UPPER_SNAKE_CASE (MAX_SPEED) ۲. کامنت‌گذاری: · توضیح کدهای پیچیده · توضیح دلیل نوشتن کد ۳. ساختار مناسب: · جدا کردن کدها به توابع کوچک · استفاده از کلاس‌ها برای سازماندهی ۹-۲: نکات طراحی بازی ۱. مقیاس‌پذیری: · طراحی با رزولوشن‌های مختلف · استفاده از Anchors برای UI ۲. تجربه کاربری: · پاسخ‌گویی سریع · بازخورد بصری مناسب · راهنمایی کاربر ۳. آزمون و تست: · تست مداوم بازی · گرفتن بازخورد از بازیکنان · رفع باگ‌ها ۹-۳: نکات انتشار ۱. بهینه‌سازی نهایی: · فشرده‌سازی بافت‌ها · کاهش حجم فایل · تست روی دستگاه‌های مختلف ۲. تبلیغات: · ساخت تریلر · حضور در شبکه‌های اجتماعی · انتشار در پلتفرم‌های معروف --- جمع‌بندی گودوت یک موتور بازی‌سازی قدرتمند و رایگان است که با یادگیری اصولی آن می‌توانید بازی‌های حرفه‌ای بسازید. این راهنما تمام مباحث از مبتدی تا پیشرفته را پوشش می‌دهد. قدم‌های بعدی: ۱. نصب گودوت ۲. شروع با پروژه Dodge the Creeps ۳. شرکت در انجمن‌های گودوت ۴. ساخت پروژه شخصی خودتان موفق باشید! 🎮 --- آخرین بروزرسانی: ۲۰۲۶ این راهنما بر اساس مستندات رسمی گودوت نسخه ۴ تدوین شده است.