Skip to main content

Unity Oyun Yapısı (Host)

Bu döküman, Unity oyununuzun RemoteNex sunucusu ile veri alışverişi yapabilmesi için gereken GameManager yapısını ve veri işleme mantığını açıklar.

Sunucumuz, oyununuza anlık olarak string (metin) tabanlı veri paketleri gönderir. Oyununuzun bu paketleri doğru şekilde parçalaması (parse etmesi), oyuncuları yönetmesi ve hareketleri işlemesi gerekmektedir.

Temel Veri Protokolü

Sistemimizle tam uyumlu bir oyun geliştirmek için kodunuzda 3 temel fonksiyonun bulunması zorunludur.

Protokol Kuralı

Sunucudan gelen tüm veriler : (iki nokta) karakteri ile ayrıştırılmış bir string formatındadır. Oyununuzdaki tüm mantık, bu stringi : karakterine göre bölerek anlamlı parçalara ayırmak üzerine kuruludur.

İki ana veri tipi vardır:

  1. Oyuncu Listesi Verisi: Odaya biri girdiğinde veya çıktığında gelir.
  2. Hareket (Input) Verisi: Oyuncu bir tuşa bastığında gelir.

1. Ana Giriş Kapısı: HandleInput

Oyununuzun yönetici sınıfında (GameManager), sunucudan gelen ham veriyi karşılayan public bir fonksiyon bulunmalıdır. Bu fonksiyon, gelen verinin türüne karar veren bir "trafik polisi" gibi çalışır.

Görevi: Gelen verinin içinde :PLAYERS: mi yoksa :MOVE: mu geçtiğini kontrol etmek ve ilgili alt fonksiyona yönlendirmektir.

public void HandleInput(string data)
{
// 1. Boş veri kontrolü (Güvenlik)
if (string.IsNullOrEmpty(data)) return;

// 2. Eğer veri oyuncu listesi içeriyorsa
if (data.Contains(":PLAYERS:"))
{
// Oyuncu listesini güncelleme fonksiyonunu çağır
UpdateIds(data);
}
// 3. Eğer veri bir hareket komutu içeriyorsa
else if (data.Contains(":MOVE:"))
{
// Hareketi işleme fonksiyonunu çağır
ProcessMovement(data);
}
}

2. Oyuncu Yönetimi: UpdateIds

Öncelikle manager kodumuzun en başına bir liste tanımlamalıyız (List<string> connectedPlayerIds = new List<string>();).

Sunucumuz, odadaki oyuncu durumunda en ufak bir değişiklik olduğunda (biri katıldığında veya bağlantısı koptuğunda), odadaki tüm güncel oyuncu listesini size yeniden gönderir.

  • Sunucudan Gelen Veri: ODA_KODU:PLAYERS:OYUNCU1_DATA,OYUNCU2_DATA...
  • Tekil Oyuncu Verisi: İSİM:ROL:CONNECTION_ID
    • Örnek: Ali:M:b49a-2c91 (İsim: Ali, Rol: Master, ID: b49a-2c91)

Görevi:

  1. Gelen stringi parçalamak.
  2. Listede olup sahnede olmayan oyuncuları oyuna dahil etmek (Spawn).
  3. Sahnede olup yeni gelen listede olmayan oyuncuları oyundan atmak (Destroy).
void UpdateIds(string message)
{
// ADIM 1: Veriyi Temizle
// Mesajın başındaki "ODA_KODU:PLAYERS:" kısmını atıp sadece oyuncu verilerini alıyoruz.
int splitIndex = message.IndexOf(":PLAYERS:");
string listPart = message.Substring(splitIndex + 9); // ":PLAYERS:" sonrasını al

// Eğer liste boşsa, odada kimse kalmamış demektir.
if (string.IsNullOrEmpty(listPart))
{
connectedPlayerIds.Clear(); // Kimse yoksa listeyi temizle
return;
}

// ADIM 2: Oyuncuları Ayırma
// Oyuncular birbirinden virgül (,) ile ayrılır.
string[] players = listPart.Split(',');

// Geçici olarak sahnedeki oyuncuları sıfırlayıp yeniden dolduracağımız bir mantık kuruyoruz.
connectedPlayerIds.Clear();

// ADIM 3: Her Bir Oyuncuyu İşleme
foreach (var p in players)
{
// Oyuncu verisi: "İsim:Rol:ID" şeklindedir. İki nokta ile bölüyoruz.
string[] details = p.Split(':');

// Veri bütünlüğü kontrolü (En az 3 parça olmalı)
if (details.Length < 3) continue;

// Bizim için en önemli parça 2. indisteki CONNECTION_ID'dir.
// Çünkü oyuncuyu bu benzersiz ID ile tanıyacağız.
string pId = details[2];

// Bu ID'yi yerel listemize ekliyoruz.
connectedPlayerIds.Add(pId);

// NOT: Burada kendi oyun mantığınıza göre;
// Eğer bu ID sahnede yoksa Instantiate (Yaratma) işlemi yapmalısınız.
}
}

