Aplicación tonta para la tienda de Windows


Paul Cezanne, Jugadores de cartas

Érase una vez, en Windows 95 había un juego de Corazones de Microsoft. Jugando a las cartas en línea, con oponentes de todo el mundo. Si la memoria me funciona bien, entonces en Windows for Workgroups 3.11 (sí, ¡encontré todos estos artefactos!) Había una versión para jugar en una red local usando el llamado NetDDE.

No tuve que elegir un juego de cartas durante mucho tiempo. Como dicen, lo que es rico ... El puente elevado y la preferencia se desvanecieron debido a su completa ignorancia. Solo quedaba una cosa: desaparecer como un estúpido tonto.

La situación se complicó por el hecho de que hasta ahora nunca he estado involucrado en el desarrollo de un "backend". Buscar en Google me llevó directamente al lugar correcto: SignalR .

Aquí quiero decir algunas palabras entusiastas a SignalR. Una biblioteca bien documentada que se adapta perfectamente a mis necesidades. Bores dirá que es solo para Windows, bueno, déjelos apretar los dientes con envidia. Aunque parece que hay clientes de granjas colectivas para iOS, no estudié este problema en detalle.

La siguiente pregunta es el alojamiento. Entonces no pensé mucho, Azure estaba bajo mis brazos.

Entonces, ¿qué quería?


  • La forma en que los jugadores se conectan debería ser similar a los Corazones de Microsoft. Los jugadores se conectan uno por uno, tan pronto como se gana la cantidad correcta, comienza el juego. Por mi parte, decidí limitarme a un juego uno a uno, ¡y nadie empata!
  • Habrá pocos jugadores al principio, ¿cómo se conocen unos de otros? Luego surgió la idea de enviar a todos los que quieran jugar notificaciones push en el momento en que alguien inicie la aplicación y se conecte al servidor del juego. Para no estrangular a los usuarios con empujones, hizo una restricción "no más de una vez cada N minutos".
  • Quiero estadísticas detalladas, premios, logros, etc.
  • Quiero tarjetas de diferentes diseños.
  • Quiero jugar con mis conocidos, y no con nadie "a quien Dios envió".

¿Qué uso con Azure?


  • AppService es, de hecho, una aplicación a la que se conectan todos los clientes.
  • Servidor SQL + base de datos SQL: para almacenar estadísticas del juego.

Eso es todo.

Recientemente, también utilicé su servicio de distribución de notificaciones push. Pero parecía caro (10 dólares al mes), además, resultó que debido a la falla de facturación de Microsoft, ¡había pagado por estos dos servicios durante más de un año! El apoyo contundente llevó al hecho de que reconocieron el error y ofrecieron hasta un mes de compensación. Después de un tiempo, abandoné completamente este servicio, agregué otra tabla a mi base de datos para almacenar firmantes para enviar y enviarlos yo mismo desde la aplicación principal.

En este momento, el costo de alojamiento mensual de unos 400 r. Este es solo el costo de SQL Server. Tengo un pequeño tráfico saliente y cabe en los 5 GB gratuitos por mes.

Desarrollo


El desarrollo tuvo lugar en Visual Studio 2015, para el cliente se utilizó el MVVM framework MVVM light.

Un pequeño servidor "cocina" (estetos y el corazón débil es mejor no mirar)


conexión de usuario, empujando
public override Task OnConnected() { if (((DateTime.Now - LastPush).TotalSeconds) > 360) { LastPush = DateTime.Now; Task.Run(() => SendNotifications()); } return base.OnConnected(); } 


creando un juego 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(); } } 


creación de una sala de juegos
 /// <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(); } } 


asoma la carta superior en el mazo
 /// <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(); } } } 


enviar un mensaje a un 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 el cliente


Para identificar a los jugadores, primero se utilizó la funcionalidad LiveId, luego la API Graph. En el primer lanzamiento de la aplicación, se invita al jugador a proporcionar acceso a su cuenta (de ella tomo solo el nombre y la llamada identificación anónima, que se parece a esto: "ed4dd29dda5f982a"). Sin embargo, el jugador puede jugar de forma anónima, pero luego no se guardan las estadísticas de sus juegos.

Para cada jugador no anónimo se almacenan:

1. fecha del primer juego / fecha del último juego
2. nombre / apodo del jugador
3. número de juegos jugados / cuántos ganaron
4. última dirección IP
5. premios recibidos

Si dos jugadores no anónimos juegan en el juego, antes de que comience, obtengo las estadísticas de los juegos de estos jugadores (cuántos juegos jugaron entre ellos y quién ganó cuánto). Para hacer esto, la identificación anónima recibida se usa en la consulta SQL.

En la captura de pantalla en la esquina superior izquierda puedes ver un ejemplo (cliqueable):



Captura de pantalla de estadísticas generales (clicable):



Además, se lleva a cabo una "competencia" en todos los países (los jugadores anónimos también participan aquí, la información se toma de la dirección IP):



Los jugadores pueden intercambiar mensajes cortos.

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

Un ejemplo de un controlador de situación "Tomo cartas, y el oponente me agrega otro 'despué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)); 

Sobre premios, cookies, etc.


Cada mes, los primeros cinco jugadores que obtuvieron la mayor cantidad de victorias reciben una insignia "Por la captura de Berlín" . Los participantes en el top 50 reciben insignias por el mejor porcentaje de victorias (también cinco). Además, hay insignias para ganar "express" (una situación en la que en el último movimiento tienes 2, 3 o 4, por ejemplo, seis o jotas). Luego pusieron todo sobre la mesa de un solo golpe y tú, bien hecho. Hay cookies para la victoria, cuando el oponente te da una "lista". También consigue uno reconfortante, con una calavera y huesos.

Sobre cualquier funcionalidad adicional


La aplicación es gratuita, pero tiene varios "bollos" adicionales decorados como Compras InApp:

  • Agrupar sus cartas por palo y puntas durante el juego (cuando necesita golpear o lanzar, las cartas adecuadas se empujan hacia arriba)
  • la capacidad de no mostrarle al oponente cuántas cartas tienes en tus manos. En una situación normal, él lo ve.
  • la oportunidad de comenzar siempre el juego primero. De lo contrario, el primer movimiento se juega al azar.
  • la capacidad de ver las cartas vencidas en el juego
  • la oportunidad de echar un vistazo al mazo una vez por juego y descubrir la siguiente carta
  • La capacidad de hacer trampa. Puedes ganar 3 veces por juego o tirar la carta equivocada, generalmente cualquiera. Pero el oponente tiene la oportunidad, habiendo notado esto, de devolverte la carta equivocada.

Conclusión


Como resultado del desarrollo de esta aplicación, yo:

  • se reunió con SignalR
  • SQL actualizado en la memoria (consultas, procedimientos almacenados, funciones)
  • Aprendí a alojar aplicaciones en Azure
  • Atónito por jugar al "tonto".

Pregunta


¿Y qué hay de la situación con Habré con la dispersión de dinero desde un helicóptero mediante la distribución de códigos de promoción a las personas interesadas en forma personal? Si no les da una patada por esto, entonces contáctanos.

Actualización


YouTube: graba un par de juegos

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


All Articles