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.
1 2 3 4 5 6 7 8 9 |
public CloneID(ID: number): number { if (ID < 100) { return parseInt(ID + "0" + ID + "0"); } else { var firstID = ID.toString().substring(0, ID.toString().length / 2); return parseInt(firstID.substring(0, firstID.length - 1)); } } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
audio: any; playAudio(url: string) { if (this.audio) { this.audio.pause(); //this.audio = null; } else { this.audio = new Audio(); } this.audio.src = "/assets/sounds/" + this.soundRoot + url + this.soundExtension; this.audio.loop = true; Category[this.categoryID] == "frozen" ? this.audio.volume = 0.2 : this.audio.volume = 0.8; this.audio.load(); this.audio.play(); } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
audioSucess: any; playSucess(url) { if (this.audioSucess) { this.audioSucess.pause(); //this.audio = null; } else { this.audioSucess = new Audio(); } this.audioSucess.src = "/assets/sounds/" + url; this.audioSucess.volume = 0.2; this.audioSucess.load(); this.audioSucess.play(); } |
1 2 3 |
getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } |
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:
- Açılan 2 kart aynı ise.
- Tüm kartlar açıldı ise.
- 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.
1 2 3 4 5 6 |
NotifyControlPage(id: number, result: boolean, isReset: boolean = false) { this._hubConnection.invoke("NotifyControlPage", this._connectionIDControlPage, id, result, isReset) .then(result => { console.log("Card Result Notify To Control Page"); }); } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import { Injectable } from '@angular/core'; import { Http, Response } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; @Injectable() export class PuzzleService { servicePath = "http://192.168.1.234:5000/"; constructor(private http: Http) { } public GetCategories() { return this.http.get(this.servicePath + "api/Puzzles") .map(result => result.json()); } public GetAllCards(connectionID: string, categoryID: number, isReset: boolean = false) { return this.http.get(this.servicePath + "api/Puzzles/" + categoryID + "/" + connectionID + "/" + isReset) .map(result => result.json()); } } |
main.css : Main.component.html sayfa üzerindeki tüm görseller bu css’i kullanmaktadır. Esas amaç Responsive bir sayfa yapmaktır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
.box { position: absolute; top: 2%; left: 24%; height: 95%; /*width: 55%;*/ /* 4K Monitor - Phone(Not Full Screen) Safari */ width: 60%; /* Screen - Phone (Not Full Screen) Safari */ } .win { width:1200px; height:850; position:fixed; margin-left:-600px; /* half of width */ margin-top:-425px; /* half of height */ top:50%; left:50%; } button { position: absolute; display: inline-block; padding: 0; margin: 0; vertical-align: top; width: 254px; height: 204px; border-radius: 30%; box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19); -webkit-transition-duration: 0.4s; /* Safari */ transition-duration: 0.4s; outline:none; /* border: none; For Google */ border: none; /* For Safari*/ /*For Play Music On Safari => Safari / Settings / Setting For This Website / Allow All Auto Play*/ background-color:white; /* Set Default Color For Safari. Don't need at Chrome*/ } button:hover { background-color: rgb(135, 210, 245); color: white; } .buttonmenu { display: inline-block; padding: 0; margin: 0; vertical-align: top; width: 254px; height: 204px; border-radius: 30%; box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19); -webkit-transition-duration: 0.4s; /* Safari */ transition-duration: 0.4s; outline:none; /* border: none; For Google */ border: none; /* For Safari*/ /*For Play Music On Safari => Safari / Settings / Setting For This Website / Allow All Auto Play*/ background-color:white; /* Set Default Color For Safari. Don't need at Chrome*/ } .buttonmenu:hover { background-color: rgb(135, 210, 245); color: white; } #moana{ position: relative; margin-left: -15%; margin-top: 13%; width: 15%; height: 15%; } #frozen{ position: relative; margin-top: 26%; width: 15%; height: 15%; margin-left: 15%; } .barcode{ width:22%; height: 22%; margin-top: 15%; margin-left: 0%; } .cardback{ height: 100%; width: 100%; } #txt_area{ background-image:url(/assets/images/cloud3.png); background-color:transparent; background-repeat:no-repeat; color:white; width:200px; padding-left:20px; padding-right:10px; border:0px; padding-top:7px; padding-bottom:10px; font-size:90px; font: bold; text-align: center; overflow:hidden; resize: none; } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import { ModuleWithProviders } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; import { ControlPageComponent } from './controlpage.component'; import { MainComponent } from './main.component'; // Route Configuration export const routes: Routes = [ { path: '', component: MainComponent }, { path: 'ControlPage/:connectionID/:categoryID', component: ControlPageComponent }, { path: '', redirectTo: '', pathMatch: 'full' }, ]; export const routing: ModuleWithProviders = RouterModule.forRoot(routes); |
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.
1 2 3 4 5 6 7 8 9 10 11 |
<div class="body" backImage="{{ bgImage }}"> <table class="box" *ngIf="cardList!=null"> <!-- <tr *ngFor="let cardRow of cardList"> --> <tr *ngFor="let cards of cardList | pairs"> <!-- <td *ngFor="let card of cardRow"> --> <td *ngFor="let card of cards"> <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"> </td> </tr> </table> </div> |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { HubConnection } from '@aspnet/signalr'; import { PuzzleService } from '../Services/Indexservice'; enum Category { frozen = 1, moana = 2 } export class ControlPageComponent implements OnInit { root: string = "frozen"; categoryID: number = 1; connectionIDMainPage: string; _connectionId: string; private _hubConnection: HubConnection; cardList: Array<FrozenPuzzle> bgPath = "/assets/images/" + this.root + "/"; servicePath = "http://192.168.1.234:5000/"; bgImage: string = this.bgPath + "controlback.jpg" cardBgImage: string = this.bgPath + "controlCardback.png?ver=1.09"; cardBgDisabledImage: string = this.bgPath + "controlDisabledCardback.png"; constructor(private route: ActivatedRoute, private service: PuzzleService) { } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
ngOnInit() { this.route.params.subscribe((params: Params) => { this.connectionIDMainPage = params['connectionID']; //MainPageConnectionID this.categoryID = params['categoryID']; this.SetCategoryParameters(Category[this.categoryID]); console.log("MainPageConnectionID:" + this.connectionIDMainPage); }); this._hubConnection = new HubConnection(this.servicePath + "puzzle?key=control"); this._hubConnection .start() .then(() => { console.log("Hub_Connection Start!"); //Eğer önce kartları çekmez isek Dictionary Liste'e Lock koymak lazım. Aynı key 2 kere yazılmaya çalışılıyor. //Get Cards this.service.GetAllCards(this.connectionIDMainPage, this.categoryID).subscribe(result => { var data = result.forEach(card => { card.controlCardBgImage = this.cardBgImage; }); console.log(JSON.stringify(data)); this.cardList = result //this.GroupTable(result, 3); }, err => console.log(err), () => { console.log("Card List Loaded"); this._hubConnection.invoke("TriggerMainPage", this.connectionIDMainPage, this._connectionId) .then(result => { console.log("MainPage Triggered"); }); } ) }) .catch(err => console.log('Error while establishing connection :(')); this._hubConnection.on('GetConnectionId', (connectionId: string) => { this._connectionId = connectionId; console.log("ConnectionID :" + this._connectionId); }); this._hubConnection.on('NotifyControlPage', (id: number, result: boolean, isReset: boolean = false) => { if (isReset) { //Get Cards this.service.GetAllCards(this.connectionIDMainPage, this.categoryID).subscribe(result => { var data = result.forEach(card => { card.controlCardBgImage = this.cardBgImage; }); console.log(JSON.stringify(data)); this.cardList = result //this.GroupTable(result, 3); }, err => console.log(err), () => { console.log("Card List Reset"); } ) } else if (result) { this.cardList.filter(cd => cd.isShow && cd.isDone == false).forEach(f => { f.controlCardBgImage = this.cardBgDisabledImage; f.isDone = true; }) } else { setTimeout(() => this.cardList.filter(cd => cd.isShow == true && cd.isDone == false).forEach(f => { f.controlCardBgImage = this.cardBgImage; f.isShow = false; f.isDone = false; }), 1000) } }); } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
SetCategoryParameters(category: string) { switch (category) { case "moana": { this.bgPath = "/assets/images/" + category + "/"; this.bgImage = this.bgPath + "controlback.jpg" this.cardBgImage = this.bgPath + "controlCardback.png?ver=1.09"; this.cardBgDisabledImage = this.bgPath + "controlDisabledCardback.png"; break; } case "frozen": { this.bgPath = "/assets/images/" + category + "/"; this.bgImage = this.bgPath + "controlback.jpg" this.cardBgImage = this.bgPath + "controlCardback.png?ver=1.09"; this.cardBgDisabledImage = this.bgPath + "controlDisabledCardback.png"; break; } } } OpenCard(id) { if (this.cardList.filter(cd => cd.isShow && cd.isDone == false).length < 2) { var card = this.cardList.filter(card => card.id == id)[0]; //Üst üste tıklanamasın if (!card.isShow) { card.isShow = true; card.controlCardBgImage = this.cardBgDisabledImage; this._hubConnection.invoke("OpenCard", this.connectionIDMainPage, id) .then(result => { console.log("Command MainPage OpenCard"); }); } } } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public Task TriggerMainPage(string connectionIDMainPage, string connectionIDControlPage) { return Clients.Client(connectionIDMainPage).SendAsync("Connected", connectionIDControlPage); } public Task OpenCard(string connectionID, int ID) { return Clients.Client(connectionID).SendAsync("OpenCard", ID); } public Task NotifyControlPage(string controlConnectionID, int ID, bool result, bool isReset = false) { return Clients.Client(controlConnectionID).SendAsync("NotifyControlPage", ID, result, isReset); } |
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
Son Yorumlar