CaYaDev Logo
  • Ana Sayfa
  • Projeler
  • Paylaşımlar
  • Destek
  • Profil
    Ayarlar Çıkış
    Giriş Kayıt Ol
Paylaşımlara Dön

Socket.IO ile Oda Tabanlı Gerçek Zamanlı Oyun Geliştirmek: Kelime Sayar'dan Dersler

CaYatur C
Paylaşan CaYatur Yönetici hesabı · @CaYatur
14.07.2026 19:30
Web Geliştirme
0
Socket.IO ile Oda Tabanlı Gerçek Zamanlı Oyun Geliştirmek kapak.png

Socket.IO ile Oda Tabanlı Gerçek Zamanlı Oyun Geliştirmek: Kelime Sayar'dan Dersler

Kelime Sayar, arkadaş gruplarının oda kurup birlikte oynadığı, gerçek zamanlı bir kelime oyunu — ve benim Socket.IO ile ilgili bildiğim her şeyi sahada öğrendiğim proje. "Mesaj gönder, mesaj al" örneklerinden gerçek bir çok oyunculu sisteme giden yol; kopan bağlantılar, sahipsiz kalan odalar, aynı anda iki cihazdan bağlanan oyuncular ve "oyun bitti ama kazanan kim?" tartışmalarıyla dolu. Bu yazıda o yoldan damıtılmış mimari dersleri paylaşıyorum.

Oda modeli: Socket.IO'nun en doğru soyutlaması

Socket.IO'nun oda (room) kavramı, oyuncu gruplarını izole etmenin doğal yoludur. Bir soket bir odaya katılır; o odaya yayınlanan her olay yalnızca üyelerine gider:

io.on('connection', (socket) => {
  socket.on('odaya-katil', ({ odaKodu, oyuncuAdi }) => {
    socket.join(odaKodu);
    socket.data.oda = odaKodu;
    socket.data.ad = oyuncuAdi;
    io.to(odaKodu).emit('oyuncu-katildi', { ad: oyuncuAdi });
  });
});

Kritik tasarım kararı şu: oda durumu (state) soketlerde değil, sunucuda ayrı bir yapıda yaşamalı. Soket nesnesine oyun verisi asıldığında, bağlantı koptuğu anda veri de gider. Benim kurulumumda her odanın durumu (oyuncular, skorlar, tur bilgisi, son aktivite zamanı) bellek içi bir Map'te ve kalıcılık gereken kısmı SQLite'ta tutulur; soketler yalnızca "bu kullanıcı şu odada" eşlemesini taşır.

Sunucu otoritesi: istemciye asla skor sordurmayın

Çok oyunculu sistemlerin demir kuralı: istemci niyet bildirir, sunucu karar verir. İstemciden "şu kelimeyi buldum, 8 puan ekle" mesajı kabul ederseniz, puanı 8000 olarak gönderen ilk meraklı oyuncuyla tanışmanız uzun sürmez.

socket.on('kelime-gonder', ({ kelime }) => {
  const oda = odalar.get(socket.data.oda);
  if (!oda || oda.durum !== 'oyunda') return;        // oyun gerçekten sürüyor mu?
  if (!oda.siradakiOyuncu === socket.id) return;      // sıra gerçekten onda mı?
  const puan = kelimeyiDogrula(kelime, oda.harfler);  // kelime gerçekten geçerli mi?
  if (puan > 0) {
    oda.skorlar[socket.id] += puan;
    io.to(oda.kod).emit('skor-guncellendi', oda.skorlar);
  }
});

Her olayda üç doğrulama: oyun durumu, sıra sahipliği, hamle geçerliliği. Bu üçlü kontrol kalıbı, hile girişimlerinin yanı sıra arayüz hatalarından doğan tutarsız istekleri de (çifte tıklama, gecikmiş paket) sessizce süzer.

Oda tabanlı gerçek zamanlı oyun mimarisi: istemciler, odalar ve sunucu durumu

En zor problem: kopan bağlantılar

Gerçek dünyada bağlantılar sürekli kopar: telefon cebe girer, asansöre binilir, Wi-Fi el değiştirir. İlk sürümümde oyuncunun soketi koptuğu anda oyuncuyu odadan atıyordum — ve oyunlar, birinin interneti üç saniye titrediği için dağılıyordu.

Doğru desen, zarif bekleme süresi (grace period):

socket.on('disconnect', () => {
  const oda = odalar.get(socket.data.oda);
  if (!oda) return;
  // Hemen atma: oyuncuyu "bağlantı koptu" olarak işaretle
  oda.oyuncular[socket.data.ad].durum = 'koptu';
  io.to(oda.kod).emit('oyuncu-durumu', { ad: socket.data.ad, durum: 'koptu' });

  // 60 saniye içinde dönmezse kalıcı olarak çıkar
  setTimeout(() => {
    if (oda.oyuncular[socket.data.ad]?.durum === 'koptu') {
      oyuncuyuCikar(oda, socket.data.ad);
    }
  }, 60_000);
});

Dönen oyuncu için de bir "yeniden bağlanma" yolu gerekir: istemci, oda kodu ve kendisine verilmiş bir oyuncu kimliğiyle gelir; sunucu mevcut durumu (mevcut-durum olayı ile skorlar, tur, kalan süre) tek pakette gönderir. Arayüz bu paketi alınca kaldığı yerden devam eder. Bu iki parça — bekleme süresi ve durum senkronizasyonu — oyuncu deneyimini "bağlantım koptu, oyun bitti"den "üç saniye dondu, devam ettim"e çevirir.

