Orvix Engine

Oyun Geliştirme Rehberi: Sıfırdan Uzmanlığa

Hoş Geldiniz, Geleceğin Oyun Geliştiricisi!

Bu eşsiz rehber, Orvix Engine'in muazzam gücünü derinlemesine keşfetmen ve kendi dijital evrenlerini yaratmaya başlaman için tasarlandı. Sıfırdan bir fikirle başlayıp onu işlevsel, optimize edilmiş ve yayınlanmaya hazır bir oyuna dönüştürme yolculuğunda, seni adım adım ileri taşıyacağız. Her bir bölüm, temel prensiplerden en ileri seviye tekniklere kadar uzanan kapsamlı bir bilgi akışı sunuyor. Kemerini bağla, çünkü oyun geliştirme sanatının zirvesine çıkmaya hazırlanıyorsun!

Eğitime Başla: İlk Kod Satırın!

Bu İleri Düzey Eğitimde Neler Öğreneceksin?

Orvix Engine'in karmaşık dünyasını basitleştirerek, seni gerçek bir oyun geliştirme uzmanı yapacak şu anahtar konulara odaklanacağız:



Bölüm 1: Oyun Geliştirmeye Başlangıç | Temel Kavramlara Derin Dalış

Oyun geliştirme maceranıza hoş geldiniz! Orvix Engine, Düğümler (Nodes) ve Sahneler (Scenes) etrafında dönen modüler bir mimariye sahiptir. Bu bölüm, bu temel yapı taşlarını ve editör arayüzünü derinlemesine anlamanızı sağlayacak.

1.1 Proje Yönetimi ve Yapılandırma Stratejileri

Orvix Engine'i ilk başlattığınızda, sizi güçlü bir Proje Yöneticisi karşılar. Burası, tüm oyun projelerinizin merkezi komuta odasıdır. Projelerinizi verimli bir şekilde düzenlemek, farklı versiyonlar arasında geçiş yapmak ve yeni fikirler için alan açmak için Proje Yöneticisi'ni ustaca kullanmak, geliştirme sürecinizin temelini oluşturur.

Yeni Bir Proje Oluşturma: İlk Adımınız

Proje Yöneticisi'ndeki parlak "Oluştur Yeni Proje" (Create New Project) butonuna tıklayarak yeni bir maceraya atılabilirsiniz. Bu aşamada, projenize sadece akılda kalıcı bir isim vermekle kalmayacak, aynı zamanda tüm oyun varlıklarınızın, kod dosyalarınızın ve sahne tanımlarınızın güvenle saklanacağı stratejik bir disk konumu seçmelisiniz. Projenin adını belirlerken, gelecekteki genişlemeleri ve olası modüler yapıları düşünerek kısa, açıklayıcı ve benzersiz bir isim seçmek akıllıca olacaktır.

Orvix Proje Dosya Yapısı: Bir Mimarın Gözünden

Her Orvix projesi, titizlikle organize edilmiş, mantıksal bir dosya yapısına sahiptir. Bu yapı, hem küçük prototipler hem de milyonlarca satır kodu barındıran devasa AAA oyunları için ölçeklenebilirliği sağlar. En kritik ve sıkça karşılaşacağınız dosya türleri şunlardır:

1.2 Oyun Dünyasının Temel Bileşenleri: Düğümler (Nodes) ve Sahneler (Scenes)

Orvix Engine'in temel felsefesi, her şeyin küçük, yeniden kullanılabilir ve hiyerarşik nesneler etrafında dönmesidir. Bu nesneleri "Düğüm" (Node), bu düğümlerin mantıksal olarak bir araya gelmiş halini ise "Sahne" (Scene) olarak adlandırırız. Bu yapı, oyununuzun karmaşıklığını yönetmek için inanılmaz bir esneklik sunar.

Düğüm (Node) Nedir? Detaylı Bakış

Düğüm, Orvix Engine'deki en küçük, atomik yapı taşıdır. Ancak bu basit tanım, onun ne kadar güçlü olduğunu tam olarak yansıtmaz. Bir düğüm, oyununuzdaki belirli bir görevi veya işlevi yerine getiren herhangi bir objedir. Örneğin:

Her düğüm, kendi benzersiz özellik setine (konum, rotasyon, boyut, renk vb.) ve kendi özel davranışlarını tanımlayabileceğiniz bir betiğe (`.ovx` dosyası) sahip olabilir. Düğümler, birbiriyle ilişkili bir "ağaç" yapısında düzenlenir. Bir düğümün altına başka düğümler ekleyerek hiyerarşiler oluşturursunuz. Örneğin, bir karakter düğümünün altına bir kamera düğümü eklediğinizde, kamera karakterle birlikte hareket eder.

Sahne (Scene) Nedir? Modüler Geliştirmenin Kalbi

Bir sahne, bir veya daha fazla düğümün mantıksal olarak bir araya getirilmiş, hiyerarşik bir koleksiyonudur. Bir sahne, oyununuzun belirli bir "parçasını" temsil eder:

Sahnelerin gücü, onların "yeniden kullanılabilir" olmasında yatar. Bir karakter sahnesi tasarladınız ve test ettiniz. Şimdi bu karakteri oyununuzun farklı seviyelerine veya birden fazla düşman olarak farklı sahnelerde kolayca örnekleyerek ekleyebilirsiniz. Bu modüler yapı, kod tekrarını azaltır, hata ayıklamayı kolaylaştırır ve büyük oyunları daha yönetilebilir hale getirir.

1.3 Editör Arayüzü ve 2D/3D Görünüm Alanı (Viewport)

Orvix Engine'in sezgisel editörü, oyununuzu görsel olarak inşa etmeniz ve test etmeniz için tasarlanmış, güçlü bir iş istasyonudur. Editörü açtığınızda, oyununuzun kalbi olan Görünüm Alanı (Viewport) ile karşılaşırsınız.

2D Görünüm Alanı (Canvas): Piksel Sanatçısının Tuvali

Özellikle 2D oyun geliştirme modunda çalışırken, bu alana "Canvas" (Tuval) denir. Canvas, oyunun tüm 2D objelerinin yerleştirildiği, sınırsız ve esnek bir çalışma alanı gibidir. Karakterlerinizi, dinamik arka planlarınızı, etkileşimli nesnelerinizi ve kullanıcı arayüzü elementlerinizi bu tuval üzerine sürükleyip bırakarak oyun dünyanızı titizlikle görsel olarak oluşturursunuz. Burada, piksel hassasiyetinde konumlandırma ve ölçekleme yaparak oyununuzun estetiğini mükemmelleştirebilirsiniz.

3D Görünüm Alanı (Spatial View): Sanal Gerçekliğin Mimarisi

3D oyun geliştirme modunda ise, Görünüm Alanı "Spatial View" (Uzamsal Görünüm) olarak işlev görür. Burada, objeleri üç boyutlu uzayda konumlandırır, ışık kaynaklarını yerleştirir, kameraları ayarlar ve oyun dünyanızın derinliğini inşa edersiniz. 3D Viewport, gerçek zamanlı gölgeler, yansımalar ve post-processing efektleriyle oyununuzun nasıl görüneceğini anında gösterir.

Kilit Paneller: İş Akışınızın Anahtarları

Orvix Editör'ü, verimli bir iş akışı için tasarlanmış bir dizi hayati panelle çevrilidir:

1.4 İlk Oyununu Yarat: Klavyeyle Hareket Eden Bir Karakter

Şimdiye kadar öğrendiğimiz tüm temel bilgileri bir araya getirerek, klavye girdileriyle kontrol edebileceğiniz, etkileşimli bir karakter oluşturalım. Bu basit proje, Orvix Engine'deki oyun geliştirme döngüsünün ilk pratik uygulaması olacak.

Adım 1: Oyuncu Karakteri Sahnesini Oluşturma (Modüler Yaklaşım)

Yeni bir sahne başlatın ve kök düğüm olarak `CharacterBody2D` (2D oyunlar için fiziksel karakterler) ekleyin. Bu düğüm, fizik motorunun algılamasını ve çarpışmalarını yönetmek için temeldir. Düğümün adını "Oyuncu" olarak değiştirin ve bu sahneyi `Oyuncu.tscn` adıyla projenizin `res://oyuncular/` klasörüne (eğer yoksa oluşturun) kaydedin.