Elbette, işte "Hareket İşleme" ve "Özet Kontrol Listesi" kısımları. Yine kod blokları için ``` etiketini kullandım.

Markdown

3. Hareket İşleme: ProcessMovement

Bir oyuncu kontrolcüden tuşa bastığında sunucu bu veriyi, basan kişinin kimliğiyle birleştirip size gönderir.

  • Sunucudan Gelen Veri: GÖNDEREN_ID:MOVE:AKSİYON:DURUM
  • Örnek: b49a-2c91:MOVE:UP:PRESS (b49a-2c91 kimlikli oyuncu, YUKARI tuşuna BASTI).

Görevi:

  1. Veriyi parçalayarak kimin bastığını (GÖNDEREN_ID) bulmak.
  2. Hangi tuşa bastığını (AKSİYON) ve ne yaptığını (DURUM) algılamak.
  3. Bu komutu sahnedeki doğru objeye uygulamak.
void ProcessMovement(string data)
{
// ADIM 1: Veriyi Parçalama
// Veri ":" ile ayrılır.
string[] parts = data.Split(':');
// Güvenlik: Eksik paket gelirse işlemeyi durdur.
if (parts.Length < 4) return;

// ADIM 2: Verileri Değişkenlere Atama
string senderId = parts[0]; // Kim? (Connection ID)
string dir = parts[2]; // Ne? (UP, DOWN, LEFT, RIGHT, FIRE vb.)
string state = parts[3]; // Nasıl? (PRESS - Basıldı, RELEASE - Bırakıldı)

// ADIM 3: Değere Dönüştürme (Örnek Mantık)
// Oyununuzda tuşa basılınca 1, bırakılınca 0 değerini kullanabilirsiniz.
float val = 0;
if (state == "PRESS" || state == "DOWN")
{
// Yön UP ise +1, DOWN ise -1 verelim (Pong oyunu örneği)
val = (dir == "UP") ? 1 : -1;
}
else
{
// RELEASE (Bırakma) durumunda değer 0 olur (Durma).
val = 0;
}

// ADIM 4: Hedef Oyuncuyu Bulma
// Elimizdeki senderId'nin listemizde kaçıncı sırada olduğuna bakıyoruz.
int playerIndex = connectedPlayerIds.IndexOf(senderId);

// Eğer bu ID listemizde yoksa (Tanımsız oyuncu), işlemi iptal et.
if (playerIndex == -1)
{
Debug.LogWarning($"⛔ TANIMSIZ ID: {senderId}");
return;
}

// ADIM 5: Hareketi Uygulama
// Örneğin; Listede 0. sıradaki kişi Sol Raket, 1. sıradaki Sağ Rakettir.
if (playerIndex == 0)
{
// Player 1 değişkenini güncelle (Örn: moveP1 = val)
// moveP1 = val;
}
else if (playerIndex == 1)
{
// Player 2 değişkenini güncelle (Örn: moveP2 = val)
// moveP2 = val;
}
}

Özet Kontrol Listesi

Sisteme entegre olacak bir oyun geliştirirken şunlara dikkat etmelisiniz:

  • GameManager: Kodunuzda HandleInput gibi public bir giriş fonksiyonu olmalı.
  • ID Takibi: Oyuncuları sunucudan gelen ConnectionId (Benzersiz Kimlik) ile takip etmelisiniz. Sadece isme göre işlem yapmayın.
  • Sıralama: UpdateIds fonksiyonunda oyuncuları bir Listeye (List<string>) ekleme sıranız, onların oyundaki yerini (Player 1, Player 2) belirler.
  • Parse Mantığı: Verileri her zaman : karakterine göre Split ederek işlemelisiniz.

Bir sonraki adımda, oyuncuların kullanacağı Mobil Kontrolcü Yapısını nasıl kuracağımızı göreceğiz.