Aplicativo tolo para a Windows Store


Paul Cezanne, jogadores de cartão

Era uma vez, no Windows 95, havia um jogo do Microsoft Hearts. Jogando cartas online, com adversários em todo o mundo. Se a memória me servir bem, no Windows for Workgroups 3.11 (sim, encontrei todos esses artefatos!) Havia uma versão para reprodução em uma rede local usando o chamado NetDDE.

Eu não tive que escolher um jogo de cartas por um longo tempo. Como se costuma dizer, o que é rico ... A ponte de alto nível e a preferência desapareceram devido à sua completa ignorância. Só havia uma coisa: desaparecer como um tolo estúpido.

A situação foi complicada pelo fato de que até agora nunca estive envolvido no desenvolvimento de um "back-end". O Google me levou direto ao lugar certo - SignalR .

Aqui, quero dizer algumas palavras entusiasmadas ao SignalR. Uma biblioteca bem documentada que se encaixa perfeitamente às minhas necessidades. Bores dirá que é apenas para Windows, bem, deixe-os cerrarem os dentes com inveja. Embora pareça haver clientes de farm coletivo para iOS, não estudei esse problema em detalhes.

A próxima pergunta é hospedagem. Então eu não pensei muito, Azure estava sob meus braços.

Então o que eu queria?


  • A maneira como os jogadores se conectam deve ser semelhante ao Microsoft Hearts. Os jogadores se conectam um a um, assim que a quantidade certa é obtida - o jogo começa. Por mim, decidi me limitar a um jogo individual - e ninguém empata!
  • Haverá poucos jogadores no início - como eles se descobrem? Então surgiu a idéia de enviar a todos que desejam jogar notificações push no momento em que alguém inicia o aplicativo e se conecta ao servidor do jogo. Para não estrangular os usuários com empurrões, ele fez uma restrição "não mais que uma vez a cada N minutos".
  • Quero estatísticas detalhadas, prêmios, conquistas, etc.
  • Quero cartões de desenhos diferentes
  • Quero brincar com meu conhecido, e não com alguém "a quem Deus enviou".

O que eu uso com o Azure?


  • O AppService é, de fato, um aplicativo ao qual todos os clientes se conectam.
  • Servidor SQL + banco de dados SQL - para armazenar estatísticas de jogos.

Só isso.

Recentemente, também usei o serviço de distribuição de notificações por push. Mas parecia caro (10 dólares por mês); além disso, devido à falha de faturamento da Microsoft, eu paguei por esses dois serviços por mais de um ano! O apoio violento levou ao fato de reconhecerem o erro e oferecerem até um mês de compensação. Depois de algum tempo, abandonei completamente esse serviço, adicionando outra tabela ao meu banco de dados para armazenar assinantes para envio e enviá-los pessoalmente a partir do aplicativo principal.

Neste momento, o custo de hospedagem mensal cerca de 400 r. Este é apenas o custo do servidor SQL. Tenho um pequeno tráfego de saída e ele se encaixa nos 5 GB gratuitos por mês.

Desenvolvimento


O desenvolvimento ocorreu no Visual Studio 2015, para o cliente foi utilizada a estrutura MVVM MVVM light.

Um pequeno servidor "cozinha" (estetas e os fracos de coração é melhor não assistir)


conexão do usuário, pressionando
public override Task OnConnected() { if (((DateTime.Now - LastPush).TotalSeconds) > 360) { LastPush = DateTime.Now; Task.Run(() => SendNotifications()); } return base.OnConnected(); } 


criando um jogo anônimo
 /// <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(); } } 


criação de uma sala de jogos
 /// <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(); } } 


espiar a carta superior no baralho
 /// <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(); } } } 


envie uma mensagem para um oponente
 /// <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(); } } } 



Sobre o cliente


Para identificar os players, a funcionalidade LiveId foi usada primeiro e depois a API do Graph. No primeiro lançamento do aplicativo, o jogador é convidado a fornecer acesso à sua conta (a partir dele, apenas o nome e o chamado ID anônimo, que se parecem com isso: "ed4dd29dda5f982a"). No entanto, o jogador pode jogar anonimamente, mas as estatísticas de seus jogos não são mantidas.

Para cada jogador não anônimo são armazenados:

1. data do primeiro jogo / data do último jogo
2. nome / apelido do jogador
3. número de jogos disputados / quantos ganharam
4. último endereço IP
5. prêmios recebidos

Se dois jogadores não anônimos jogam no jogo, antes de começar, recebo as estatísticas dos jogos desses jogadores em particular (quantos jogos eles jogaram um com o outro e quem ganhou quanto). Para fazer isso, o ID anônimo recebido é usado na consulta SQL.

Na captura de tela no canto superior esquerdo, você pode ver um exemplo (clicável):



Captura de tela das estatísticas gerais (clicável):



Além disso, uma "competição" está sendo realizada entre países (jogadores anônimos também participam aqui, as informações são obtidas do endereço IP):



Os jogadores podem trocar mensagens curtas.

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

Um exemplo de um manipulador de situação "Pego as cartas e o oponente me adiciona outro 'depois" ":

 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)); 

Sobre prêmios, cookies, etc.


Todos os meses, os cinco primeiros jogadores que obtiveram mais vitórias recebem o emblema "Pela captura de Berlim" . Os participantes do top 50 são premiados com distintivos pelo melhor percentual de vitórias (também cinco). Além disso, existem emblemas para ganhar por "express" (uma situação em que no último lance você tem 2, 3 ou 4, digamos, seis ou valetes). Então eles colocaram tudo sobre a mesa de uma só vez e você - muito bem. Existem cookies para a vitória, quando o oponente lhe der uma "lista". Ele também recebe um reconfortante, com uma caveira e ossos.

Sobre qualquer funcionalidade adicional


O aplicativo é gratuito, mas possui vários "pães" adicionais decorados como Compras InApp:

  • agrupando suas cartas por naipe e dicas durante o jogo (quando você precisa acertar ou atirar, cartas adequadas são empurradas para cima)
  • a capacidade de não mostrar ao oponente quantas cartas você tem em suas mãos. Em uma situação normal, ele vê
  • a oportunidade de sempre começar o jogo primeiro. Caso contrário, o primeiro movimento é jogado aleatoriamente.
  • a capacidade de ver as cartas derrotadas no jogo
  • a oportunidade de espreitar o baralho uma vez por jogo e descobrir a próxima carta
  • a capacidade de trapacear. Você pode vencer três vezes por jogo ou jogar a carta errada, geralmente qualquer. Mas o oponente tem a oportunidade, depois de perceber isso, de devolver a carta errada para você.

Conclusão


Como resultado do desenvolvimento deste aplicativo, eu:

  • conheceu SignalR
  • SQL atualizado na memória (consultas, procedimentos armazenados, funções)
  • Aprendeu como hospedar aplicativos no Azure
  • Aturdido de fazer o "tolo".

Pergunta


E a situação com Habré com a dispersão de dinheiro de um helicóptero através da distribuição de códigos promocionais às pessoas interessadas de maneira pessoal? Se eles não derem um chute por isso, entre em contato.

Update


YouTube: grave alguns jogos

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


All Articles