Adım 2: GDScript ile Karakter Hareketi Programlama (GDScript'in İlk Temelleri)

"Oyuncu" düğümüne sağ tıklayarak veya düğümü seçip üst menüden "Attach Script" (Betiği Bağla) seçeneğiyle yeni bir GDScript dosyası (`Oyuncu.ovx`) oluşturun ve aşağıdaki kodu içine yazın. Bu kod, klavye yön tuşlarından gelen girdiyi okuyacak ve `CharacterBody2D`'nin `velocity` (hız) özelliğini kullanarak karakteri fizik motoruyla hareket ettirecektir.


# Oyuncu.cs - Bu script, bir CharacterBody2D düğümüne eklendi.
extends CharacterBody2D

# Karakterin hareket hızını bir değişken olarak tanımlıyoruz.
# '@export' anahtar kelimesi, bu değişkeni İnceleyici panelinde düzenlenebilir yapar.
@export var hiz = 250.0 # Piksel/saniye cinsinden hız

# '_physics_process' fizik motoru tarafından kare başına sabit bir zamanda çağrılır.
# Bu, tutarlı fizik hareketleri için önemlidir.
func _physics_process(delta: float):
    # Klavyeden yön girdisini alalım.
    # 'Vector2.ZERO' boş bir 2D vektördür (0,0).
    var yon_girisi = Vector2.ZERO

    # Her bir yön tuşu için girdiyi kontrol et.
    # 'ui_right', 'ui_left', 'ui_down', 'ui_up' varsayılan giriş eylemleridir.
    if Input.is_action_pressed("ui_right"):
        yon_girisi.x += 1.0
    if Input.is_action_pressed("ui_left"):
        yon_girisi.x -= 1.0
    if Input.is_action_pressed("ui_down"):
        yon_girisi.y += 1.0
    if Input.is_action_pressed("ui_up"):
        yon_girisi.y -= 1.0

    # Yön girdisi normalize edilir (büyüklüğü 1 olur) ve hız ile çarpılır.
    # Bu, çapraz hareketlerin daha hızlı olmamasını sağlar.
    # 'velocity' CharacterBody2D'nin dahili bir değişkenidir.
    velocity = yon_girisi.normalized() * hiz
    
    # Karakteri fizik motoruyla hareket ettir ve çarpışmaları algıla.
    # 'move_and_slide()' yöntemi, karakteri hızına göre hareket ettirir
    # ve yüzeyler boyunca kaydırır.
    move_and_slide()

Adım 3: Oyunu Oynatma ve İlk Zaferin!

Yeni bir ana sahne oluşturun (örneğin `MainGame.tscn`). Bu sahne, oyununuzun genel çerçevesini oluşturacaktır. `Oyuncu.tscn` sahnesini, Dosya Sistemi panelinden sürükleyip ana sahnenizin Sahne paneline bırakarak "Oyuncu" karakterinizi ana oyuna ekleyin. Şimdi, editörün üst kısmındaki "Oynat" (Play) butonuna basarak veya `F5` tuşuna basarak oyununuzu çalıştırın. Klavyenizdeki yön tuşlarını kullanarak karakterinizi Canvas üzerinde sorunsuz bir şekilde hareket ettirebileceksiniz. Tebrikler! Oyun geliştirme yolculuğunuzda ilk büyük adımı attın ve kendi ilk etkileşimli oyun mekaniğini tamamladın!

Sonraki Bölümde Seni Neler Bekliyor?

Oyununu daha dinamik ve etkileşimli hale getirmek için bir sonraki bölümde şu kritik konulara derinlemesine dalacağız:

  • Sinyallerin Gücü: Düğümlerin birbirleriyle nasıl zarifçe iletişim kurduğunu ve olay tabanlı programlamanın temellerini öğreneceksin.
  • Kullanıcı Arayüzü (GUI) Ustalığı: Menüler, butonlar, puan tabloları ve diğer etkileşimli arayüz elemanlarını profesyonelce nasıl oluşturacağını ve tasarlayacağını keşfedeceksin.
  • Giriş Haritalaması ve Aksiyonlar: Klavyeden, fareden veya gamepad'den gelen komutları nasıl özelleştirebileceğini, aksiyonları nasıl tanımlayabileceğini ve oyun içi tepkileri nasıl programlayabileceğini öğreneceksin.
  • İlk Düşmanınız: Basit bir düşman karakteri oluşturarak, onu temel bir hareket döngüsü ile nasıl canlandıracağını göreceksin.

Bölüm 2: Dinamik Etkileşimler | Sinyallerin Gücü ve Kullanıcı Arayüzü

Oyunlar sadece hareketli görsellerden ibaret değildir; aynı zamanda etkileşimlerden ibarettir. Orvix Engine'in temelinde yatan **Sinyal (Signal) Sistemi** ve **Kullanıcı Arayüzü (GUI)** mimarisi, oyun dünyanızdaki dinamik tepkileri ve oyuncu etkileşimlerini yönetmenizi sağlar. Bu bölümde, bu güçlü mekanizmaları nasıl kullanacağınızı detaylıca inceleyeceğiz.

2.1 Çarpışma Sinyalleri ile Gelişmiş Etkileşimler

Sinyaller, Orvix'teki düğümler arası iletişimin omurgasıdır. Bir düğüm belirli bir olay gerçekleştirdiğinde bir sinyal yayar, diğer düğümler ise bu sinyali dinleyerek (bağlayarak) o olaya göre tepki verir. Bu, kodu daha temiz, daha modüler ve daha az bağımlı hale getirir. En yaygın sinyallerden biri, fiziksel çarpışmalardan tetiklenen sinyallerdir.

Adım 1: "Para" Toplanabilir Nesnesini Oluşturma Sahnesi

Yeni bir sahne başlatın ve kök düğüm olarak `Area2D` ekleyin. `Area2D` düğümü, fiziksel kurallara göre hareket etmeyen, ancak diğer fiziksel nesnelerle çarpışmaları (veya onlara giriş/çıkışları) algılayabilen alanlar oluşturmak için idealdir. Bu düğüme "Para" adını verin ve sahneyi `Para.tscn` olarak `res://varliklar/` klasörüne (oluşturun) kaydedin.

Adım 2: Para Sinyali ve GDScript Kod Mantığı

"Para" düğümüne bir GDScript (`Para.ovx`) ekleyin. Bu script, bir oyuncuyla çarpıştığında özel bir sinyal yayacak ve ardından kendini sahneden kaldırarak "toplandı" efektini verecektir. Bu, nesne tabanlı programlamanın ve sinyal/slot mekaniğinin güzel bir örneğidir.


# Para.ovx - Bu script, bir Area2D düğümüne eklendi.
extends Area2D

# "para_alindi" adında, 'puan' adında bir argüman taşıyan özel bir sinyal tanımla.
signal para_alindi(puan: int)

# '_on_body_entered' fonksiyonu, bu Area2D'ye fiziksel bir 'body' (CharacterBody2D veya RigidBody2D gibi)
# girdiğinde otomatik olarak çağrılır. Editörden sinyali bağlayarak oluşturulabilir.
func _on_body_entered(body: Node2D):
    # Çarpışan nesnenin 'Oyuncu' karakterimiz olup olmadığını kontrol ediyoruz.
    # 'body.name' yerine gruplar kullanmak daha sağlam bir yöntemdir.
    if body.name == "Oyuncu":
        # "para_alindi" sinyalini yayıyoruz ve 100 puan değerini argüman olarak gönderiyoruz.
        # Bu sinyali dinleyen tüm düğümler bu olayı alacaktır.
        emit_signal("para_alindi", 100)
        # Parayı sahneden güvenli bir şekilde sil (sonraki fizik adımında silinir).
        queue_free()

Bu kodu yazdıktan sonra, editörde "Para" düğümünü seçin. Sağdaki **"Düğüm"** panelini (Inspector'ın yanında) açın, `Area2D` altındaki "body_entered" sinyaline çift tıklayın. Açılan pencerede, script'inizin bağlı olduğu düğümü (Para) ve metodu seçerek `_on_body_entered` fonksiyonunu otomatik olarak oluşturabilir ve sinyali bağlayabilirsiniz.

Adım 3: Oyuncu Scriptinde Sinyali Dinleme ve Puan Entegrasyonu

Ana sahnede (veya `Oyuncu.tscn` içindeki "Oyuncu" düğümüne bağlı olan) `Oyuncu.ovx` script'inizi açın. Şimdi, "para_alindi" sinyalini dinlemek ve toplanan paralarla oyuncunun puanını güncellemek için aşağıdaki kodu script'inize ekleyin. Ayrıca, bu puanı oyun boyunca erişilebilir kılmak için global bir "OyunYönetimi" (Globals) singleton'ı kullanacağız.


# Oyuncu.ovx - Oyuncu karakterinin script'ine eklenir.
extends CharacterBody2D

# ... (Önceki hareket kodu burada kalır) ...

# '_ready' fonksiyonu düğüm sahne ağacına girdiğinde bir kez çağrılır.
func _ready():
    # 'Para' sahnelerinin nerede olduğunu varsayıyoruz (örneğin ana sahnede örneklenmişlerse).
    # Tüm 'Para' düğümlerini bulup onların 'para_alindi' sinyallerini bu oyuncuya bağlıyoruz.
    # Alternatif olarak, 'Para' düğümü oluşturulduğunda bu bağlantıyı yapabilirsiniz.
    # Bu, sinyalleri dinamik olarak bağlamanın bir yoludur.
    get_tree().get_nodes_in_group("toplanabilir_objeler").for_each(
        func(toplanabilir): 
            if toplanabilir is Area2D and toplanabilir.has_signal("para_alindi"):
                toplanabilir.para_alindi.connect(_on_Para_para_alindi)
    )
    # Önemli: 'Para' düğümlerinizi editörde bir gruba eklemeyi unutmayın (örn. "toplanabilir_objeler")!

# 'Para' düğümünün 'para_alindi' sinyali yayıldığında bu fonksiyon çağrılır.
func _on_Para_para_alindi(puan: int):
    # Global singleton'daki puanı güncelleyin.
    GlobalGameManager.artir_puan(puan) # GlobalGameManager, Project Settings -> AutoLoad'a eklenmeli.
    print("Toplanan Puan: ", GlobalGameManager.puan)
    # Oyuncuya ses veya görsel geribildirim ekleyebilirsiniz.

Bu kodla, oyuncu bir parayla çarpıştığında, para kendini yok edecek ve `GlobalGameManager` adlı global bir singleton'daki (projenizin herhangi bir yerinden erişilebilir) `puan` değişkenini güncelleyecektir. Konsolda puanınızın arttığını göreceksiniz. Bu, sinyal sisteminin temel gücüdür!

2.2 Kullanıcı Arayüzü (GUI) ve Akış Yönetimi

Oyunun menüleri, skoru, envanteri, diyalog kutuları ve diğer tüm etkileşimli elemanları kullanıcı arayüzü (GUI) ile oluşturulur. Orvix Engine, bu amaçla özel **Kontrol (Control)** düğümleri ve düzenleyiciler sunar. GUI, oyunun çekirdek mekaniklerinden ayrı bir katmanda çalışarak esneklik ve performans sağlar.

Adım 1: Basit Bir Başlangıç Menüsü Sahnesini Oluşturma

Yeni bir sahne başlatın ve kök düğüm olarak bir `Control` düğümü ekleyin. Bu, tüm UI elementleri için temel bir kapsayıcıdır. Bu sahneyi `MainMenu.tscn` olarak `res://ui/` klasörüne kaydedin. Ardından, bu `Control` düğümünün altına bir `CanvasLayer` düğümü ekleyin. `CanvasLayer`, GUI elemanlarının her zaman 2D veya 3D oyun dünyasının üzerinde, kendi bağımsız render katmanında çizilmesini sağlar, bu da ölçekleme ve görünürlük sorunlarını önler. `CanvasLayer`'ın altına sırasıyla şu UI düğümlerini ekleyin:

Bu düğümleri Canvas'ın (2D Viewport) tam ortasına yerleştirmek için, kapsayıcı `Control` düğümünün `Layout` özelliğini `Center Container` veya ilgili `Anchor` ve `Margin` ayarlarını kullanabilirsiniz.

Adım 2: Butona İşlev Kazandırma ve Sahne Geçişleri

Butonun "pressed" sinyaline tıklayarak (Düğüm panelinden veya scriptten bağlayarak), butona basıldığında çalışacak bir fonksiyon oluşturun. Bu fonksiyonu kullanarak oyun akışını ana oyun sahnesine geçirebiliriz. Sahne geçişleri, oyunun farklı bölümleri arasında sorunsuz bir deneyim sunmak için kritik öneme sahiptir.


# MainMenu.ovx - Bu script, ana menü sahnesindeki ana Control düğümüne eklendi.
extends Control

# `@onready` ile düğümlere daha güvenli referanslar alınır.
# '$' işareti, Sahne ağacında bir düğüm yolu anlamına gelir.
@onready var basla_butonu = $"VBoxContainer/BaslaButonu" # Butonunuzun Sahne yolunu doğru ayarlayın.

# '_ready' fonksiyonu, düğüm sahne ağacına girdiğinde bir kez çağrılır.
func _ready():
    # Butonun 'pressed' sinyalini bu scriptteki bir fonksiyona bağlıyoruz.
    basla_butonu.pressed.connect(_on_BaslaButonu_pressed)

# '_on_BaslaButonu_pressed' fonksiyonu, "Başla" butonuna basıldığında tetiklenir.
func _on_BaslaButonu_pressed():
    print("Oyun başlatılıyor! Ana Oyun Sahnesi'ne geçiliyor...")
    # 'get_tree().change_scene_to_file()' ile mevcut sahneyi değiştiriyoruz.
    # 'res://' prefix'i projenin kök dizinini ifade eder.
    get_tree().change_scene_to_file("res://AnaOyunSahnesi.tscn")

Bu kodla, "Başla" butonuna tıklandığında oyunun akışı "AnaOyunSahnesi" adlı sahneye sorunsuz bir şekilde geçiş yapacaktır. Bu, bir ana menüden oyuna veya bir seviyeden diğerine geçiş yapmanın en temel ve yaygın yoludur. Gelecekte, sahne geçişlerine animasyonlar veya yükleme ekranları da ekleyebilirsiniz.

2.3 Giriş Haritalaması ve Dinamik Kontroller

Oyuncu girdileri (klavye, fare, gamepad) oyununuzla etkileşimin temelidir. Orvix Engine'in **Giriş Haritalaması (Input Map)** sistemi, bu girdileri daha soyut ve yönetilebilir "Aksiyonlar"a dönüştürmenizi sağlar. Bu, farklı cihazlar için kontrol şemalarını kolayca özelleştirebileceğiniz anlamına gelir.

Giriş Haritalaması Kurulumu

Orvix Editör'de: **Proje > Proje Ayarları > Giriş Haritası (Input Map)** sekmesine gidin. Burada yeni aksiyonlar (örneğin "ates_et", "zipla", "envanter_ac") tanımlayabilir ve bu aksiyonlara farklı tuşları veya fare düğmelerini atayabilirsiniz. Örneğin, "ates_et" aksiyonuna hem fare sol tuşunu hem de klavyeden `Space` tuşunu atayabilirsiniz. Bu, kontrol esnekliği sağlar.

Girdiyi Kodda Kullanma

Oyun içinde bu aksiyonları kontrol etmek için `Input` singleton'ını kullanırsınız. Önceki `Oyuncu.ovx` script'imizdeki hareket kontrolünü bu sisteme uyarlayabiliriz:


# Oyuncu.ovx - Geliştirilmiş Giriş Yönetimi
extends CharacterBody2D

@export var hiz = 250.0

func _physics_process(delta: float):
    var yon_girisi = Vector2.ZERO

    # Giriş eylemlerini kullanarak daha temiz ve esnek kod.
    # Kullanıcı bu aksiyonlara dilediği tuşu atayabilir.
    if Input.is_action_pressed("move_right"): # "move_right" gibi yeni aksiyonlar tanımlayın.
        yon_girisi.x += 1.0
    if Input.is_action_pressed("move_left"):
        yon_girisi.x -= 1.0
    if Input.is_action_pressed("move_down"):
        yon_girisi.y += 1.0
    if Input.is_action_pressed("move_up"):
        yon_girisi.y -= 1.0

    velocity = yon_girisi.normalized() * hiz
    move_and_slide()

    # Bir aksiyonun yalnızca bir kez basılmasını kontrol etme (örneğin zıplama veya ateş etme)
    if Input.is_action_just_pressed("ates_et"): # "ates_et" aksiyonu tanımlanmış olmalı
        print("Ateş edildi!")
        # Mermi oluşturma fonksiyonunu burada çağırabilirsiniz.

Bu yöntem, oyuncuların kendi kontrol şemalarını özelleştirmelerine olanak tanır ve gelecekte farklı platformlara (gamepad gibi) uyum sağlamayı kolaylaştırır.

Sonraki Bölümde Seni Neler Bekliyor?

Oyununu daha da geliştirmek ve görsel zenginliğini artırmak için bir sonraki bölümde şu kritik konulara odaklanacağız:

  • TileMap Ustalığı: Hızlı ve pratik bir şekilde devasa 2D seviyeleri nasıl tasarlayacağını, çarpışma katmanlarını nasıl tanımlayacağını ve TileSet'leri nasıl optimize edeceğini öğreneceksin.
  • Dinamik Kamera Takibi: Oyuncuyu veya sahnedeki belirli bir bölgeyi takip eden dinamik bir kamera sistemi oluşturmayı, kamera limitlerini ve zoom efektlerini keşfedeceksin.
  • Temel Yapay Zeka (AI) Algoritmaları: Basit bir düşman karakteri oluşturarak, onun oyuncuyu takip etmesini, belirli yollar üzerinde hareket etmesini ve temel karar verme süreçlerini nasıl programlayacağını öğreneceksin.

Bölüm 3: Oyununu Geliştir | Seviye Tasarımı, Kamera ve Temel Yapay Zeka

Oyunun temel etkileşimlerini sinyaller ve GUI ile kurduktan sonra, sıra oyun dünyasını inşa etmeye geliyor. Bu bölümde, hızlı ve verimli seviye tasarımı için **TileMap** düğümünü, oyuncu hareketini takip eden bir **Kamera** sistemini ve oyununuza meydan okuma ekleyecek basit bir **Düşman Yapay Zekası** geliştirmeyi öğreneceksin.

3.1 Hızlı Seviye Oluşturma: TileMap (Döşeme Haritası)

TileMap, 2D oyunlarda seviye tasarlamanın en güçlü, en hızlı ve en verimli yoludur. Tek tek Sprite'ları manuel olarak yerleştirmek yerine, önceden hazırlanmış bir **TileSet** (döşeme kümesi) kullanarak haritanı sanki bir ressamın fırçasıyla boyar gibi oluşturabilirsin. Bu, büyük ve karmaşık seviyeleri inanılmaz bir hızla inşa etmene olanak tanır.

Adım 1: TileMap Düğümünü Kurma ve TileSet Oluşturma

Ana oyun sahnene (`AnaOyunSahnesi.tscn`) bir `TileMap` düğümü ekle. Bu düğüm, tüm harita döşemelerini içerecektir. Ardından, İnceleyici panelinde (Inspector) `TileMap` düğümünü seçiliyken, `Tile Set` özelliğine tıklayarak yeni bir `TileSet` kaynağı oluştur. Bu `TileSet`'e, haritanı oluşturan tüm görsel dosyalarını (örneğin zemin, duvar, platform görselleri) sürükleyip bırakarak döşemelerini (Tiles) tanımlayabilirsin. Her bir döşeme için çarpışma şekillerini, yansımaları veya özel verileri de ayarlayabilirsin.

Adım 2: Seviyeyi Tasarlama: Sanal Bir Ressam Gibi

`TileMap` düğümünü seçtiğinde, editörün üst kısmında özel TileMap düzenleme araçları belirecektir. Buradan farklı fırça araçlarını (tekli fırça, dikdörtgen, çizgi vb.) seçerek veya kütüphanendeki döşemeleri tek tek seçerek oyun haritanı Canvas (2D Görünüm Alanı) üzerine özgürce çizebilirsin. Fiziksel objeler (duvarlar, zeminler) için `Collision` (Çarpışma) katmanlarını da bu aşamada tanımlayabilirsin, böylece karakterlerin bu objelerle doğru bir şekilde etkileşim kurar.

3.2 Dinamik Kamera Takibi ve Viewport Yönetimi

Oyun dünyası genellikle oyuncu karakterinin hareketine göre kaymalıdır, böylece oyuncu her zaman ekranın merkezinde kalır ve çevresini görebilir. Bunu sağlamak için `Camera2D` düğümünü kullanacağız. `Camera2D`, oyun dünyasının belirli bir kısmını "görüntüleyen" ve bu görüntüyü oyuncunun ekranına yansıtan bir objektif gibidir.

Adım 1: Kamera Düğümünü Ekleme ve İlişkilendirme

Ana sahnedeki "Oyuncu" düğümünün (veya takip etmek istediğin herhangi bir düğümün) altına bir `Camera2D` düğümü ekle. Bu, kameranın her zaman karakterle aynı konumda olmasını, yani karakteri otomatik olarak takip etmesini sağlayacaktır. Bu hiyerarşik ilişki, kamera kodunu yazma ihtiyacını ortadan kaldırır.

Adım 2: Kamera Ayarları ve Optimizasyonlar

`Camera2D` düğümünü seç ve İnceleyici panelinden **"Current"** (Aktif) özelliğini işaretle. Bu, Orvix Engine'e oyun başlarken bu kamerayı kullanmasını söyler. Ayrıca, kameranın davranışını özelleştirmek için birçok ayar bulunur:

3.3 Basit Bir Düşman Yapay Zekası: Oyuncu Takibi

Oyununa biraz daha meydan okuma ve dinamizm eklemek için, oyuncuyu takip eden basit bir düşman oluşturalım. Bu, oyununuzda temel bir yapay zeka davranışının nasıl programlanacağını anlamanızı sağlayacak.

Adım 1: Düşman Karakteri Sahnesini Oluşturma

Yeni bir sahne oluştur ve ana düğüm olarak `CharacterBody2D` ekle. Adını "Düşman" olarak değiştir ve bu sahneyi `Düşman.tscn` olarak `res://dusmanlar/` klasörüne (oluşturun) kaydet. Karakterin görseli ve çarpışma şekli için bir `Sprite2D` ve `CollisionShape2D` eklemeyi unutma, tıpkı oyuncu karakterinde yaptığın gibi.

Adım 2: Düşman Yapay Zekası Kodu: Oyuncu Peşinde!

"Düşman" düğümüne bir GDScript (`Düşman.ovx`) ekle ve aşağıdaki kodu yaz. Bu kod, düşmanın her fizik adımında oyuncunun konumunu tespit etmesini ve ona doğru hareket etmesini sağlar. Ayrıca, düşmanı bir "düşmanlar" grubuna ekleyerek daha sonra mermilerle veya diğer etkileşimlerle kolayca hedef alabileceğiz.


# Düşman.ovx - Bu script, bir CharacterBody2D düğümüne eklendi.
extends CharacterBody2D

@export var hiz = 120.0 # Düşmanın hareket hızı
var oyuncu: CharacterBody2D = null # Oyuncu düğümünü tutacak değişken (tip ipucu)

# _ready fonksiyonu, düğüm sahne ağacına girdiğinde bir kez çağrılır.
func _ready():
    # Oyuncu düğümünü sahne ağacında "oyuncular" grubundan buluyoruz.
    # Oyuncuyu sahneye eklediğinizde bu gruba eklemeyi unutmayın!
    oyuncu = get_tree().get_first_node_in_group("oyuncular")
    if oyuncu is null:
        print("Hata: 'oyuncular' grubunda oyuncu bulunamadı!")
        queue_free() # Oyuncu yoksa düşmanı sil

# _physics_process, fiziksel hesaplamalar için sabit aralıklarla çağrılır.
func _physics_process(delta: float):
    if oyuncu:
        # Oyuncunun global pozisyonunu al ve ona doğru bir yön vektörü oluştur.
        # 'normalized()' vektörün büyüklüğünü 1 yapar, sadece yönü korur.
        var yon = (oyuncu.global_position - global_position).normalized()
        
        # Hız vektörünü ayarla (yön x hız).
        velocity = yon * hiz
        
        # Düşmanı hareket ettir ve çarpışmaları yönet.
        move_and_slide()
    else:
        # Oyuncu yoksa veya henüz bulunamadıysa düşmanı durdur.
        velocity = Vector2.ZERO
        move_and_slide()

# Oyuncuyu düşman grubuna eklemeyi unutma: Oyuncu düğümünü seç > Inspector > Node tab > Groups > "oyuncular" grubunu ekle.
# Ayrıca, düşmanı da "düşmanlar" grubuna ekleyebilirsin.

Önemli Not: Bu kodun doğru çalışması için, ana sahnenize eklediğiniz "Oyuncu" düğümüne **"oyuncular"** adında bir grup atamanız gerekir. Bunu, "Oyuncu" düğümünü editörde seçip, İnceleyici panelindeki "Düğüm" (Node) sekmesine giderek "Gruplar" (Groups) bölümünden yapabilirsiniz. Aynı şekilde, "Düşman" düğümlerinizi de "düşmanlar" adında bir gruba eklemek, gelecekteki mermi isabetleri gibi etkileşimleri kolaylaştıracaktır.

Sonraki Bölümde Seni Neler Bekliyor?

Oyununu daha da profesyonel hale getirmek ve oyuncu deneyimini zenginleştirmek için bir sonraki bölümde şu dinamik konulara odaklanacağız:

  • Gelişmiş Mermi Sistemi: Oyuncunun ateş etmesini sağlayan, çarpışmaları algılayan ve hasar veren bir mermi mekanizması oluşturacaksın.
  • İhtişamlı Partikül Efektleri (Particle Effects): Patlamalar, duman, toz bulutları veya sihirli parıltılar gibi görsel efektler ekleyerek oyununu daha canlı ve etkileyici hale getireceksin.
  • Kapsamlı Ses Yönetimi: Oyun müziği, ortam sesleri ve tekil ses efektleri ekleyerek oyunun atmosferini zenginleştirecek ve oyuncuya işitsel geribildirim sağlayacaksın.

Bölüm 4: Profesyonel Dokunuşlar | Silah Mekanikleri, Efektler ve Ses Yönetimi

Oyunun temel seviye tasarımını ve yapay zekayı öğrendikten sonra, sıra onu aksiyon ve duyusal geri bildirimlerle doldurmaya geldi. Bu rehber sayfasında, oyununu daha çekici ve dinamik hale getirmek için mermi sistemleri, etkileyici partikül efektleri ve sürükleyici bir ses yönetimi gibi önemli konuları ele alacağız.

4.1 Mermi Sistemi Oluşturma ve Çarpışma Yönetimi

Oyuncunun düşmanlara veya diğer etkileşimli nesnelere saldırmasını sağlamak, birçok oyun türünün en temel mekaniklerinden biridir. Orvix Engine'de güçlü ve esnek bir mermi sistemi oluşturmak oldukça basittir, çünkü fizik motoru ve sinyal sistemi bunu destekler.

Adım 1: "Mermi" Sahnesini Oluşturma (Yeniden Kullanılabilir Obje)

Yeni bir sahne başlatın ve kök düğüm olarak `RigidBody2D` ekleyin. `RigidBody2D` düğümü, fizik kurallarına (yerçekimi, kuvvetler vb.) göre hareket eden nesneler için idealdir, ancak mermilerde genellikle yerçekimini kapatırız. Adını "Mermi" olarak değiştirin ve sahneyi `Mermi.tscn` olarak `res://savunma/mermiler/` klasörüne (oluşturun) kaydedin.

Merminin `RigidBody2D` düğümünü seçiliyken, İnceleyici panelinde `Mode` özelliğini `Character` veya `Kinematic` yerine `Rigid` olarak bırakın, ancak `Gravity Scale` (Yerçekimi Ölçeği) değerini `0` olarak ayarlayın. Ayrıca, `Physics Material` (Fizik Materyali) ayarlarını kontrol edin ve `Friction` (Sürtünme) ile `Bounce` (Sekme) değerlerini `0` olarak ayarlayarak merminin düz bir çizgide hareket etmesini sağlayın.

Mermi Kodu: Ateşleme ve Hasar Mekaniği

"Mermi" düğümüne bir GDScript (`Mermi.ovx`) ekleyin. Bu kod, merminin bir kez oluşturulduğunda kendi başına hareket etmesini ve bir nesneye çarptığında (özellikle bir düşmana) ne olacağını belirler. Hasar verme ve kendini silme mekanizmalarını içerecektir.


# Mermi.ovx - Bu script, bir RigidBody2D düğümüne eklendi.
extends RigidBody2D

@export var hiz = 800.0 # Merminin hızı (piksel/saniye)
@export var hasar_miktari = 10 # Merminin verdiği hasar
@export var yasam_suresi = 3.0 # Merminin ne kadar süre sonra kendiliğinden silineceği (saniye)

# '_ready' fonksiyonu, düğüm sahne ağacına girdiğinde bir kez çağrılır.
func _ready():
    # Mermiyi 'mermiler' grubuna ekleyin, böylece düşmanlar tarafından algılanabilir.
    add_to_group("mermiler")
    
    # Mermiye hareket yönünde (düğümün rotasyonu) bir başlangıç hızı ver.
    # 'linear_velocity' bir RigidBody2D'nin dahili bir özelliğidir.
    linear_velocity = Vector2.RIGHT.rotated(rotation) * hiz
    
    # Merminin belirli bir süre sonra kendini yok etmesini sağlayan bir zamanlayıcı başlat.
    var timer = get_tree().create_timer(yasam_suresi)
    timer.timeout.connect(queue_free) # Zamanlayıcı bittiğinde mermiyi sil.

# '_on_body_entered' sinyali, mermi başka bir fiziksel nesneye çarptığında tetiklenir.
# Bu sinyali Editörden, Mermi düğümünün CollisionShape2D'sinden veya RigidBody2D'sinden bağlayabilirsiniz.
func _on_body_entered(body: Node):
    # Çarpışılan nesnenin 'hasar_al' adında bir metodu olup olmadığını kontrol et.
    # Bu, düşmanlar, kırılabilir objeler vb. için geçerli olacaktır.
    if body.has_method("hasar_al"):
        body.hasar_al(hasar_miktari) # Hasar ver.
        
    # Çarptıktan sonra mermiyi sahneden sil.
    queue_free()

# Editörde mermi düğümünü seçin ve RigidBody2D panelindeki 'body_entered' sinyalini script'e bağlayın.
# Eğer Area2D eklediyseniz, Area2D'nin 'body_entered' veya 'area_entered' sinyallerini de kullanabilirsiniz.

Önemli Notlar:

Oyuncu Scriptinde Mermi Ateşleme Fonksiyonu

Şimdi, `Oyuncu.ovx` script'inize geri dönün ve oyuncunun bir tuşa bastığında (örneğin "ates_et" aksiyonu) mermi oluşturup fırlatmasını sağlayan kodu ekleyin. Bu, dinamik sahne oluşturma ve örnekleme kavramını da içerir.


# Oyuncu.ovx - Mermi ateşleme özelliği eklendi
extends CharacterBody2D

# ... (Önceki hareket ve puanlama kodu burada kalır) ...

# Mermi sahnesinin ön yüklemesi (pre-load). Bu, mermiyi hafızaya alır ve hızlıca örneklemeyi sağlar.
const MermiSahnesi = preload("res://savunma/mermiler/Mermi.tscn") # Kendi mermi sahnenizin yolunu girin!

# Merminin ortaya çıkacağı konum (örneğin, silahın ucu).
# Editörde Oyuncu düğümünün altına bir Marker2D düğümü ekleyip adını "MermiCikisNoktasi" yapın.
@onready var mermi_cikis_noktasi = $"MermiCikisNoktasi" 

func _physics_process(delta: float):
    # ... (Hareket kodu) ...

    # "ates_et" aksiyonuna basıldığında mermi ateşle.
    if Input.is_action_just_pressed("ates_et"):
        ates_et()

# 'ates_et' fonksiyonu, bir mermi örneği oluşturur ve onu sahneye ekler.
func ates_et():
    # Mermi sahnesinden yeni bir örnek oluştur.
    var yeni_mermi = MermiSahnesi.instantiate()
    
    # Merminin global pozisyonunu ve rotasyonunu oyuncunun mermi çıkış noktasına ayarla.
    yeni_mermi.global_position = mermi_cikis_noktasi.global_position
    yeni_mermi.rotation = global_rotation # Oyuncunun baktığı yöne doğru ateş etmesini sağlar.
    
    # Mermiyi ana sahnenin bir çocuğuna ekle (örn. get_parent() veya get_tree().current_scene).
    get_parent().add_child(yeni_mermi)
    # Oyunun ana Node'una eklemek daha iyi bir yöntem olabilir:
    # get_tree().get_current_scene().add_child(yeni_mermi)

Bu kodla, `ates_et` aksiyonuna basıldığında, oyuncunun konumunda yeni bir mermi oluşacak ve ateşleme sesini çalacak (eğer eklediysen). Bu, dinamik olarak nesne oluşturmanın ve sahne ağacına eklemenin temel yoludur.

4.2 Görsel Şölen: Partikül Sistemleri (CPUParticles2D / GPUParticles2D)

Görsel efektler (FX), oyunun canlı, tepkisel ve sürükleyici hissetmesini sağlayan en önemli unsurlardan biridir. Bir patlama, duman bulutu, karakterin ayak izi tozu veya sihirli parıltılar gibi efektler için Orvix Engine'in güçlü **Partikül Sistemlerini** kullanacağız. 2D için `CPUParticles2D` (CPU tabanlı, daha basit) veya `GPUParticles2D` (GPU tabanlı, daha performanslı ve karmaşık efektler için) düğümlerini kullanabiliriz.

Adım 1: Partikül Efekti Düğümünü Ekleme ve Temel Ayarlar

Merminin çarpışma noktasında bir patlama efekti veya oyuncunun ateş ettiğinde namludan çıkan duman efekti yaratmak için, ilgili sahnelerinize (örneğin "Mermi" sahnesine veya "Oyuncu" sahnesindeki mermi çıkış noktasına) bir `CPUParticles2D` düğümü ekle. Ardından, İnceleyici panelinde, partikül sisteminin özelliklerini kapsamlı bir şekilde özelleştirebilirsin:

Partikül sistemleri oldukça esnektir ve sadece birkaç ayar değişikliğiyle alevden suya, sihirli parıltılardan yoğun dumana kadar her türlü efekti yaratabilirsin. **`One Shot`** özelliğini açarak, sistemin sadece bir kez tetiklenmesini (örneğin bir patlama için) ve ardından durmasını sağlayabilirsin.

Partikül Efektini Kodla Tetikleme

Partikül sistemini bir olayla (örneğin mermi çarpışması) tetiklemek için, genellikle `emitting` (yayılım) özelliğini `true` yaparak başlar ve ardından kısa bir süre sonra kendini silmesini sağlarsın. Partikül sistemlerini sahneye dinamik olarak ekleyip silmek daha verimlidir.


# Mermi.ovx - Partikül efekti tetikleme örneği
extends RigidBody2D

# ... (Diğer değişkenler ve fonksiyonlar) ...

# Patlama partikül sahnesinin ön yüklemesi.
const PatlamaEfektiSahnesi = preload("res://efektler/PatlamaEfekti.tscn") # Kendi patlama sahnenizin yolu

func _on_body_entered(body: Node):
    # Hasar verme kodu...
    
    # Patlama efektini oluştur ve oyna.
    var patlama_efekti = PatlamaEfektiSahnesi.instantiate()
    patlama_efekti.global_position = global_position # Merminin pozisyonunda oluşur
    get_tree().get_current_scene().add_child(patlama_efekti)
    
    # Eğer partikül sistemi 'One Shot' değilse, manuel olarak başlat.
    if !patlama_efekti.one_shot:
        patlama_efekti.emitting = true

    # Partikül efekti bittiğinde kendini silmesi için bir zamanlayıcı ayarla (eğer 'One Shot' değilse ve 'Autostart' kapalıysa)
    # Genellikle partikül efekti sahneleri 'One Shot' açık ve 'Autostart' açık olarak ayarlanır
    # ve 'Lifetime' süresinden sonra otomatik silinmeleri için bir 'Timer' eklenir.
    var efekti_sil_timer = get_tree().create_timer(patlama_efekti.lifetime + 0.5) # Küçük bir gecikme ekleyerek bitmesini bekle
    efekti_sil_timer.timeout.connect(patlama_efekti.queue_free)

    queue_free() # Mermiyi sil

Bu kodla, mermi herhangi bir şeye çarptığında dinamik bir patlama efekti oluşacak ve ardından hem mermi hem de efekt sahneden silinecektir.

4.3 Oyun Sesleri: Atmosferi Yaratma ve Duyusal Geri Bildirim

Ses, oyunun atmosferini güçlendiren, oyuncuya önemli geri bildirimler sağlayan ve genel deneyimi inanılmaz derecede zenginleştiren, genellikle göz ardı edilen ama en önemli unsurlardan biridir. Orvix Engine, ses dosyalarını yönetmek ve çalmak için güçlü **AudioStreamPlayer** düğümleri ve Audio Bus sistemi sunar.

Adım 1: Ses Düğümlerini Ekleme (2D, 3D ve Global)

Orvix'te üç ana ses düğümü vardır:

Oyununuzun arka plan müziği için ana sahnenize bir `AudioStreamPlayer` düğümü ekle ve ses dosyanı (örneğin `.ogg`, `.wav` veya `.mp3`) İnceleyici panelindeki "Stream" özelliğine sürükle. `Autoplay` özelliğini aktif ederek oyun başladığında müziğin otomatik olarak çalmasını sağlayabilirsin. Ses efektleri (örneğin mermi sesi, patlama sesi) için ise her etkileşimli objeye (oyuncu, düşman, mermi) veya efekt sahnesine birer `AudioStreamPlayer2D` düğümü eklemelisin.

Adım 2: Koduyla Ses Oynatma ve Yönetimi

Bir sesi kod ile oynatmak oldukça basittir. Genellikle ilgili `AudioStreamPlayer` düğümüne bir referans alırsın ve ardından `play()` metodunu çağırırsın:


# Oyuncu.ovx - Ateş sesi örneği
extends CharacterBody2D

# ... (Önceki kodlar) ...

# Ateş sesi için AudioStreamPlayer2D düğümüne referans al.
# Bu düğümü Oyuncu sahnesinin altına eklemeyi unutmayın!
@onready var ates_sesi = $"AtesSesiPlayer" # Düğüm yolunuza göre ayarlayın.

# 'ates_et' fonksiyonu içindeki ses çalma.
func ates_et():
    # ... mermi oluşturma kodları ...
    
    # Sesi baştan başlat ve çal.
    ates_sesi.play() 

Bu basit komutla, oyunundaki aksiyonlara anında ses tepkileri ekleyebilirsin. Daha karmaşık ses yönetimi için Orvix'in `Audio Bus` sistemini kullanabilirsin. Bu sistemle müzik, ses efektleri ve diyalog seslerini ayrı ayrı kontrol edebilir, ses seviyelerini ayarlayabilir ve efektler (yankı, gecikme) ekleyebilirsin. Bu, oyunun genel ses dengesini ve kalitesini artırır.


Bölüm 5: Uzmanlık Seviyesi | Orvix Engine Geliştirme Sanatının Zirvesi

Tebrikler! Orvix Engine ile oyun geliştirme yolculuğunuzun bu aşamasına ulaştınız. Artık temel konularda yetkinliğe ulaştığınıza göre, bir oyunun "oynanabilir bir demodan" tam teşekküllü, optimize edilmiş ve yayınlanmaya hazır bir ürüne dönüşmesi için bilmeniz gereken en önemli 20 konuyu detaylı bir şekilde öğreneceksin. Her başlık altında hem teorik bilgi hem de pratik GDScript kod örnekleri bulacaksın.

5.1 GDScript'in Derinlikleri: Temiz ve Verimli Kodlama Sanatı

GDScript, basitliği ve esnekliği sayesinde hızlı prototipleme için mükemmeldir. Ancak, büyük projelerde temiz, sürdürülebilir ve verimli kod yazmak için dilin daha ileri düzey özelliklerini bilmek gerekir.

  1. Sınıflar (Classes) ve Otomatik Yükleme (AutoLoad) ile Global Yönetim

    Bir projenin büyümesiyle birlikte kodun yönetilebilir olması kritik hale gelir. Kendi özel sınıflarınızı oluşturarak kodu mantıksal, bağımsız parçalara ayırabilirsiniz. class_name anahtar kelimesi, bir script dosyasını global bir sınıf olarak tanımlamanızı sağlar, böylece editörde otomatik tamamlamadan yararlanabilirsiniz. "AutoLoad" (Otomatik Yükleme) ise, bu sınıflardan birini veya bir sahneyi, oyunun açılışında otomatik olarak yükleyerek her yerden erişilebilir bir singleton'a (tekil örnek) dönüştürür. Bu, oyunun ana durumunu (skor, can, seviye), envanterini, ses ayarlarını veya herhangi bir global yönetimi yapmak için mükemmel bir desendir.

    
    # GlobalGameManager.ovx (Project Settings -> AutoLoad'a "GlobalGameManager" adıyla eklenmeli)
    extends Node
    # 'class_name' ile global bir sınıf olarak tanımla. Editörde otomatik tamamlama sağlar.
    class_name GlobalGameManager
    
    var puan = 0
    var oyuncu_can_sayisi = 3
    var oyun_bitti = false
    
    # Puanı artıran metod
    func artir_puan(ek_puan: int):
        puan += ek_puan
        print("Toplam Puan: ", puan)
        # Buradan UI'daki puan etiketine sinyal yayabilirsiniz.
    
    # Oyunu bitiren metod
    func oyunu_bitir():
        oyun_bitti = true
        print("Oyun Bitti! Final Puanı: ", puan)
        # Menüye geçiş veya oyun sonu ekranı açma gibi işlemleri burada yapabilirsiniz.
    
    

    Kullanım Örneği:

    
    # Herhangi bir script dosyasında
    extends CharacterBody2D
    
    func _on_dusman_olduruldu():
        # Global singleton'a doğrudan erişim (GlobalGameManager olarak adlandırdığımızı varsayarsak)
        GlobalGameManager.artir_puan(100)
        GlobalGameManager.oyuncu_can_sayisi -= 1
    
    
  2. Enums (Sabit Listeler) ile Kod Okunabilirliğini Artırma

    Oyun geliştirirken, belirli durumları, tipleri, nesne hallerini veya modları temsil etmek için sabit listeler (enums) kullanmak, kodunuzu sadece daha okunabilir hale getirmekle kalmaz, aynı zamanda hata yapma olasılığını da ciddi şekilde azaltır. Örneğin, bir düşmanın durumunu bir metin (`"bekle"`) veya rastgele bir sayı (`0`) yerine, daha anlamlı ve otomatik tamamlamayla desteklenen bir enum ile ifade edebilirsiniz. Bu, büyük kod tabanlarında tutarlılık sağlar.

    
    # Düşman.ovx - Enum Kullanımı
    extends CharacterBody2D
    
    # Düşman durumları için enum tanımlama. GDScript'te bu, aslında sabit int değerleridir.
    enum Durum { BEKLE, YURUME, SALDIRMA, OLME, KACMA }
    var mevcut_durum = Durum.BEKLE # Varsayılan başlangıç durumu
    
    func _physics_process(delta: float):
        # 'match' ifadesi, durum makineleri için idealdir.
        match mevcut_durum:
            Durum.BEKLE:
                # Bekleme davranışları: Animasyon durdur, hareket etme, etrafı gözlemle.
                velocity = Vector2.ZERO
                # Oyuncuyu algılarsa durumu değiştir.
                if algila_oyuncu():
                    mevcut_durum = Durum.YURUME
            Durum.YURUME:
                # Yürüme davranışları: Hedefe doğru ilerle, yürüme animasyonunu oyna.
                # ... (hareket kodu) ...
                if saldiri_menzilinde():
                    mevcut_durum = Durum.SALDIRMA
                elif can < 20:
                    mevcut_durum = Durum.KACMA # Düşük can durumunda kaçma
            Durum.SALDIRMA:
                # Saldırı davranışları: Saldırı animasyonu, hasar verme mantığı.
                velocity = Vector2.ZERO # Saldırırken durabilir
                if !saldiri_menzilinde():
                    mevcut_durum = Durum.YURUME # Menzil dışına çıkarsa takip etmeye devam et
            Durum.OLME:
                # Ölme davranışları: Ölüm animasyonu oyna, düşmanı sahneden sil.
                # ... (ölüm efekti veya zamanlayıcı) ...
                queue_free() # Düğümü sil.
            Durum.KACMA:
                # Kaçma davranışları: Oyuncudan uzaklaş, koşma animasyonunu oyna.
                # ... (ters yöne hareket kodu) ...
    
    # Yardımcı fonksiyonlar (örnek)
    func algila_oyuncu() -> bool: return true # Gerçek algılama mantığı buraya gelir
    func saldiri_menzilinde() -> bool: return false # Gerçek menzil kontrolü buraya gelir
    
  3. Özel Sinyaller (Custom Signals) ve Karmaşık Sinyal Bağlantıları

    Orvix'in dahili düğüm sinyalleri (örneğin `body_entered`, `pressed`) haricinde, kendi özel sinyallerinizi de tanımlayabilirsiniz. Bu, bileşenler arasındaki iletişimi daha esnek, "gevşek bağlı" (loosely coupled) ve olay odaklı hale getirir. Bir sınıf bir olay hakkında sinyal yayar, diğer sınıflar ise bu sinyale abone olarak (connect) bu olaya göre tepki verir. Bu, UI ve oyun mekanikleri arasında ayrım yaparken veya karmaşık sistemler arasında bilgi akışını yönetirken çok güçlüdür.

    
    # Oyuncu.ovx - Can Değişimi ve Özel Sinyal
    extends CharacterBody2D
    
    # 'can_degisti' adında bir sinyal tanımla. Bu sinyal, yeni can değerini argüman olarak yayacak.
    signal can_degisti(yeni_can: int)
    signal oldu() # Oyuncu öldüğünde yayılacak sinyal
    
    var can = 100:
        # 'setget' gibi davranan property setter'ı. 'can' değişkeni değiştiğinde tetiklenir.
        set(yeni_can):
            can = clampi(yeni_can, 0, 100) # Canı 0-100 arasında sınırla.
            emit_signal("can_degisti", can) # Can değişti sinyalini yay.
            if can == 0:
                emit_signal("oldu") # Can 0 olursa ölüm sinyalini yay.
    
    # Hasar alma metodu
    func hasar_al(miktari: int):
        self.can -= miktari # Setter otomatik olarak tetiklenecek.
        print("Oyuncu canı: ", can)
    
    # UI elementinde canı güncelleme örneği (örneğin bir HealthBar script'inde)
    # HealthBar.ovx'e eklenmeli:
    # extends ProgressBar
    # @onready var oyuncu = $"../Oyuncu" # Oyuncuya referans al
    # func _ready():
    #     oyuncu.can_degisti.connect(self._on_oyuncu_can_degisti)
    #     max_value = oyuncu.can # Max değeri ayarla
    # func _on_oyuncu_can_degisti(yeni_can):
    #     value = yeni_can # ProgressBar'ın değerini güncelle
    

5.2 Optimizasyon ve Performans Teknikleri: Akıcı Oyunlar İçin Sırlar

Büyük ve karmaşık oyunlarda performans sorunları kaçınılmazdır. Orvix Engine, bu sorunları tespit etmenize ve gidermenize yardımcı olacak güçlü araçlar sunar. Oyuncuların takılmadan, akıcı bir deneyim yaşamasını sağlamak için optimizasyon sanatını öğrenmelisin.

  1. Performans Profilleyici (Profiler) ve Hata Ayıklama (Debugger): Performans Dedektifleri

    Oyununuzun neden yavaşladığını veya takıldığını anlamak, optimize etmek için ilk ve en kritik adımdır. Orvix'in yerleşik **Profiler'ı**, CPU ve GPU kullanımını, bellek tahsisatını, çizim çağrılarını ve fiziksel işlemlerin harcadığı süreyi gerçek zamanlı olarak izlemenizi sağlar. Bu, darboğazları (bottleneck) tespit etmeniz için size somut veriler sunar. Örneğin, hangi script'in çok zaman harcadığını veya hangi sahnenin çok fazla poligon içerdiğini görebilirsiniz. **Hata Ayıklayıcı (Debugger)** ise, kodunuzu adım adım çalıştırarak değişken değerlerini anlık olarak görmenizi, kesme noktaları (breakpoints) ayarlayarak kodun belirli noktalarda durmasını sağlamanızı ve çağrı yığınını (call stack) incelemenizi sağlar. Bu ikili, karmaşık performans sorunlarını ve mantıksal hataları bulmak için vazgeçilmezdir.

  2. `_process` ve `_physics_process` Arasındaki Kritik Fark: Akış Kontrolü

    Performans optimizasyonunun en temel kurallarından biri, doğru fonksiyonu doğru amaç için kullanmaktır. `_process(delta)` fonksiyonu, oyunun her **çizim karesinde (frame)** çalışır ve ekran yenileme hızıyla (FPS) ilişkilidir. Görsel güncellemeler, giriş okumaları ve zamanla değişen animasyonlar için idealdir. `_physics_process(delta)` ise saniyede **sabit bir kez** (varsayılan olarak 60 kez) çalışır ve fiziksel hesaplamalar, çarpışma algılamaları ve hareket kodları için kullanılmalıdır. Karakter hareketlerini, çarpışmaları, yerçekimi etkileşimlerini ve fiziksel etkileşimleri daima `_physics_process` içinde yapın. Bu ayrım, oyununuzun farklı sistemlerde tutarlı fiziksel davranış sergilemesini ve gereksiz hesaplamalardan kaçınmasını sağlar.

  3. Bellek Yönetimi ve Kaynak Yüklemesi: Akıllı Hafıza Kullanımı

    Özellikle mobil cihazlar ve düşük sistemler için bellek yönetimi hayati önem taşır. Gereksiz kaynakları (dokular, sesler, sahneler) yüklemekten kaçının. Artık ihtiyaç duymadığınız düğümleri ve kaynakları `queue_free()` (düğümler için) veya `ResourceLoader.load()/unload()` (kaynaklar için) kullanarak sahneden kaldırın. `preload()` yerine `load()` kullanmak, kaynakları yalnızca ihtiyaç duyulduğunda yüklemenizi sağlar. Nesne havuzlama (object pooling) gibi teknikler, sık sık oluşturulan ve yok edilen nesneler (mermiler, düşmanlar) için performansı ciddi şekilde artırabilir.

5.3 Gelişmiş Düğüm Sistemleri: Karakter ve Sahne Yönetiminde Ustalık

Orvix Engine'in düğüm tabanlı yapısı, karmaşık oyun mekaniklerini bile modüler ve yönetilebilir hale getirmenize olanak tanır. İşte daha dinamik ve esnek oyunlar oluşturmak için kullanabileceğiniz bazı ileri düzey düğüm sistemleri:

  1. Animasyon Ağacı (AnimationTree) ile Karmaşık Animasyon Akışı

    Basit AnimationPlayer düğümü, tekli animasyonları oynatmak için yeterlidir. Ancak, bir karakterin yürüme, koşma, zıplama, bekleme gibi farklı animasyon durumları arasında yumuşak ve mantıksal geçişler yapması gerektiğinde AnimationTree düğümü devreye girer. Bu düğüm, bir **durum makinesi (state machine)** veya **karışım ağacı (blend tree)** kullanarak animasyonları görsel olarak bir ağaç yapısında bağlamanızı, geçiş koşullarını (örneğin hız > 0 ise koşmaya geç) ve geçiş sürelerini ayarlamanızı sağlar. Böylece kodunuzda sadece karakterin durumunu değiştirerek doğru animasyonun otomatik olarak oynatılmasını sağlayabilirsiniz.

  2. Durum Makineleri (State Machines) ile Karakter ve Düşman Kontrolü

    Durum makineleri, bir objenin (karakter, düşman, oyun durumu) farklı davranışlarını organize etmenin en güçlü ve ölçeklenebilir yollarından biridir. Örneğin, bir düşman "Bekleme" durumundayken oyuncuyu arar, "Takip" durumundayken oyuncuya doğru ilerler ve "Saldırı" durumundayken ona saldırır. Her durum için ayrı bir kod parçası yazmak yerine, hepsini tek bir durum makinesi altında yönetebilirsiniz. Bu, kod tekrarını azaltır ve davranışları kolayca değiştirebilmenizi sağlar. GDScript'teki `enum`'lar ve `match` ifadeleri ile kolayca durum makineleri oluşturabilirsiniz (örneğini yukarıda vermiştik).

    
    # Gelişmiş Düşman Durum Makinesi Örneği
    extends CharacterBody2D
    
    enum State { IDLE, PURSUE, ATTACK, DEAD, PATROL } # Yeni durumlar eklendi
    var state = State.IDLE
    var player: Node2D = null
    var hiz = 100.0
    var saldiri_menzili = 50.0
    var goruntu_menzili = 300.0
    
    func _ready():
        player = get_tree().get_first_node_in_group("oyuncular")
        # Eğer düşman devriye gezecekse, bir Patrul noktası veya yolu ayarlanabilir.
    
    func _physics_process(delta: float):
        match state:
            State.IDLE:
                velocity = Vector2.ZERO
                # Oyuncuyu algılarsa takip et.
                if player and global_position.distance_to(player.global_position) < goruntu_menzili:
                    state = State.PURSUE
                else:
                    # Boşta gezinme veya rastgele hareket.
                    pass
            State.PURSUE:
                # Oyuncuyu takip et.
                if player:
                    var direction = (player.global_position - global_position).normalized()
                    velocity = direction * hiz
                    move_and_slide()
                    if global_position.distance_to(player.global_position) < saldiri_menzili:
                        state = State.ATTACK
                    elif global_position.distance_to(player.global_position) > goruntu_menzili:
                        state = State.IDLE # Oyuncu menzilden çıkarsa dur
                else:
                    state = State.IDLE
            State.ATTACK:
                velocity = Vector2.ZERO
                # Saldırı mantığı, animasyon, hasar verme.
                if global_position.distance_to(player.global_position) >= saldiri_menzili:
                    state = State.PURSUE # Menzil dışına çıkarsa tekrar takip et.
            State.DEAD:
                # Ölüm animasyonu, skor verme, sahneden silme.
                queue_free()
            State.PATROL:
                # Devriye gezme mantığı (belirli noktalara gitme)
                pass # Daha karmaşık devriye kodu buraya gelir.
    
    # hasar_al metodu (Düşmanın canını yönetmek için)
    var can = 50
    func hasar_al(miktari: int):
        can -= miktari
        print("Düşman canı: ", can)
        if can <= 0:
            state = State.DEAD
    
  3. Tween ile Akıcı ve Dinamik Geçişler

    Bir objenin bir özellik değerini (konum, rotasyon, boyut, renk, opaklık) belirli bir süre içinde yumuşak ve kontrol edilebilir bir şekilde değiştirmek için Tween düğümünü veya `create_tween()` metodunu kullanın. Bu, menülerin zarif bir şekilde açılması/kapanması, bir objenin ekranda titreşmesi, karakterin bir noktaya kayması veya UI elementlerinin animasyonlu olarak görünmesi gibi birçok görsel efekt için idealdir. `Tween`'ler, farklı geçiş türleri (linear, sine, elastic, bounce) ve kolaylık fonksiyonları (ease-in, ease-out, ease-in-out) ile özelleştirilebilir.

    
    # Butona basıldığında pencereyi açma animasyonu veya karakter zıplama
    extends Control # UI için
    # extends CharacterBody2D # Karakter için
    
    @onready var pencere_paneli = $"AyarlarPaneli" # Animasyon yapılacak düğüm
    
    func _on_ac_buton_pressed():
        # Mevcut tween'i durdur (varsa), çakışmayı önler.
        if get_tree().has_group("active_tweens"): # Kendi tween grubunuzu oluşturabilirsiniz.
            var active_tweens = get_tree().get_nodes_in_group("active_tweens")
            for t in active_tweens:
                if t.get_target() == pencere_paneli:
                    t.kill()
        
        var tween = create_tween()
        tween.set_trans(Tween.TRANS_ELASTIC) # Yaylı geçiş
        tween.set_ease(Tween.EASE_OUT) # Yavaş başlayıp hızlanır, sonra yavaşlar.
        
        # Pencerenin konumunu 0.8 saniyede (100, 100) pozisyonuna yumuşakça getir.
        tween.tween_property(pencere_paneli, "position", Vector2(100, 100), 0.8)
        
        # Pencerenin opaklığını da aynı anda değiştir (paralel animasyon)
        tween.tween_property(pencere_paneli, "modulate:a", 1.0, 0.5) # Görünür hale getir.
        
        # Animasyon bittikten sonra bir fonksiyon çağırabilirsin.
        tween.finished.connect(func(): print("Pencere animasyonu bitti!"))
    
    

5.4 Oyun Fiziği ve Çarpışma Mekanikleri: Gerçekçilik ve Kontrol

Oyununuzdaki fiziksel etkileşimler, oyuncuya gerçekçi bir deneyim sunmak için kritik öneme sahiptir. Orvix Engine'in güçlü fizik motoru, çarpışmaları, hareketleri ve etkileşimleri hassas bir şekilde kontrol etmenizi sağlar.

  1. Fizik Katmanları (Physics Layers) ve Maskeleri (Masks): Gelişmiş Çarpışma Filtreleme

    Oyununuzdaki farklı objelerin (oyuncu, düşman, mermi, zemin, duvar, toplanabilir eşyalar) hangi gruplara ait olduğunu ve hangi gruplarla çarpışacağını veya etkileşimde bulunacağını belirlemek için fizik katmanlarını ve maskelerini kullanmak hayati öneme sahiptir. **Katman (Layer)**, bir objenin "hangi katmanda var olduğunu", **Maske (Mask)** ise "hangi katmandaki objeleri algılayacağını veya onlarla çarpışacağını" belirler. Bu, gereksiz çarpışma hesaplamalarını önleyerek performansı ciddi şekilde artırır ve fizik etkileşimlerini hassas bir şekilde kontrol etmenizi sağlar. Örneğin, mermilerin sadece düşmanlarla çarpışmasını, oyuncunun sadece zeminle çarpışmasını sağlayabilirsiniz.

  2. `RayCast2D` ve `RayCast3D` ile Işın Gönderimi: Hassas Algılama

    RayCast2D (2D için) veya `RayCast3D` (3D için) düğümü, belirli bir yöne sanal bir "ışın" (veya çizgi) göndererek bu ışının bir şeye çarpıp çarpmadığını kontrol etmenizi sağlar. Bu, düşmanın önündeki engelleri tespit etmek (yol bulma için), bir karakterin zemine basıp basmadığını kontrol etmek (platform oyunlarında zıplama için hayati), interaktif bir objeyi işaret etmek veya düşmanın görüş alanını kontrol etmek gibi birçok senaryoda kullanılır. Sonuç olarak çarptığı objeyi ve çarpışma noktasını alabilirsiniz.

    
    # Oyuncunun zemine basıp basmadığını kontrol eden raycast örneği
    extends CharacterBody2D
    
    # '@onready' ile editörden bağlı olan RayCast2D düğümüne referans al.
    @onready var zemin_ray = $"ZeminRayCast2D" # Oyuncu düğümünün altında olmalı ve doğru pozisyonda.
    
    # _physics_process içinde raycast'i kontrol et.
    func _physics_process(delta: float):
        # Raycast'i güncelle (eğer aktif değilse veya sürekli güncellenmesi gerekiyorsa).
        zemin_ray.force_raycast_update()
        
        if zemin_ray.is_colliding():
            var collider = zemin_ray.get_collider() # Çarptığı düğümü al.
            if collider and collider.is_in_group("zeminler"): # Çarptığı nesnenin "zeminler" grubunda olup olmadığını kontrol et.
                print("Zemine bastı! Collider: ", collider.name)
                # Zıplama veya diğer zemin bazlı eylemleri burada tetikleyebilirsiniz.
            elif collider and collider.is_in_group("platformlar"):
                print("Platforma bastı!")
        else:
            print("Havada!")
    
    
  3. `Area2D` ve `Area3D` ile Bölge Algılaması: Çarpışmasız Etkileşimler

    Area2D (2D için) veya `Area3D` (3D için) düğümleri, fiziksel bir çarpışma olmadan, bir objenin belirli bir "bölgeye" girip girmediğini algılamanızı sağlar. `RigidBody` veya `CharacterBody` gibi düğümler fiziksel olarak birbirine çarpar ve tepki verirken, `Area` düğümleri sadece bir nesnenin alanına girdiğini veya çıktığını algılar ve ilgili sinyalleri yayar (`body_entered`, `body_exited`, `area_entered`, `area_exited`). Bu, toplama objeleri (altın, iksir), tetikleyiciler (kapı açma, sahne değiştirme), düşmanın menzili (oyuncuyu algılama) veya tehlikeli bölgeler (zehirli havuz) için idealdir. Sinyal sistemi ile birlikte kullanıldığında çok güçlüdür.

5.5 Kullanıcı Arayüzü (GUI) Mimarisi: Profesyonel ve Esnek Arayüzler

Bir oyunun kullanıcı arayüzü (GUI), oyuncu deneyiminin ayrılmaz bir parçasıdır. Orvix Engine'in sağlam GUI sistemi, her cihazda harika görünen, responsive ve etkileşimli arayüzler oluşturmanıza olanak tanır.

  1. `Control` Düğümlerinin Esnekliği: Responsive UI Tasarımı

    Orvix'te tüm arayüz elemanları `Control` düğümleridir. Bu düğümlerin **`Anchor` (Çapa)**, **`Margin` (Kenar Boşluğu)** ve **`Size Flags` (Boyut Bayrakları)** gibi güçlü özelliklerini kullanarak, farklı ekran boyutlarına ve çözünürlüklere otomatik olarak uyum sağlayan responsive arayüzler oluşturabilirsiniz. `Anchor`'lar, bir UI elementinin ekranın belirli bir kenarına, köşesine veya merkezine göre konumlanmasını sağlarken, `Size Flags`'ler bir elementin ebeveynine göre ne kadar genişleyip daralacağını belirler. Bu, oyununuzun farklı cihazlarda (mobil, tablet, masaüstü) sorunsuz çalışmasını ve her zaman harika görünmesini sağlar.

  2. Özel Temalar (Custom Themes) ve Stil Yönetimi: Tek Tuşla Yeniden Tasarım

    Oyununuzun tüm UI öğelerinin (butonlar, paneller, kaydırıcılar, metin kutuları) görünümünü ve hissini tek bir yerden yönetmek için **`Theme`** kaynaklarını kullanın. Bu, her bir UI düğümünün rengini, fontunu, kenarlığını veya boyutunu tek tek ayarlamak yerine, projeniz için global bir stil rehberi oluşturmanızı sağlar. Bir `Theme` kaynağı oluşturup içine farklı UI elementleri için stiller tanımlayabilirsiniz (örneğin, tüm butonların varsayılan rengi, fontu, hover efekti). Bu, oyununuzun markalaşma tutarlılığını sağlar ve tasarım değişikliklerini saniyeler içinde tüm arayüze uygulamanıza olanak tanır. GUI üzerinde hızla yineleme yapmak için vazgeçilmezdir.

  3. İstemci Tarafı Sinyalleri ve Kullanıcı Etkileşimleri: UI'ya Hayat Verme

    `Control` düğümleri, kullanıcı etkileşimlerini (tıklama, üzerine gelme, fare tekerleği, klavye girişi) tetiklemek için kendi zengin sinyal setine sahiptir. Bu sinyalleri (`pressed`, `mouse_entered`, `value_changed` vb.) scriptlerinize bağlayarak butonlara işlevsellik, kaydırıcılara tepkiler veya metin kutularına veri girişi yeteneği katın. Bu, oyuncu ile oyun arasındaki ana etkileşim yoludur. Örneğin, bir "Ayarlar" butonuna basıldığında bir ayarlar panelinin açılmasını veya bir "Çıkış" butonuna basıldığında oyunun kapanmasını sağlayabilirsiniz.

5.6 Oyun Verileri ve Kalıcı Depolama: Kaydetme ve Yükleme Sistemleri

Oyuncuların ilerlemesini kaydetmek ve daha sonra devam etmelerine izin vermek, modern bir oyun için temel bir özelliktir. Orvix Engine, bu verileri güvenli ve verimli bir şekilde yönetmek için çeşitli araçlar sunar.

  1. Kalıcı Veri Kaydı ve Yüklemesi: Oyun Durumunu Saklama

    FileAccess sınıfını kullanarak, oyuncu verilerini (puan, envanter, seviye ilerlemesi, ayarlar, kilidi açılmış özellikler) yerel dosyalara kaydetmeyi ve daha sonra bu verileri yüklemeyi öğrenin. **JSON** (JavaScript Object Notation) formatı, okunabilirliği ve platformlar arası uyumluluğu nedeniyle genellikle tercih edilir. Daha hassas veya büyük veriler için ikili (binary) formatlar da kullanılabilir. Oyunun kaydedilmesi ve yüklenmesi, oyuncu deneyimi için temel bir özelliktir ve oyuncuların oyununuzla uzun süre bağlı kalmasını sağlar. Verileri `user://` dizinine kaydetmek, kullanıcının sistemine özel bir dizinde güvenli ve yazılabilir bir konum sağlar.

    
    # Oyun Verilerini JSON Formatında Kaydetme ve Yükleme
    extends Node # Bu script bir GameManager veya AutoLoad'a eklenebilir.
    
    const KAYIT_DOSYASI_YOLU = "user://savegame.json"
    
    func oyunu_kaydet():
        # Kaydedilecek verileri bir Dictionary'de toplarız.
        var veri = {
            "puan": GlobalGameManager.puan,
            "can": GlobalGameManager.oyuncu_can_sayisi,
            "son_seviye": GlobalGameManager.mevcut_seviye,
            "envanter": GlobalGameManager.oyuncu_envanteri # List, Dictionary olabilir
        }
        
        # Dosyayı yazma modunda aç. Hata durumunu kontrol et.
        var dosya = FileAccess.open(KAYIT_DOSYASI_YOLU, FileAccess.WRITE)
        if dosya:
            # Dictionary'yi JSON string'ine dönüştür ve dosyaya yaz.
            dosya.store_string(JSON.stringify(veri))
            dosya.close()
            print("Oyun Başarıyla Kaydedildi!")
        else:
            print("Hata: Kayıt dosyası yazılamadı!")
    
    func oyunu_yukle():
        # Dosyanın varlığını kontrol et.
        if !FileAccess.file_exists(KAYIT_DOSYASI_YOLU):
            print("Kayıt dosyası bulunamadı, yeni oyun başlatılıyor.")
            return false
    
        # Dosyayı okuma modunda aç.
        var dosya = FileAccess.open(KAYIT_DOSYASI_YOLU, FileAccess.READ)
        if dosya:
            # Dosya içeriğini oku.
            var json_string = dosya.get_as_text()
            # JSON string'ini bir GDScript nesnesine (Dictionary) dönüştür.
            var parse_result = JSON.parse_string(json_string)
            
            if parse_result is Dictionary: # Başarılı ayrıştırma kontrolü
                var veri = parse_result
                # Global değişkenleri veya oyun durumunu yüklenen verilerle güncelle.
                # .get() metodunu varsayılan değerle kullanarak hatalardan kaçının.
                GlobalGameManager.puan = veri.get("puan", 0)
                GlobalGameManager.oyuncu_can_sayisi = veri.get("can", 3)
                GlobalGameManager.mevcut_seviye = veri.get("son_seviye", 1)
                GlobalGameManager.oyuncu_envanteri = veri.get("envanter", {})
                print("Oyun Başarıyla Yüklendi!")
                dosya.close()
                return true
            else:
                print("Hata: Kayıt dosyası içeriği geçersiz veya bozuk.")
                dosya.close()
                return false
        else:
            print("Hata: Kayıt dosyası okunamadı!")
            return false
    
    

5.7 Görsel Şaheserler: Shader'lar ile Grafik Büyüsü

Shader'lar, bir materyalin veya sahnenin piksel piksel nasıl çizileceğini belirleyen küçük programlardır. Kendi shader'larınızı yazarak, oyununuzda standart görsellerle elde edemeyeceğiniz benzersiz, dinamik ve görsel açıdan çarpıcı efektler yaratabilirsiniz. Bu, oyununuzu görsel olarak bir üst seviyeye taşımanın en güçlü yollarından biridir.

  1. Shader Kullanımı: Görsel Efektlerin Derinlikleri (GLSL ES)

    Orvix Engine'de shader'lar, OpenGL ES Shading Language (GLSL ES) söz dizimine benzer bir dil kullanılarak yazılır. Bir shader, genellikle bir `ShaderMaterial`'e atanır ve bir `Sprite2D`, `MeshInstance3D` veya hatta bir `Viewport`'a uygulanabilir. Yaygın kullanım alanları şunlardır:

    • **Su Yansımaları ve Dalgalanmalar:** Gerçekçi veya stilize su efektleri.
    • **Ekran Efektleri (Post-Processing):** Ekran titremesi (oyuncu hasar aldığında), renk düzeltmeleri (filtreler), bulanıklık veya film greni gibi efektler.
    • **Özel Işıklandırmalar:** Cel shading, çizgi film benzeri gölgelendirme veya dinamik neon ışık efektleri.
    • **Karakter Hasar Efektleri:** Karakterin hasar aldığında kırmızı yanıp sönmesi, şeffaflaşması veya dağılması.
    • **Yanma veya Erime Efektleri:** Objelerin yanarak veya eriyerek kaybolması.
    
    // shader_parlama.gdshader - Basit bir parlama/renklendirme shader'ı örneği
    shader_type canvas_item; // 2D objeler için (Sprite2D, Control vb.)
    // 3D objeler için 'shader_type spatial;' kullanılır.
    
    // Editörden ayarlanabilir uniform değişkenler.
    // 'hint_color' bir renk seçici, 'range_float' bir kaydırıcı sağlar.
    uniform vec4 parilti_renk: hint_color = vec4(0.0, 1.0, 1.0, 1.0); // Varsayılan turkuaz renk
    uniform float parilti_gucu: range_float(0.0, 5.0, 0.1) = 1.5; // Parlaklık gücü
    uniform float zaman_faktor = 0.0; # GDScript'ten güncellenebilir (örneğin _process içinde time değişkeni)
    
    // Fragment shader, her piksel için çalışır.
    void fragment() {
        // Pikselin orijinal rengini al. TEXTURE dahili bir değişkendir.
        // UV koordinatları doku üzerinde geçerli pikselin konumunu verir.
        vec4 renk = texture(TEXTURE, UV);
        
        // Şeffaf olmayan pikseller için efekti uygula.
        if (renk.a > 0.0) {
            // Orijinal rengin RGB kanallarına parıltı rengini gücüne göre ekle.
            renk.rgb += parilti_renk.rgb * parilti_gucu;
            
            // Zaman faktörünü kullanarak hafif bir animasyon ekle (örneğin titreşme).
            float dalgalanma = sin(zaman_faktor * 5.0 + UV.x * 10.0) * 0.1;
            renk.rgb += dalgalanma * parilti_gucu * 0.5;
        }
        
        // Son rengi piksele atıyoruz. COLOR, çıktının rengidir.
        COLOR = renk;
    }
    
    

    Bu shader'ı bir `Sprite2D`'ye uygulamak için: `Sprite2D`'yi seçin, İnceleyici panelinde `Material` özelliğine yeni bir `ShaderMaterial` atayın. Ardından `ShaderMaterial`'i seçip `Shader` özelliğine `.gdshader` dosyanızı sürükleyin. Artık uniform değişkenleri İnceleyici'den ayarlayarak shader'ı canlı olarak görebilirsiniz.

5.8 Proje Yönetimi ve Yayınlama: Oyununuzu Dünyaya Açma

Oyun geliştirmenin son aşaması, projeyi doğru bir şekilde yönetmek ve tamamlanmış ürünü oyunculara ulaştırmak. Bu süreç, sadece kod yazmaktan çok daha fazlasını içerir.

  1. Git ile Versiyon Kontrolü ve Ekip Çalışması (Vazgeçilmez)

    Profesyonel bir oyun geliştirme sürecinde, kodunuzu ve projenizin tüm varlıklarını yedeklemek, farklı versiyonlarını yönetmek ve ekip üyeleriyle sorunsuz bir şekilde çalışmak için **Git** gibi bir versiyon kontrol sistemi kullanmak kritik önem taşır. Orvix Engine, doğrudan Git entegrasyonuna sahiptir (Editör > Sürüm Kontrolü). Değişiklikleri takip etmek, eski versiyonlara geri dönmek, farklı özellikler üzerinde paralel çalışmak (branching) ve ekip üyeleri arasında kod çakışmalarını çözmek (merging) için Git'i öğrenmelisiniz. GitHub, GitLab veya Bitbucket gibi platformlar, projelerinizi depolamak ve yönetmek için popüler seçeneklerdir.

  2. Hata Ayıklama (Debugging) ve Loglama Teknikleri: Sorun Giderme Sanatı

    Oyununuzdaki hataları bulmak ve düzeltmek, geliştirme sürecinin büyük bir kısmını oluşturur. Orvix'in yerleşik **hata ayıklayıcı (debugger)** sekmesi, değişkenleri gerçek zamanlı olarak izlemenize, kodu durdurup adım adım çalıştırmanıza, kesme noktaları (breakpoints) ayarlamanıza ve çağrı yığınını (call stack) görmenize olanak tanır. Basit sorunları gidermek ve olayları izlemek için GDScript'teki `print()` fonksiyonunu kullanarak konsola mesajlar göndermek veya `push_warning()` / `push_error()` fonksiyonlarıyla özel uyarılar/hatalar oluşturmak harika bir başlangıçtır. Karmaşık hataları bulmak için hata ayıklayıcıyı etkin bir şekilde kullanmayı öğrenin.

  3. Farklı Platformlara Derleme (Export): Hedef Kitlenize Ulaşın

    Orvix Engine, oyununuzu farklı platformlara (Windows, macOS, Linux, Android, iOS, HTML5) kolayca derlemenizi sağlayan güçlü bir derleme (export) sistemine sahiptir. **Proje > Derle (Export)** menüsünden farklı platformlar için derleme ön tanımları (export presets) oluşturabilirsiniz. Her platform için özel ayarlar (örneğin çözünürlük, ikonlar, sıkıştırma, DRM) yapabilirsiniz. Hedef kitlenize ulaşmak ve oyununuzu farklı cihazlarda oynanabilir kılmak için bu adımı iyi anlamak ve her platform için test etmek önemlidir.

  4. Son Kontroller, Optimizasyon ve Paketleme: Yayınlanmaya Hazırlık

    Oyununuzu dünyaya yayınlamadan önce, son bir kez kapsamlı testler yapın. Tüm mekaniklerin doğru çalıştığından, hataların giderildiğinden ve oyunun akıcı olduğundan emin olun. Hata ayıklama kodlarını kaldırın, performansı tekrar test edin (profilleyici ile) ve son paketleme ayarlarınızı kontrol edin. Oyununuzun küçük boyutlu, hızlı yüklenebilir ve hedef platformun (Steam, Itch.io, Google Play Store, App Store) özel gereksinimlerini karşıladığından emin olun. Gerekirse kapalı veya açık beta testleri yaparak gerçek kullanıcılardan geri bildirimler toplayın ve bu geri bildirimleri değerlendirerek son rötuşları yapın. Oyununuzu en iyi şekilde sunmak için bu son adımlar hayati öneme sahiptir.

Tebrikler, Artık Bir Uzmansınız!

Bu devasa rehber serisi ile Orvix Engine'in temellerinden en ileri düzey uzmanlık konularına kadar birçok önemli konuyu derinlemesine öğrendin. Artık kendi hayalindeki oyunları tasarlayacak, programlayacak, optimize edecek ve dünyaya yayınlayacak bilgi ve beceriye sahipsin.

Unutma, oyun geliştirme sürekli bir öğrenme ve deneyimleme sürecidir. Kendi projelerine korkusuzca başla, Orvix topluluğuyla aktif olarak etkileşimde bulun, karşılaştığın her sorunu bir öğrenme fırsatına çevir ve her zaman yeni teknolojileri ve fikirleri denemekten çekinme. Senin gibi yetenekli geliştiricilerin yaratacağı yeni oyunları görmek için sabırsızlanıyoruz! Oyunlarını yaratmaya şimdi başla ve dijital dünyayı şekillendir!