Angular 6 ve SignalR 2 ile Web’de Mobil Etkileşimli Hafıza Oyunu Yapma Part 3

Selamlar,

Bu makale Web’de Mobil Etkileşimli Hafıza Oyunu makalesinin 3.südür. Bu makaleye “Main.component.ts” sayfasında kullanılan önceki makalelerde anlatılmayan functionlar anlatılacaktır. Daha sonra da ControlPage’in kodlarına girilecektir.

CloneID(): Aynı server side tarafda olduğu gibi client side tarafda da, açılan resmin “ID” eşleniği bu method sayesinde bulunmaktadır. Data formatı sayısal olmak zorundadır. Bu durumda bir ID’nin eşleniği için nasıl bir algoritma yazmak gerektiğini, gelin hep beraber inceleyelim. Önceki makalede de bahsettiğim gibi, sayının eşleniği ile olan arasına yani ortasına ve sayının sonuna “0” konur. Tersi işlem için de sayı ortasından kesilir ve sondaki “0” rakamı atılır. Eğer seçilen karta ait sayının eşleniği diğer açılan kartın sayısal değeri ile eşit ise, aynı kartlar bulunmuş demektir.

Örnek: 17 sayısı => 170170 şeklinde tanımlanır. Eşlenik için => “170/170” şeklinde ortadan ayrılıp yarısı alınır. ==> “170” Son olarak sondaki “0” atılır => “17” değerine erişilir.

playAudio(): Seçilen oyuna göre arkada çalan müzik tamamen HTM5’in gücü sayesinde buradan ayarlanır.

  • “if (this.audio)” : Eğer çalan bir müzik var ise durdurulur yok ise ==> “this.audio = new Audio();” yeni bir audio dosyası yaratılır.
  • “this.audio.src” : Çalıcak müziğin yolu tanımlanır.
  • “this.audio.loop = true;” : Bitince tekrarlanması sağlanır.
  • “Category[this.categoryID] == “frozen” ? this.audio.volume = 0.2 : this.audio.volume = 0.8;” : Seçilen oyun tipine göre ses yüksekliği ayarlanır.
  • “this.audio.load();” : Ses dosyası yüklenir.
  • “this.audio.play();” : İlgili müzik çalınır.
  • Not: Safaride web sayfasında ilgili müziğin çalınabilmesi için “Safari / Settings / Setting For This Website / Allow All Auto Play” izninin verilmesi gerekmektedir.

playSucess(): Bu function eşlenik kartlar açıldığı zaman, başarıldığını belirten bir ses çalar. Bunun için ayrı bir functionın yazılmasının nedeni, arkada çalan müzikten tamamen bağımsız bir ses olması ve ilgili müziğin kesilmemesinin sağlanmasıdır. İlgili ses çalındığı zaman Html tarafında diğer sesin anlık kesildiğine dair bir hata mesajı alınmaktadır. Ama normal akışı etkilememektedir. Henüz çözüm bulunamamıştır.

getRandomInt(): Her oyun için farklı random çalınan 6 ile 9 arası ses dosyası bulunmaktadır. Bu function rastgele her oyun için farklı maximum sayıda ses dosyası arasından bir tanesinin alınması için kullanılır.

NotifyControlPage() : Main.component.ts sayfasında 3 farklı durum için bu function çağrılmıştır: Böylece oyunun gidişatı ile ilgili alınması gereken kararlar, MainPage’e beyin rolü verilerek aldırılmış ve ControlPage’e iletilmiştir. Bir diğer yöntem karar mekanizmasının 2 sayfa içinde ayrı ayrı yapılması olabilirdi. Bu hem kod tekrarına hem de ilerde sayfa yönetimine büyük bir yük getirebilirdi. Bu durumda tek negatif durum, socket’e daha fazla yük bindirilmesidir. Bu yüzden MainPage, ControlPage’in connectionID’sini bilmek zorundadır.

