Fool App pour le Windows Store


Paul Cezanne, joueurs de cartes

Il était une fois, dans Windows 95, il y avait un jeu Microsoft Hearts. Jouer aux cartes en ligne, avec des adversaires du monde entier. Si la mémoire me sert bien, alors dans Windows pour Workgroups 3.11 (oui, j'ai trouvé tous ces artefacts!) Il y avait une version pour jouer sur un réseau local en utilisant le soi-disant NetDDE.

Je n'ai pas eu à choisir un jeu de cartes depuis longtemps. Comme on dit, ce qui est riche ... Le pont de haut vol et la préférence ont disparu en raison de leur ignorance totale. Il ne restait plus qu'une chose: disparaître comme un idiot stupide.

La situation était compliquée par le fait que jusqu'à présent je n'ai jamais été impliqué dans le développement d'un «backend». La recherche sur Google m'a conduit au bon endroit - SignalR .

Ici, je veux dire quelques mots enthousiastes à SignalR. Une bibliothèque bien documentée qui correspond parfaitement à mes besoins. Bores dira que ce n'est que pour Windows, eh bien, laissez-les grincer des dents avec envie. Bien qu'il semble qu'il existe des clients de ferme collective pour iOS, je n'ai pas étudié ce problème en détail.

La prochaine question est l'hébergement. Alors je n'ai pas réfléchi longtemps, Azure était sous mes bras.

Alors qu'est-ce que je voulais?


  • La façon dont les joueurs se connectent doit être similaire à Microsoft Hearts. Les joueurs se connectent un par un, dès que la bonne somme est gagnée - le jeu commence. Pour ma part, j'ai décidé de me limiter à un match en un contre un - et personne ne tire!
  • Il y aura peu de joueurs au tout début - comment se découvrent-ils? Puis l'idée est venue d'envoyer à tous ceux qui veulent jouer des notifications push au moment où quelqu'un lance l'application et se connecte au serveur de jeu. Afin de ne pas étrangler les utilisateurs avec des poussées, il a fait une restriction «pas plus d'une fois toutes les N minutes».
  • Je veux des statistiques détaillées, des prix, des réalisations, etc.
  • Je veux des cartes de différents designs
  • Je veux jouer avec ma connaissance, et non avec quelqu'un "que Dieu a envoyé".

Qu'est-ce que j'utilise avec Azure?


  • AppService est, en fait, une application à laquelle tous les clients se connectent.
  • Serveur SQL + base de données SQL - pour stocker les statistiques du jeu.

C’est tout.

Récemment, j'ai également utilisé leur service de distribution de notifications push. Mais cela semblait cher (10 dollars par mois), en plus, il s'est avéré qu'en raison d'un problème de facturation de Microsoft, j'avais payé ces deux services pendant plus d'un an! L'aboutissement du soutien a conduit au fait qu'ils ont reconnu l'erreur et ont offert jusqu'à un mois d'indemnisation. Après un certain temps, j'ai complètement abandonné ce service, ajoutant une autre table à ma base de données pour stocker les signataires pour push et les envoyer moi-même depuis l'application principale.

A cette époque, le coût d'hébergement mensuel d'environ 400 r. Ce n'est que le coût du serveur SQL. J'ai un petit trafic sortant et il s'inscrit dans les 5 Go gratuits par mois.

Développement


Le développement a eu lieu à Visual Studio 2015, pour le client le framework MVVM MVVM light a été utilisé.

Un petit serveur "cuisine" (les esthètes et les faibles de coeur vaut mieux ne pas regarder)


connexion utilisateur, poussée
public override Task OnConnected() { if (((DateTime.Now - LastPush).TotalSeconds) > 360) { LastPush = DateTime.Now; Task.Run(() => SendNotifications()); } return base.OnConnected(); } 


créer un jeu anonyme
 /// <summary> ///   .        /// </summary> /// <returns>ID  </returns> async public Task<String> ConnectAnonymous(PlayerInformation pi) { MainSemaphore.WaitOne(); try { string res = String.Empty; string p_ip = Context.Request.GetHttpContext().Request.UserHostAddress; if (NextAnonymGame == null) { NextAnonymGame = new FoolGame(Context.ConnectionId, pi, p_ip, false); res = NextAnonymGame.strGameID; } else { await NextAnonymGame.Start(Context.ConnectionId, pi, p_ip); ActiveGames.Add(NextAnonymGame.strGameID, NextAnonymGame); res = NextAnonymGame.strGameID; NextAnonymGame = null; } return res; } finally { MainSemaphore.Release(); } } 


création d'une salle de jeux
 /// <summary> ///    /// </summary> /// <returns>   </returns> public String CreatePrivateGame(PlayerInformation pi) { MainSemaphore.WaitOne(); try { string p_ip = Context.Request.GetHttpContext().Request.UserHostAddress; FoolGame game = new FoolGame(Context.ConnectionId, pi, p_ip, true); WaitingPrivateGames.Add(game.strGameID, game); return game.PrivatePass; } finally { MainSemaphore.Release(); } } 


jetez un œil à la carte du dessus dans le jeu
 /// <summary> ///     - /// </summary> /// <param name="gameid"></param> /// <returns></returns> async public Task PeekCard(string gameid) { FoolGame game = null; game = ActiveGames.FirstOrDefault(games => games.Value.strGameID == gameid).Value; if (game != null) { game.GameSemaphore.Wait(); await Task.Delay(35); try { await Clients.Caller.PeekedCard(game.Deck.Peek()); } finally { game.GameSemaphore.Release(); } } } 


envoyer un message à un adversaire
 /// <summary> ///  /// </summary> /// <param name="gameid">ID  (  )</param> /// <param name="ChatMessage"> </param> /// <returns></returns> async public Task ChatMessage(string gameid, string ChatMessage) { FoolGame game = null; game = ActiveGames.FirstOrDefault(games => games.Value.strGameID == gameid).Value; if (game != null) { game.GameSemaphore.Wait(); await Task.Delay(35); try { await Clients.OthersInGroup(gameid).ChatMessage(ChatMessage); } finally { game.GameSemaphore.Release(); } } } 



À propos du client


Pour identifier les joueurs, la fonctionnalité LiveId a d'abord été utilisée, puis l'API Graph. Lors du premier lancement de l'application, le joueur est invité à donner accès à son compte (je n'en retiens que le nom et le soi-disant identifiant anonyme, qui ressemble à ceci: "ed4dd29dda5f982a"). Cependant, le joueur peut jouer de manière anonyme, mais les statistiques de ses parties ne sont pas conservées.

