Windows应用商店的傻瓜应用程序


保罗·塞尚(Paul Cezanne),纸牌玩家

从前,在Windows 95中有一个Microsoft Hearts游戏。 在线玩纸牌,世界各地的对手。 如果内存适合我,那么在Windows for Workgroups 3.11中(是的,我发现了所有这些工件!)有一个版本可以使用所谓的NetDDE在本地网络上播放。

我不必长时间选择纸牌游戏。 正如他们所说的,什么是丰富的……高架桥和偏好由于他们的完全无知而消失了。 只剩下一件事- 作为愚蠢的傻瓜消失了

到目前为止,我从未参与过“后端”的开发,这使情况变得复杂。 谷歌搜索使我正确地到达了正确的位置-SignalR

在这里我想对SignalR说几句热情的话。 一个文档齐全的库非常适合我的需求。 无聊的人会说这仅适用于Windows,好吧,让他们羡慕不已。 尽管似乎有iOS的集体农场客户端,但我没有详细研究此问题。

下一个问题是托管。 然后我没多久,Azure就在我的怀抱中。

那我想要什么?


  • 玩家的连接方式应类似于Microsoft Hearts。 一旦获得正确的数量,玩家就会一一连接-游戏开始。 对于我自己,我决定将自己限制为一对一的游戏-而且没人会抽签!
  • 一开始会有很少的参与者-他们如何相互了解? 然后,这个想法浮出水面,以便在有人启动应用程序并连接到游戏服务器时,向想要播放推送通知的每个人发送消息。 为了不通过推挤来限制用户,他做出了“每N分钟不超过一次”的限制。
  • 我需要详细的统计数据,奖项,成就等。
  • 我想要不同设计的卡片
  • 我想和我的熟人一起玩,而不是和“上帝差派的人”一起玩。

我在Azure上使用什么?


  • 实际上,AppService是所有客户端都连接到的应用程序。
  • SQL Server + SQL数据库-用于存储游戏统计信息。

仅此而已。

最近,我还使用了他们的推送通知分发服务。 但这似乎很昂贵(每月10美元),此外,事实证明,由于Microsoft的帐单故障,我已经为这两项服务支付了超过一年的费用! 对接支持导致他们认识到错误并提供了长达一个月的赔偿。 一段时间后,我完全放弃了该服务,将另一个表添加到我的数据库中以存储签名者以进行推送并从主应用程序中自己发送它们。

这时,每月托管费用约为400 r。 这仅是SQL Server的成本。 我的传出流量很小,每月可容纳5 GB。

发展历程


开发在Visual Studio 2015上进行,针对客户端使用了MVVM框架MVVM light。

一个小的服务器“厨房”(美观和内心的虚弱最好不要看)


用户连接,推送
public override Task OnConnected() { if (((DateTime.Now - LastPush).TotalSeconds) > 360) { LastPush = DateTime.Now; Task.Run(() => SendNotifications()); } return base.OnConnected(); } 


创建一个匿名游戏
 /// <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(); } } 


建立游戏室
 /// <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(); } } 


偷看甲板上的顶卡
 /// <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(); } } } 


给对手发信息
 /// <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(); } } } 



关于客户


为了识别玩家,首先使用LiveId功能,然后使用Graph API。 在首次启动该应用程序时,将邀请玩家提供对其帐户的访问权限(从中我仅获得名称和所谓的匿名ID,看起来像这样:“ ed4dd29dda5f982a”)。 但是,玩家可以匿名玩,但随后不会保留其游戏统计信息。

为每个非匿名玩家存储:

1.第一场比赛的日期/最后一场比赛的日期
2.玩家姓名/昵称
3.玩过的游戏数/赢了多少
4.最后的IP地址
5.收到的奖品

如果有两个非匿名玩家参与游戏,那么在开始之前,我会获得这些特定玩家的游戏统计信息(他们互相玩了多少游戏,谁赢了多少)。 为此,在SQL查询中使用接收到的匿名ID。

在左上方的屏幕截图中,您可以看到一个示例(可点击):



常规统计信息的屏幕截图(可点击):



此外,还将在各个国家/地区举行“竞争”(匿名参与者也在此参加,信息取自IP地址):



玩家可以交换短信。

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

情况处理程序的示例“我拿牌,而对手又给我加了一个”之后””:

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

关于奖品,Cookie等


每个月,获胜最多的前五名球员将获得一个徽章“为夺取柏林” 。 进入前50名的参与者将获得徽章,以获得最佳的胜利百分比(也是5项)。 此外,还有通过“快速”获胜的徽章(在最后一步中,您有2、3或4,例如6个或千斤顶)。 然后他们一口气把所有东西放在桌上,您-做得很好。 当对手给您一个“清单”时,就有胜利的曲奇。 他也得到了令人欣慰的头骨和骨头。

关于任何其他功能


该应用程序是免费的,但它还具有各种其他的“小包”,这些小包装饰为InApp购买:

  • 在游戏过程中,按照衣服和提示对卡片进行分组(当您需要打或抛时,将合适的卡片向上推)
  • 不向对手显示您手中有多少张牌的能力。 在正常情况下,他会看到
  • 总是总是首先开始游戏的机会。 否则,将随机播放第一步。
  • 看到游戏中被击败的卡片的能力
  • 每场比赛有机会窥视一下甲板并找出下一张牌
  • 作弊的能力。 您每场比赛可以击败3次,也可以掷错牌,通常是任何一张。 但是,对手已经注意到这一点,就有机会将错误的卡退还给您。

结论


作为开发此应用程序的结果,我:

  • 遇见SignalR
  • 内存中刷新的SQL(查询,存储过程,函数)
  • 了解如何在Azure上托管应用
  • 由于扮演“傻瓜”而傻眼。

问题


哈布雷的情况又如何呢? 通过向个人感兴趣的人分发促销代码, 从直升机上驱散金钱,情况如何? 如果他们对此不满意,请联系。

更新资料


YouTube:录制一些游戏

Source: https://habr.com/ru/post/zh-CN442746/


All Articles