Karşılaşılabilecek Durumlar:

  1. Açılan 2 kart aynı ise.
  2. Tüm kartlar açıldı ise.
  3. Açılan 2 kart aynı değil ise.
  • “id” : Açılan kartın id’sidir.
  • “result” : Kartın eşleniği bulundu mu yoksa bulunamadı mı cavabıdır.
  • “isReset” : Eğer tüm kartlar açılmış ise “ture” değil ise “false” değerini alır. Böylece ControlPage içinde oyun yeniden başlar ya da devam eder.
  • “_connectionIDControlPage” : ControlPage’e ait ConnectionID değeridir. Böylece sayfayı taratan mobile cihaza, ilgili bildirimi yapılabilecektir.

SignalR Puzzle: Hub sınıfının “NotifyControlPage()” methodu, ilgili parametreler ile birlikte client side tarafından tetiklenir. Server Side tarafda anlatılmayan methodlar bu yazının devamında anlatılacaktır.

Services/PuzzleService: Bu servisin amacı, Puzzle amaçlı oyun kategorilerinin ve seçilen kategoriye ait kartların databaseden getirilmesini sağlamaktır.

  • “servicePath”: .net Core 2.0 WebApi projesine erişilecek makina IP’sidir.
  • “GetCategories()”: İstenen kategori bilgileri, Azure’daki DB’den WebApi servisini kullanarak çekilir.
  • “GetAllCards()” : Seçilen oyuna göre (“categoryID”), kartları isteyen Main sayfasının ConnectionID’si (connectionID) ve son olarak oyunun kazanılıp kazanılmadı bilgisi (isReset) parametreleri ile rastgele eşli 12 kart Azure DB’den sorgulanır.

main.css : Main.component.html sayfa üzerindeki tüm görseller bu css’i kullanmaktadır. Esas amaç Responsive bir sayfa yapmaktır.

Controlpage.Component.html:

QrBarcode okutulduktan sonra  örnek amaçlı : “localhost:4200/ControlPage/939d52ec-76d4-48f5-98e1-8c9e6c1a117f/1” bir siteye gidilir.

Öncelikle ilgili sayfaya gidilebilmesi için Angular tarafında routing yapılması gerekmektedir.

src/app/app.routes.ts: Tüm Url bazlı yönlendirme işlemleri aynı Mvc’de olduğu gibi bu sayfa üzerinden yapılmaktadır.

  • Ana route’a gelindiğinde, url’de hiç bir parametrenin olmayacağı için
    • path: ‘ ‘ : path boşa atanır.
    • redirectTo: ” ‘ ‘: Path’i boş olan component’a yönlendirilir.
    • pathMatch: ‘full’ : istenen koşulun tam karşılanması gerekmektedir.
  • path: ”, component: MainComponent  : Boş path “MainComponent”‘a yönlendirilmiştir. Kısacası ana sayfaya gelindiğinde “MainComponent” sayfası ile başlanır.
  • path: ‘ControlPage/:connectionID/:categoryID’, component: ControlPageComponent : Url satırına “ControlPage” ile başlayan bir url yazıldığında devamında connectionID ve categoryID parametreleri aynı Url içinde  var ise ControlPage sayfasına gidilir. Bu işlem QrBarcode okutulduğu zaman devreye girmektedir.

Controlpage.component.html: Cep telefonu tarafından kumanda edilen sayfadır.

  • Sayfa arka resmi için, gene burada “backImage” directive’i kullanılmıştır.
  • “<table class=”box” *ngIf=”cardList!=null”>” : Eğer servisten “cardList” listesi çekilmiş ise ilgili tablo ekrana basılır.
  • “<tr *ngFor=”let cards of cardList | pairs”>” : Mobile ekran üzerindeki kartlar gene custom yazılan “pairs” filter’ı ile ekrana 3×4 şeklinde basılmaktadır.
  • “<img [src]=”card.controlCardBgImage” alt=”{{card.name}}” [attr.isShow]=”card.isShow” [attr.isDone]=”card.isDone” name=”{{card.name}}” id=”{{card.id}}” class=’cardBack’ (click)=”OpenCard(card.id)” width=”98px” height=”135px”>” :

  • Ekrana basılacak kartın resmi “card.controlCardBgImage” propertysı ile tanımlanır. Kartın her zaman arkası gözükecektir.  En başta yukarıda görüldüğü gibi aktif kart gelecektir. Sadece açılan kartlar pasif şeklinde yukarıda görüldüğü gibi başka bir arka resme sahip olacaktır.
    • Alt ve Kart ismi =>”card.name” değişkeni ile açılıp açılmadığı “attr.isShow” değişkeni ile tanımlanmaktadır. Eşleniği bulunun kartların “attr.isDone” property’si “true“‘ya atanır. İlgili kart’a “cardBack” css adı verilmiştir.
    • Kart tıklanma durumunda “(click)=”OpenCard(card.id)” ilgili function’a tıklanan kartın ID’si ile gidilir.