Pour chaque joueur non anonyme sont stockés:

1. date du premier match / date du dernier match
2. nom / pseudo du joueur
3. nombre de parties jouées / combien d'entre elles ont gagné
4. dernière adresse IP
5. prix reçus

Si deux joueurs non anonymes jouent dans le jeu, alors avant qu'il ne commence, je reçois les statistiques des jeux de ces joueurs particuliers (combien de jeux ils ont joué ensemble et qui a gagné combien). Pour ce faire, l'ID anonyme reçu est utilisé dans la requête SQL.

Dans la capture d'écran en haut à gauche, vous pouvez voir un exemple (cliquable):



Capture d'écran des statistiques générales (cliquable):



De plus, un «concours» est organisé dans tous les pays (des joueurs anonymes y participent également, les informations sont extraites de l'adresse IP):



Les joueurs peuvent échanger de courts messages.

 FoolHubProxy.On<string>("ChatMessage", (chatmessage) => synchrocontext.Post(delegate { PlayChatSound(); ShowMessageToast(chatmessage); }, null)); 

Un exemple de gestionnaire de situation "Je prends des cartes et l'adversaire m'en ajoute un autre" après "":

 FoolHubProxy.On<byte, bool>("TakeOneMoreCard", (addedcard, lastcard) => synchrocontext.Post(delegate { CardModel card = new CardModel(addedcard, DeckIndex); CardsOnTable_Low.Add(card); OpponentsCards.Remove(OpponentsCards.Last()); if (lastcard) { AppMode = AppModeEnum.defeated; } }, null)); 

À propos des prix, cookies, etc.


Chaque mois, les cinq premiers joueurs qui ont remporté le plus de victoires reçoivent un badge «Pour la capture de Berlin» . Les participants dans le top 50 reçoivent des badges pour le meilleur pourcentage de victoires (également cinq). De plus, il y a des badges pour gagner «express» (une situation où au dernier coup vous avez 2, 3 ou 4, disons six ou jacks). Ensuite, ils ont tout mis sur la table d'un seul coup et vous - bravo. Il y a des cookies pour la victoire, lorsque l'adversaire vous donne une "liste". Il en reçoit également un réconfortant, avec un crâne et des os.

À propos de toute fonctionnalité supplémentaire


L'application est gratuite, mais elle contient plusieurs "petits pains" supplémentaires décorés comme des achats InApp:

  • regrouper vos cartes par couleur et astuces pendant le jeu (lorsque vous devez frapper ou lancer, les cartes appropriées sont poussées vers le haut)
  • la possibilité de ne pas montrer à l'adversaire combien de cartes vous avez entre les mains. Dans une situation normale, il le voit
  • la possibilité de toujours commencer le jeu en premier. Sinon, le premier coup est joué au hasard.
  • la possibilité de voir les cartes battues dans le jeu
  • l'occasion de jeter un coup d'œil dans le jeu une fois par partie et de découvrir la prochaine carte
  • la capacité de tricher. Vous pouvez battre 3 fois par partie ou lancer la mauvaise carte, généralement n'importe laquelle. Mais l'adversaire a la possibilité, après l'avoir remarqué, de vous retourner la mauvaise carte.

Conclusion


Suite au développement de cette application, j'ai:

  • rencontré SignalR
  • SQL actualisé en mémoire (requêtes, procédures stockées, fonctions)
  • J'ai appris à héberger des applications sur Azure
  • Abasourdi de jouer le "fou".

Question


Et qu'en est-il de la situation avec Habré avec la dispersion d'argent d'un hélicoptère en distribuant des codes promotionnels aux personnes intéressées dans un cadre personnel? S'ils ne donnent pas un coup de pied pour cela, alors contactez.

Mettre à jour


YouTube: enregistrez quelques jeux

Source: https://habr.com/ru/post/fr442746/


All Articles