SignalR İle Zar Atma Oyunu

Merhaba arkadaşlar, bu yazımızda SignalR ile ufak bir zar atma oyunu nasıl yapılır birlikte inceliyor olacağız.

Uygulama senaryomuz online casinolardaki oyun odalarına benzer şekilde olacak. Bir giriş ekranı ve bu ekranda girilne kullanıcı adı ve salon numarasına göre giriş yapılan bir oyun salonumuz olacak. Gelen oyun salonu ekranında aynı salona giren rakip oyuncu ile karışıklı sırayla zar atılacak ve 2 elin sonunda yüksek zar atan oyuncu kazanmış ve ilgili tebrik,geçmiş olsun mesajı oyunculara gösterilmiş olacak. Dilerseniz başlayalım.

NOT: Yazıyı çok uzatmamak amacıyla önemli noktaları belirterek bir anlatım yapacağım. Projeyi yazının sonuna ekleyeceğim Github linkinden indirip inceleyebilirsiniz.

1.Nugettan projemize SignalR kütüphanesini ekliyoruz.

2.Dosya ve klasörleri oluşturma ve yapılandırma işlemi

Projemizin kök dizininde Startup classı oluşturuyoruz.

[assembly: OwinStartupAttribute(typeof(SignalRZarAtma.Startup))]
namespace SignalRZarAtma
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

Hubs klasörü oluşturup klasörün içerisinde bir adet LoginOperationHub adında bir class oluşturuyoruz ve SignalR kütüphanesini kurunca gelen Hub classından inheritance(miras) alıyoruz

ConnectionIdGetir metodu istemcinin bağlantı idsini almamıza yarıyor. Yani bir istemiciyi diğer istemciden bu sayede ayırt edebiliyoruz.Bu metodu kişi özel işlem yapacağımız zaman, sıklıkla kullanıyor olacağız.

public class ZarOyunHub: Hub
{
        private string ConnectionIdGetir()
        {
            return Context.ConnectionId;
        }
}

Models adında bir klasör oluşturarak projemizde kullanacağımız Oyun ve OyuncuBilgi adında classlarımızı oluşturuyoruz.

    public class Oyun
    {
        public string KullaniciAdi { get; set; }
        public string ConnectionId { get; set; }
        public string SalonKodu { get; set; }
        public int Zar1 { get; set; }
        public int Zar2 { get; set; }
        public int Toplam
        {
            get { return Zar1 + Zar2; }
        }
        public bool Sira { get; set; }
    }
    public class OyuncuBilgi
    {
        public string KullaniciAdi { get; set; }
        public string ConenctionId { get; set; }
        public int Zar1 { get; set; }
        public int Zar2 { get; set; }
        public int ToplamPuan { get; set; }
    }

3.Giriş ekranını düzenleme

<script src="~/Scripts/jquery.signalR-2.4.1.js"></script>
<script src="~/signalr/hubs"></script>
<div class="row">
    <div class="col-md-12">
        <div id="divGiris">
            <div class="row">
                <div class="col-md-12">
                    <input type="text" placeholder="Kullanıcı Adı" class="form-control" id="txtKullaniciAdi" />
                </div>
            </div>
            <br />
            <div class="row">
                <div class="col-md-12">
                    <input type="text" placeholder="Salon Kodu" class="form-control" id="txtSalonKodu" />
                </div>
            </div>
            <div class="row">
                <div class="col-md-12">
                    <br />
                    <input type="button" class="btn btn-primary btn-block" value="Giriş Yap" id="btnGirisYap" />
                </div>
            </div>
        </div>

    </div>
</div>
<div class="row">
    <div class="col-md-12">
        <div id="divRakipOyuncuBekleniyor" style="display:none">
            <div class="alert alert-info" role="alert"><h3>Oyuncu katılması bekleniyor.</h3></div>
        </div>
    </div>
</div>
<div class="row">
    <div class="col-md-12">
        <div id="divRakipOyuncununSirasi" style="display:none">
            <div class="alert alert-warning" role="alert"><h3>Rakip oyuncunun oynaması bekleniyor.</h3></div>
        </div>
    </div>
</div>
<div class="row">
    <div class="col-md-12">
        <div id="divSiraSende" style="display:none">
            <main id="dice-body">
                <div id="tl" class="dot"></div>
                <div id="tc" class="dot"></div>
                <div id="tr" class="dot"></div>
                <div id="cl" class="dot"></div>
                <div id="cc" class="dot show"></div>
                <div id="cr" class="dot"></div>
                <div id="bl" class="dot"></div>
                <div id="bc" class="dot"></div>
                <div id="br" class="dot"></div>
            </main>
            <section>
                <button id="roll-btn">Zar At</button>
            </section>
        </div>
    </div>