Controlpage.component.ts (Part 1): Aşağıda görüldüğü gibi önce “import” dosyaları eklenmiştir :

  • Router,ActivatedRoute,Params : Url ile parametre olarak gelen “connectionID” ve “categoryID” değerleri alınır.
  • HubConnection : SignalR kütüphanesinin kullanılması için eklenmiştir.
  • PuzzleService : WebApi webservisleri işlemleri için eklenmiştir.

Category tablosundan gelen oyun listesi, Enum olarak client side’a da eklenmiştir. Son olarak global değişkenler OnInit() methodu içinde tepede tanımlanmıştır:

  • root: Seçilen oyuna göre resim veya ses dosyaları için gidilen ana Path’dir. Default “frozen” oyunu atanmıştır.
  • categoryID: Seçilen oyunun “categoryID”‘sinir. Default frozen’ın ==1 değeri atanmıştır.
  • connectionIDMainPage : Ana sayfaya ait signalR ConnectionID’sini temsil etmektedir.
  • _hubConnection : ControlPage sayfanın signalR ConnectionID’sidir.
  • cardList : Random olarak seçilen oyuna ait kart listesidir.
  • bgPath : Oyundaki base resim yoludur.
  • servicePath: .Net Core WebApi servisine erişilen sunucunun IP’sidir.
  • bgImage : Seçilen oyuna göre sayfanın arka thema’sıdır.
  • cardBgImage : Seçilen oyuna göre sıralanan kartların arka, yani kapalı iken ki resmidir.
  • cardBgDisabledImage : Seçilen kartın bir daha seçilmemesi için değiştirilen pasif görünümlü resmidir.

ControlPage constructor()’ ında ActivateRout ve PuzzleService kütüphanelerini dependency Injection ile almaktadır.