Bir de köşe durumu var: kalan herkes koptuysa oyun ne olacak? Bizim kuralımız: oda boşaldığında oyun duraklatılır, süre sayacı durdurulur; bekleme süresi içinde kimse dönmezse oyun "tamamlanmadı" olarak kapatılır ve geçici skorlar kaydedilmez. Bu kararı baştan vermezseniz, yarıda kalan oyunların skor tablosunu kirletmesiyle uğraşırsınız.

Hayalet odalar: sessiz bellek sızıntısı

Oda tabanlı her sistemin kaderi: oyuncular gelir, oynar, gider — ve odalar kalır. Süresi dolmuş odaları temizlemeyen bir sunucu, haftalar içinde binlerce ölü kaydın ve zamanlayıcının altında ezilir.

Çözüm iki katmanlı:

  1. Son aktivite damgası. Odadaki her anlamlı olay (katılma, hamle, mesaj) odanın sonAktivite alanını günceller.
  2. Periyodik süpürücü. Birkaç dakikada bir çalışan bir görev, belirli süredir aktivitesi olmayan odaları kapatır, üyelerine bilgi verir ve hem bellekten hem veritabanından siler.
setInterval(() => {
  const simdi = Date.now();
  for (const [kod, oda] of odalar) {
    if (simdi - oda.sonAktivite > ODA_OMRU_MS) {
      io.to(kod).emit('oda-kapandi', { neden: 'inaktivite' });
      odalar.delete(kod);
    }
  }
}, 5 * 60_000);

Süpürücüyü yazarken bir ayrıntıya dikkat: oda kapanırken o odaya bağlı zamanlayıcılar (tur süresi sayaçları, bekleme süreleri) da iptal edilmeli. setTimeout referanslarını oda nesnesinde tutup kapanışta clearTimeout ile temizlemezseniz, ölü odanın sayacı dakikalar sonra ateşlenip var olmayan bir odaya yayın yapmaya çalışır — loglarınızda açıklaması zor hatalar olarak karşınıza çıkar.

Olay tasarımı: az, anlamlı, sürümlenebilir

İlk sürümde her küçük değişiklik için ayrı olay tanımlamıştım: skor-arti, sure-azaldi, oyuncu-yazdi... Zamanla bu, istemci ile sunucunun birbirine kırk yerden bağlandığı kırılgan bir yapıya dönüştü. Şimdi kuralım şu: istemciden sunucuya niyet olayları (kelime-gonder, tura-basla), sunucudan istemciye durum olayları (mevcut-durum, skor-guncellendi). Durum olayları her zaman eksiksiz veri taşır; istemci hiçbir zaman "parça parça topladığı" bilgiyle durum kurmaz. Bu yaklaşım, yeniden bağlanmayı da bedavaya getirir: dönen oyuncuya aynı mevcut-durum olayını göndermek yeterlidir.

Sonuç

Socket.IO ile oda tabanlı bir oyun yazmak, kütüphaneyi öğrenmekten çok dağıtık sistem disiplinini öğrenmektir: durum sunucuda yaşar, istemci yalnızca niyet bildirir, her bağlantının kopabileceği varsayılır ve kaynaklar (odalar, zamanlayıcılar) açıldığı gibi kapatılır. Kelime Sayar'da bu derslerin her birini bir hata raporu sayesinde öğrendim; siz baştan bu desenlerle kurarsanız, oyuncularınız "internetim koptu, her şey gitti" yerine "bir an dondu, devam etti" der — ve gerçek zamanlı bir oyunda bundan daha iyi bir iltifat yoktur.

Ek Görseller

Socket.IO ile Oda Tabanlı Gerçek Zamanlı Oyun Geliştirmek
Büyütmek için tıklayın

Diğer Paylaşımlar

Web Geliştirme

Sağlam Bir REST API Nasıl Tasarlanır?

Sağlam Bir REST API Nasıl Tasarlanır? Bir API, uygulamanızın dış dünyaya açılan kapısıdır. İyi tasarlanmış bir API'yi kullanan geliştirici,

30 Mayıs 2026
Web Geliştirme

Web Sitesi Performansını Artırmanın Yolları

Web Sitesi Performansını Artırmanın Yolları Bir web sayfasının ilk üç saniyede açılmaması, ziyaretçilerin önemli bir kısmının sekmeyi kapatm

30 Mayıs 2026
Sunucu Yönetimi

Node.js Sitenizi Cloudflare Arkasında Yayınlamak: Sertifikalar, Gerçek IP ve Önbellek

Node.js Sitenizi Cloudflare Arkasında Yayınlamak: Sertifikalar, Gerçek IP ve Önbellek Bu site, ilk günden beri Cloudflare arkasında çalışıyo

16 Haziran 2026
Güvenlik

Express.js Uygulamanızı Güvene Almak: Oturumlar, CSRF ve Hız Sınırlama

Express.js Uygulamanızı Güvene Almak: Oturumlar, CSRF ve Hız Sınırlama Express ile bir uygulamayı ayağa kaldırmak yarım saat sürer; onu inte

14 Haziran 2026

Tüm paylaşımları görüntüle →

1 / 1

CaYaDev

CaYaDev — kişisel projelerimi, kod örneklerimi ve teknoloji içeriklerimi paylaştığım platform. Geliştiriciler için kaynak ve ilham kaynağı.

Hızlı Bağlantılar

  • CaYaDev Projeleri
  • CaYaDev Paylaşımları
  • Destek
  • Hakkımızda

İletişim

  • İletişim
  • Gizlilik Politikası
  • Kullanım Şartları
  • Sorumluluk Reddi

CaYaDev Topluluğu

CaYaDev ile geliştirici topluluğuna katılın ve projelerimizden ilham alın.

Uygulama Portalı

© 2026 CaYaDev. Tüm hakları saklıdır.