</div>
<div class="row">
    <div class="col-md-12">
        <div id="divKazandiSonuc" style="display:none">
            <div class="alert alert-success" role="alert"><h3>Tebrikler Oyunu Kazandınız.</h3></div>
        </div>
    </div>
</div>
<div class="row">
    <div class="col-md-12">
        <div id="divYenildiSonuc" style="display:none">
            <div class="alert alert-danger" role="alert"><h3>Geçmiş Olsun Yenildiniz.</h3></div>
        </div>
    </div>
</div>
<div class="row">
    <div class="col-md-12">
        <div id="divBerabereSonuc" style="display:none">
            <div class="alert alert-info" role="alert"><h3>Berabere Kaldınız.</h3></div>
        </div>
    </div>
</div>

4.Salon Giriş İşlemleri

btnGirisYap butonuna tıklandığında girilen kullanıcı adı ve salon kodu Hubımızdaki oyuncuEkle metoduna iletilir.

$("#btnGirisYap").click(function () {
    var txtSalonAdi = $("#txtKullaniciAdi").val();
    var txtSalonKodu = $("#txtSalonKodu").val();
    bildirim.server.oyuncuEkle(txtSalonAdi, txtSalonKodu);

})

ZarOyunHub classına aşağıdaki kodları ekliyoruz.

        public static List<Oyun> oyuns = new List<Oyun>();

        public void OyuncuEkle(string kullaniciAdi, string salonKodu)
        {

            IHubContext context = GlobalHost.ConnectionManager.GetHubContext<ZarOyunHub>();
            if (!oyuns.Exists(x => x.SalonKodu == salonKodu))
            {
                oyuns.Add(new Oyun
                {
                    KullaniciAdi = kullaniciAdi,
                    ConnectionId = ConnectionIdGetir(),
                    SalonKodu = salonKodu,
                    Zar1 = 0,
                    Zar2 = 0,
                    Sira = false
                });
                context.Clients.Client(ConnectionIdGetir()).RakipOyuncuBekleniyor();
            }
            else if (oyuns.Exists(x => x.SalonKodu == salonKodu) && oyuns.Count(x => x.SalonKodu == salonKodu) == 1)
            {
                var oyuncu = oyuns.FirstOrDefault(x => x.SalonKodu == salonKodu);
                oyuncu.Sira = true;
                oyuns.Add(new Oyun
                {
                    KullaniciAdi = kullaniciAdi,
                    ConnectionId = ConnectionIdGetir(),
                    SalonKodu = salonKodu,
                    Zar1 = 0,
                    Zar2 = 0,
                    Sira = false
                });
                context.Clients.Client(ConnectionIdGetir()).RakipOyuncununSirasi();
                context.Clients.Client(oyuncu.ConnectionId).OyunaBasla();
            }
            else
            {
                context.Clients.Client(ConnectionIdGetir()).SalondaOyunDevamEdiyor();
            }
        }

Her salonda 2 oyuncu olacak şekilde bir tasarımımız mevcut. Yukarıdaki kod bloğunda girilen salonkodu listemizde daha önce kayıtlımı diye bakıyoruz. Kayıtlı değil ise listeye kullanıcı adı ve salon kodu kaydı yapılır ve salondaki ilk oyuncu olmuş oluruz. Sonrasında aynı salon kodu ile bir kullanıcı giriş yapmak istediğinde salon kodu var mı şeklinde kontrol yapılır ve salon kodunun listedeki sayısı 1 ise salondaki ikinci oyuncu salona giriş yapmış olur. 3. durumda yani else kısmında salonda 2 oyuncu vardır ve aynı salon kodunu 3. giren kişi olduysak gerçekleşecek durumdur.

Şimdi dilerseniz bu if bloglarının içerisindeki durumlara göre ön taraftaki yapılan gösterimleri inceleyelim.

İlk if bloğu yukarıda belirttiğimiz üzere salona giren ilk oyuncu olmamız durumunu ifade ediyordu ve bu bloğun sonunda aşağıdaki kod bloğu ile ön taraftaki gösterimi yapıyoruz.

Bu şu anlama geliyor ConnectionIdGetir metodu ile son giriş yapan kullanıcının connectionidsi alınır ve bu connectionidye sahip kullanıcının ekranında viewimizdeki rakipOyuncuBekleniyor functionı çalışır.