Controlpage.component.ts (Part 2):

  • this.route.params.subscribe((params: Params) : Url’den gelen parametre değerleri “connectionID”,”categoryID” alınır. “this.SetCategoryParameters()” methodu, yazının devamında incelenecektir.
  • this._hubConnection = new HubConnection(this.servicePath + “puzzle?key=control”) : SignalR “Puzzle” Hub sınıfına “?key=control” parametresi ile bağlanılmıştır. Bu parametre ile hangi sayfadan bağlanıldığı belirtilmiştir.
  • this._hubConnection .start() : Connection işlemi yapıldıktan sonra “this.service.GetAllCards()” methodu ile seçilen oyun kategorisine ait random kartlar, servisten çekilmektedir.
    • var data = result.forEach(card => { card.controlCardBgImage = this.cardBgImage; }) : Çekilen herbir kartın arka resmi, seçilen oyun kategorisine göre tek tek atanmaktadır.
    • this.cardList = result : Çekilen kart listesi “cardList[]” array değişkenine atanmaktadır.
    • this._hubConnection.invoke(“TriggerMainPage”, this.connectionIDMainPage, this._connectionId) : Kartların tamamı çekildikten sonra ana sayfada(mainpage), uyarılarak, main.component.ts’deki “Connected” function’ın tetiklenmesi sağlanmıştır. Böylece aynı kart destenin ana sayfa için de çekilmesi sağlanmıştır.
  • this._hubConnection.on(‘GetConnectionId’, (connectionId: string) => { : ControlPage, ilgili signalR sınıfına connect olunca, “GetConnectionId()” methodu aldığı yeni connectionID değeri ile trigger edilir. Ve yeni alınan connectinonID değeri, “_connectionId” değişkenine atanır.
  • this._hubConnection.on(‘NotifyControlPage’, (id: number, result: boolean, isReset: boolean = false) => { : Ana sayfada bir kart açıldığı zaman, bir eşinin bulunup bulunmadığı, ya da tüm kartların açılıp açılmadığı kararı “ControlPage”‘e bırakılmaz. İlgili bussines burada işletilip, Controlpage sayfasına bu method ile bildirilir. Böylece kod tekrarından kaçınılmış ve aynı şeyin 2 farklı yerde yapılmasının önüne geçilmiş olunur.
    • Eğer “isReset==true” ise, tüm kartların eşleniği bulunmuş ve yeni bir oyuna geçilecek demektir. Bu durumda “this.service.GetAllCards()” methodu ile random yeni 12 kart isteğinde bulunulmuştur.
    • else if (result) { : Eğer açılan 2 kart aynı ama tüm kartlar daha açılmamış ise, seçilen 2 kartın arka resmi disabled (“f.controlCardBgImage = this.cardBgDisabledImage”) yani bir daha seçilemez hale getirilir (“if.isDone = true”).
    • else { : Seçilen 2 kart eşlenik değil demektir. Ve 1sn beklendikten sonra:
      • ” this.cardList.filter(cd => cd.isShow == true && cd.isDone == false).forEach(f => {” : İlgili kartların yani o an denenen 2 kartın arka resmi eski haline getirilir. Ayrıca “isShow” ve “isDone” değişkenleri false’a çekilir.

Controlpage.component.ts (Part 3):

  • SetCategoryParameters(): Seçilen oyun tipine göre ==> Dizilen kartların arka(cardBgImage) ve pasif resmi(cardBgDisabledImage), Controlpage sayfasının arka teması (bgImage) dinamik olarak değiştirilmektedir.
  • OpenCard() : Methodu ile tıklanan kartın açılması amaçlanmıştır :
    • if (this.cardList.filter(cd => cd.isShow && cd.isDone == false).length < 2) : “isShow”  ile açılan kartın olup olmadığı, “isDone” ile eşleniği açılmış bir kartın olup olmadığına bakılır. Güvenlik amaçlı 2’den fazla kartın açılmaması için bu tipde kart sayısının <2 olmasına bakılmıştır.
    • if (!card.isShow) { : Tıklanan bir kartın üst üste tıklanmamsı için güvenlik adımı konulmuştur.
    • card.isShow = true; card.controlCardBgImage = this.cardBgDisabledImage : Tıklanan kartın arka rengi pasife çekilir.”isShow” yani gösterildi property’si ture’ya atanır.
    • this._hubConnection.invoke(“OpenCard”, this.connectionIDMainPage, id) : Tıklanarak açılan kart bilgisi, websayfasına yani main.component page’e, signalR “OpenCard()” methodu tetiklenerek bildirilir.

Puzzle : Hub (Part 2): Son olarak aşağıda görülen, SignalR Hub sınıfımızın diğer methodlarını inceleyelim.

  • TriggerMainPage: Control sayfası signalR sınıfına bağlandığı zaman, almış olduğu connectionID değerini Main sayfasına iletmek için kullanılan bir methoddur.
  • OpenCard() : Control sayfasında bir kart tıklandığında, aynı kartın main.component.html sayfasında da açılması için tetiklenen signalR Hub sınıfına ait methoddur.
  • NotifyControlPage() : Main sayfasında bir kart açıldığında, eşleniğinin bulunduğu veya bulunamadığı ya da tüm kartların açıldığı bilgisini, Control sayfasına bildiren methoddur.

Geldik bir makale serisinin daha sonuna. Bu makalede .Net Core, Angular6, SignalR 2.0 ve HTML5’in gücü de kullanılarak, mobile etkileşimli bir oyununun nasıl yazılabileceği hakkında, bir fikir sahibi olduk. Daha değişik tipte, yine mobile etkileşimli bir başka uçak oyunu, aynı GitHub source kodunda bulunmaktadır. Bu oyun hakkındaki fikirlerinizi de yorum satırlarında belirtirseniz sevinirim.

Yeni bir makalede görüşmek üzere hepinize hoşçakalın.

Source Code : https://github.com/borakasmer/PuzzleWithSignalRAndAngular

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

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