context.Clients.Client(ConnectionIdGetir()).RakipOyuncuBekleniyor()

rakipOyuncuBekleniyor functionundan önce viewmizde script tagi içerisine aşağıdaki eklemeyi yapıyoruz. Sonrasında çalışacak olan rakipOyuncuBekleniyor function’ ı ekliyoruz.

var bildirim;
var zarDeger = 0;

$(function () {
    bildirim = $.connection.zarOyunHub;
    bildirim.client.rakipOyuncuBekleniyor = function () {
        $("#divGiris").css("display", "none");
        $("#divRakipOyuncuBekleniyor").css("display", "block");
    }
})

Artık salondayız ve bize bir ekran gösteriyor. Bu ekranda rakip oyuncuyu beklediğimize dair yazı yazıyor.

Diyelim ki 2. kullanıcı da salona giriş yaptı bu durumda Hubumuzdaki OyuncuEkle metodunda yer alan else if bloğu çalışacak. Aşağıdaki kod bloğu ile Viewe değişikliğimizi gönderiyor olacağız.

Salona giriş yapan 2. oyuncu olduğunda oyun başlayacağı için giriş yapan 2.kullanıcıya RakipOyuncununSirasi functionı ile buna dair bir ekran gösteriyor olacağız. Tabi bunun yanında gelen salon kodunu listeye parametre olarak gönderip salondaki diğer oyuncunun ConnectionIdsini alarak bu kullanıcıya artık zar atması gerektiğini söylüyor olacağız.

context.Clients.Client(ConnectionIdGetir()).RakipOyuncununSirasi();
context.Clients.Client(oyuncu.ConnectionId).OyunaBasla();
    bildirim.client.rakipOyuncununSirasi = function () {
        $("#divGiris").css("display", "none");
        $("#divRakipOyuncuBekleniyor").css("display", "none");
        $("#divRakipOyuncununSirasi").css("display", "block");
    }
    bildirim.client.oyunaBasla = function () {
        $("#divGiris").css("display", "none");
        $("#divRakipOyuncuBekleniyor").css("display", "none");
        $("#divRakipOyuncununSirasi").css("display", "none");
        $("#divSiraSende").css("display", "block");
    }

Oyun devam ederken aynı salon kodunu 3. bir kullanıcı girdiğinde de else bloğuna düşüp aşağıdaki function ile ön taraftaki değişiklik işlemini yapıyor olacağız.

context.Clients.Client(ConnectionIdGetir()).SalondaOyunDevamEdiyor();
    bildirim.client.salondaOyunDevamEdiyor = function () {
        alert("Salonda oyun devam ediyor");
    }

5.Zar Atma ve Sonuç Gösterme İşlemleri

Hub’a PuanEkle metodumuzu ekliyoruz

        public void PuanEkle(string kullaniciAdi, string salonkodu, int puan)
        {
            IHubContext context = GlobalHost.ConnectionManager.GetHubContext<ZarOyunHub>();
            var rakipoyuncu = oyuns.FirstOrDefault(x => x.SalonKodu == salonkodu && x.KullaniciAdi != kullaniciAdi);
            var oyuncu = oyuns.FirstOrDefault(x => x.SalonKodu == salonkodu && x.KullaniciAdi == kullaniciAdi);
            List<OyuncuBilgi> salondakiOyuncular = new List<OyuncuBilgi>();
            List<string> kullanicilar = new List<string>();
            var liste = oyuns.Where(x => x.SalonKodu == salonkodu).ToList();
            if (oyuncu.Zar1 != 0 && oyuncu.Zar2 == 0)
            {
                oyuncu.Zar2 = puan;
                oyuncu.Sira = false;
                rakipoyuncu.Sira = true;
                context.Clients.Client(oyuncu.ConnectionId).SiraRakipte();
                context.Clients.Client(rakipoyuncu.ConnectionId).SiraSende();
            }
            if (oyuncu.Zar1 == 0)
            {
                oyuncu.Zar1 = puan;
                oyuncu.Sira = false;
                rakipoyuncu.Sira = true;
                context.Clients.Client(oyuncu.ConnectionId).SiraRakipte();
                context.Clients.Client(rakipoyuncu.ConnectionId).SiraSende();
            }

            if (oyuncu.Zar1 != 0 && oyuncu.Zar2 != 0 && rakipoyuncu.Zar1 != 0 && rakipoyuncu.Zar2 != 0)
            {
                foreach (var item in liste)
                {
                    salondakiOyuncular.Add(new OyuncuBilgi
                    {
                        KullaniciAdi = item.KullaniciAdi,
                        ConenctionId = item.ConnectionId,
                        Zar1 = item.Zar1,
                        Zar2 = item.Zar2,
                        ToplamPuan = item.Toplam
                    });
                    kullanicilar.Add(item.ConnectionId);
                }
                oyuns.RemoveAll(x => x.SalonKodu == salonkodu);
                if (salondakiOyuncular[0].ToplamPuan > salondakiOyuncular[1].ToplamPuan)
                {
                    context.Clients.Client(salondakiOyuncular[0].ConenctionId).KazananOyuncuGoster(salondakiOyuncular);
                    context.Clients.Client(salondakiOyuncular[1].ConenctionId).KaybedenOyuncuGoster(salondakiOyuncular);
                }
                else if (salondakiOyuncular[0].ToplamPuan == salondakiOyuncular[1].ToplamPuan)
                {
                    context.Clients.Clients(kullanicilar).BerabereSonucGoster(salondakiOyuncular);
                }
                else
                {
                    context.Clients.Client(salondakiOyuncular[1].ConenctionId).KazananOyuncuGoster(salondakiOyuncular);
                    context.Clients.Client(salondakiOyuncular[0].ConenctionId).KaybedenOyuncuGoster(salondakiOyuncular);
                }

            }
        }

Yukarıdaki blogda oyuncu ilk oyuncuyu rakipOyuncu 2. oyuncuyu ifade eder. Bu durum ilk oyuncunun Zar1 propetysindeki değer 0 ise zar atılmadığı ve sıranın onda olduğu anlamına gelir. Zar1 değeri 0 değil ve Zar2 propertysi kullanıcının 2.zarını attığı anlamına gelir Bu durumda aşağıdaki functionlar ile şu işlemler gerçekleşir

context.Clients.Client(oyuncu.ConnectionId).SiraRakipte();
context.Clients.Client(rakipoyuncu.ConnectionId).SiraSende();
bildirim.client.siraRakipte = function () {
    $("#divGiris").css("display", "none");
    $("#divRakipOyuncuBekleniyor").css("display", "none");
    $("#divSiraSende").css("display", "none");
    $("#divRakipOyuncununSirasi").css("display", "block");
}
bildirim.client.siraSende = function () {
    $("#divGiris").css("display", "none");
    $("#divRakipOyuncuBekleniyor").css("display", "none");
    $("#divRakipOyuncununSirasi").css("display", "none");
    $("#divSiraSende").css("display", "block");
}

Son olarak Hub’ ta her iki oyuncu da ikişer defa zar attıysa gerçekleşecek functionlar aşağıdaki gibidir.

  • KazananOyuncuGoster(salondakiOyuncular)
  • KaybedenOyuncuGoster(salondakiOyuncular)
  • BerabereSonucGoster(salondakiOyuncular)
   bildirim.client.berabereSonucGoster = function (oyuncular) {
        $("#divGiris").css("display", "none");
        $("#divRakipOyuncuBekleniyor").css("display", "none");
        $("#divRakipOyuncununSirasi").css("display", "none");
        $("#divSiraSende").css("display", "none");
        $("#divBerabereSonuc").css("display", "block");
        sonucGoster("divBerabereSonuc", oyuncular)
    }
    bildirim.client.kazananOyuncuGoster = function (oyuncular) {
        $("#divGiris").css("display", "none");
        $("#divRakipOyuncuBekleniyor").css("display", "none");
        $("#divRakipOyuncununSirasi").css("display", "none");
        $("#divSiraSende").css("display", "none");
        $("#divKazandiSonuc").css("display", "block");
        sonucGoster("divKazandiSonuc", oyuncular)
    }
    bildirim.client.kaybedenOyuncuGoster = function (oyuncular) {
        $("#divGiris").css("display", "none");
        $("#divRakipOyuncuBekleniyor").css("display", "none");
        $("#divRakipOyuncununSirasi").css("display", "none");
        $("#divSiraSende").css("display", "none");
        $("#divYenildiSonuc").css("display", "block");
        sonucGoster("divYenildiSonuc", oyuncular)
    }

Arkadaşlar yine uzun bir anlatım oldu. Bu yüzden gözden kaçırdığım, yeteri kadar üzerinde duramadığım yerler varsa yorumda belirtirseniz sevinirim.

Github Linki

https://github.com/MehmetAkifVurucu/SignalR-Zar-Atma-Oyunu

Bir sonraki yazıda görüşmek üzere

Related Post

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir