65.9K
CodeProject 正在变化。 阅读更多。
Home

HTML5 游戏开发实验

starIconstarIconstarIconstarIconstarIcon

5.00/5 (6投票s)

2013年4月25日

CPOL

11分钟阅读

viewsIcon

28803

downloadIcon

287

使用Windows Azure构建在线棋盘游戏。

 

介绍 

本文是作为“Windows Azure开发者挑战赛”的一部分而创作的,该挑战赛包含五个旨在探索Windows Azure提供的不同服务的挑战。在接下来的几周内,我们将随着我们应对每个挑战而更新本文。 

我们的故事  

 

作为书呆子,我们有书呆子朋友和书呆子爱好,例如游戏之夜。游戏之夜是一个每月一次的机会,可以不知羞耻地像书呆子一样玩上几个小时。我们围坐在桌旁,喝着成人饮料,玩棋盘游戏,并在游戏结束后过度分析每个玩家的策略和战术。全职工作、伴侣和几个孩子之后,游戏之夜不复存在了。然而,我们玩游戏的热情从未减退。  

最近,我们中的一些人一直在考虑让游戏之夜重现,但我们希望以一种非常酷的方式来做。 作为网络开发者,我们决定探索创建在线棋盘游戏的想法。 这样的游戏可以持续几天甚至几周,并且可以按我们自己的时间进行。 

这次比赛给了我们一个探索实现这个想法的绝佳机会。 

 

为什么选择Azure 

有了Windows Azure,我们不必成为网络/数据库专家就可以在线发布应用程序,而是可以专注于核心实现。由于设置或修改服务非常简化,我们可以自由地尝试不同的应用程序,而无需花费大量时间来创建基础结构。 

未来展望 

以下是我们将在每个挑战中涵盖的内容的概述。 

 

  1. 入门 - 您刚刚读过!微笑 | <img src= 
  2. 构建网站 - 我们将介绍如何使用Windows Azure快速启动一个网站。 我们还将探讨如何使用SignalR创建游戏大厅。 
  3. 在Azure上使用SQL - 我们将创建一个简单的游戏,并使用数据库存储各种信息。
  4. 虚拟机 - 我们将展示如何将现有应用程序迁移到VM,以提高可伸缩性并探索增强应用程序的机会。
  5. 移动访问 - 我们将创建一个移动应用程序,用于跟踪玩家的游戏并管理通知。

构建网站

 

当我们在游戏之夜聚在一起时,我们的第一步是围坐在桌旁,聊聊生活中的游戏,并选择当晚的游戏。为了重现这种体验,我们将在网站上创建一个大厅,大家在游戏开始前在此集合。 

我们将探讨如何将我们新的Windows Azure网站连接到Team Foundation Service,创建大厅并进行部署。  

基础设施 

我们不会重现Microsoft在Windows Azure网站上提供的关于创建新网站的出色教程。如果您需要入门方面的帮助,请在此处查看。  

在本节中,我们将把Team Foundation Service、Visual Studio和Windows Azure结合起来,以帮助管理源代码和部署。 

将Team Foundation Service链接到Visual Studio

构建基础结构的第一步是设置某种形式的源代码管理,并将其连接到Visual Studio。您可以随意使用任何您喜欢的源代码管理方式,但出于本教程的目的,我们将使用Team Foundation Service。 

Team Foundation Service是Microsoft流行的Team Foundation Server软件的云托管服务版本。截至撰写本文时,TFS仍处于预览阶段,您可以在此处免费注册。注册后,您将需要创建一个新的团队项目。项目的详细信息由您决定。项目创建后,我们将需要将Visual Studio链接到TFS。

从您的主团队项目页面,在“活动”部分单击“打开Visual Studio的新实例”链接。  

 

 

打开Visual Studio后,您将在Team Explorer中看到您的TFS帐户。 

将解决方案添加到Team Foundation Service 

在Visual Studio中打开现有解决方案或创建一个新解决方案。对于此演示,我们使用的是ASP.NET MVC4项目的基本模板。右键单击解决方案,然后选择“添加到源代码管理”。

 

 

接受或更改默认设置,然后选择“确定”按钮。过程完成后,打开解决方案的快捷菜单,然后选择“签入…”。 

将项目连接到Windows Azure

现在已设置好源代码管理,我们将希望将团队项目连接到我们的Windows Azure网站。执行此操作可带来许多好处。 我们可以设置自动部署,查看部署历史记录,甚至在出现问题时将网站回滚到先前的版本。  

首先,转到您的Windows Azure门户并选择您的网站。在“快速入门”页面上,选择“设置从源代码控制进行部署”。 

在向导中,选择Team Foundation Service,然后输入您的TFS帐户名称(https://youraccount.visualstudio.com)。您可能需要输入密码。 

 

 

当弹出对话框出现时,选择“接受”以授权Azure配置TFS中的团队项目。

授权成功后,您将看到一个下拉列表,其中包含您的TFS团队项目列表。选择您在先前步骤中创建的团队项目名称,然后单击“接受”。 

在短短的几分钟内,我们就成功地设置了一个新的TFS团队项目,它为您和您的团队成员提供了基于云的源代码、构建管理、敏捷开发和问题跟踪。我们还将该团队项目与Windows Azure绑定,以更好地控制部署,并且我们拥有一个优秀的IDE用于编码。 

Windows Azure、Visual Studio和Team Foundation Service使我们能够快速构建出健壮的基础结构,从而节省我们未来的时间。  

现在我们可以开始编码了! 

创建大厅 

在本节中,我们将探讨使用SignalR实现大厅中的一些关键功能。SignalR是一个很棒的包装器包,它建立在WebSockets之上,并允许客户端和服务器之间进行实时通信。有关更多信息,请在此处查看SignalR网站。 

要开始,请将SignalR NuGet包添加到Web项目中。使用程序包管理器控制台,键入以下命令。 

 

使用GUI,搜索SignalR并选择Microsoft ASP.NET SignalR。 

 

 

我们还需要确保我们的项目引用了jQuery。如果您使用了MVC4模板之一(Empty除外),那么您应该已经准备好了。 

现在项目已包含所有必需的SignalR引用,我们将创建简单的聊天功能,以便用户可以在大厅中相互交流。 

初始化SignalR的第一步是注册SignalR集线器的默认路由。将“RouteTable.Routes.MapHubs()”行添加到global.asax的Application_Start方法中。 确保它位于正常路由调用之上。  

 

RouteTable.Routes.MapHubs();
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes); 

 

下一步是创建一个SignalR集线器。 我们将此集线器命名为LobbyHub。

 

public class LobbyHub : Hub
{ 
    public void Send(string name, string message)
    {
        Clients.All.addNewMessage(name, message);
    }
    public void Login(string name, string color)
    {
        Clients.All.addNewUserToList(name, color);
    }
} 

 

 

当用户首次进入大厅时,将调用“Login”方法,“Send”将在用户发送消息时被调用。 

 

现在让我们创建视图。 创建一个HomeController和一个Index视图。 此视图将是我们的主大厅,并将包含用户列表、聊天框以及用于输入消息的文本框。

 

@Html.Hidden("displayName")
@Html.Hidden("displayColor")
<div>
    @Html.TextBox("message")
    <button id="sendmessage">Send</button>
</div>
<div class="chat-window main">
    <h2>Chat</h2>
    <ul id="discussion"></ul>
</div>
<div class="chat-window side">
    <h2>Users</h2>
    <ul id="userList"></ul>
</div>

 

 

 

 

如果您愿意,可以在Site.css文件中使用此CSS。 它并不花哨,但足以让页面在测试中看起来不错。 

.player-box {
    position: fixed;
    top: 100px;
    left: 500px;
    border: 1px solid #333;
    width: 100px;
    height: 100px;
    text-align: center;
    -moz-transition: -moz-transform 1s;
    -webkit-transition: -webkit-transform 1s;
    transition: transform 1s;
}
.large { width: 200px; height: 200px; }
.spin {
    -moz-transform: rotateZ(360deg);
    -webkit-transform: rotateZ(360deg);
    transform: rotateZ(360deg);
}
.chat-window {
    display: inline-block;
    vertical-align: top;
    border:1px solid #333;
    height:400px;
    overflow-y:scroll;
}
    .chat-window.side { width:15%; }
    .chat-window.main { width:50%; } 
.controls {
    border: 1px solid #333;
    margin-top: 10px;
    width: 300px;
}
    .controls div {
        display: inline-block;
        border: 1px solid #666;
        background-color: #F5F5F5;
        padding: 5px;
        margin: 10px;
        text-align:center;
} 

 

 

 

现在让我们连接SignalR。 

 

@section scripts {
    <script src="~/Scripts/jquery-2.0.0.js"></script>
    <script src="~/Scripts/jquery.signalR-1.0.1.js"></script>
    <script src="~/signalr/hubs"></script>
    <script>
        $(function () {
            var lobby = $.connection.lobbyHub,
                $displayName = $("#displayName"),
                $displayColor = $("#displayColor");
            lobby.client.addNewMessage = function (name, message) {
                $("#discussion").append("<li><strong>" + htmlEncode(name) + "</strong>: " + htmlEncode(message) + "</li>");
            };
            lobby.client.addNewUserToList = function(name, color) {
                $("#userList").append("<li><span style='color:" + color + ";'>" + htmlEncode(name) + "</span>");
            };
            $displayName.val(prompt("Enter your name:", ""));
            $("#message").focus();
            $.connection.hub.start().done(function () {
                var color = getRandomColor();
                $displayColor.val(color);
                lobby.server.login($displayName.val(), color);
                $("#sendmessage").click(function () {
                    var $message = $("#message");
                    lobby.server.send($displayName.val(), $message.val());
                    $message.val("").focus();
                });
            });
        });
        function getRandomColor() {
            var colors = ["blue", "yellow", "red", "black", "green", "darkgrey"];
            var selectedColor = colors[Math.floor(Math.random() * colors.length)];
            return selectedColor;
        };
        function htmlEncode(value) {
            var encodedValue = $("<div />").text(value).html();
            return encodedValue;
        };
    </script>
} 

 

 

 

 

 

 

 

这信息量很大。 让我们尝试回顾一下我们刚刚所做的工作。

 

前三行是我们让一切正常运行所需的引用。脚本“~/signalr/hubs”由运行时在第一个请求时自动生成,然后缓存。它将包含SignalR与LobbyHub通信所需的所有神奇逻辑。

 

接下来,我们设置变量并定义集线器将使用的两个函数。请记住,“Send”调用了“addNewMessage”,而“Login”调用了“addNewUserToList”。 

 

最后,我们设置了集线器连接,并在DOM中绑定了必要的事件和对象。请注意,“lobby.server.login”将转到LobbyHub并执行“Login”方法,并传递正确的参数。

 

就是这样!构建并运行您的网站。您在聊天中输入的任何消息都会立即在访问此页面的所有其他客户端上呈现。 

 

SignalR的更多乐趣 

聊天很有趣,但这将是一个游戏网站,所以我们应该让页面更具互动性。让我们来制作一个小游戏!在这个小游戏中,用户将在屏幕上显示一个带有其相应显示颜色的方框。然后他们可以移动该方框,调整其大小,甚至使其旋转(为什么不呢?微笑 | <img src= )。

 

首先,让我们创建一个新的集线器。就叫它BoxHub吧。 

 

public class BoxHub : Hub
{ 
    public void Create(string name, string color)
    {
        Clients.All.create(name, color);
    }
    public void Move(string name, int keyCode) 
    {
        Clients.All.move(name, keyCode);
    }
}

 

 

这里有两个方法。两者都很直接。一个创建方框,另一个将负责移动方框。 

 

回到我们的Index视图,我们需要在页面上添加一些元素。我们将添加一个播放按钮来创建方框,以及一个方框容器div,它将容纳所有新创建的方框。新代码以**粗体**显示。 

 

@Html.Hidden("displayName")
@Html.Hidden("displayColor")
<div>
    @Html.TextBox("message")
    <button id="sendmessage">Send</button>
    <button id="play">Play</button>
</div>
<div class="chat-window main">
    <h2>Chat</h2>
    <ul id="discussion">
    </ul>
</div>
<div 
class="chat-window side">
    <h2>Users</h2>
    <ul id="userList"></ul>
</div>
<div class="controls">
    <h2>Controls</h2>
    <div>Z</div>
    <div>X</div>
    <div>&#8592;</div>
    <div>&#8593;</div>
    <div>&#8595;</div>
    <div>&#8594;</div>
    <div>Enter</div>
</div>
<div id="boxContainer"></div> 

 

 

 

 

 

 

最后,让我们更新我们的javascript。我们需要添加一个到BoxHub的连接,并定义新的创建和移动函数。  

 

var lobby = $.connection.lobbyHub,
    box = $.connection.boxHub,
    $displayName = $("#displayName"),
    $displayColor = $("#displayColor");
box.client.create = function(name, color) {
    $("#boxContainer").append("<div id='playerBox_" + name + "' class='player-box' style='background-color:" + color + ";'></div>");
};
box.client.move = function (name, keyCode) {
    var $playerBox = $("#playerBox_" + name);
    switch (keyCode) {
                    case 39: // right 
                        $playerBox.css("left", "+=50");
                        break;
                    case 37: // left
                        $playerBox.css("left", "-=50");
                        break;
                    case 38: // up
                        $playerBox.css("top", "-=50");
                        break;
                    case 40: // down
                        $playerBox.css("top", "+=50");
                        break;
                    case 90: // Z
                        if ($playerBox.hasClass("large")) {
                            $playerBox.removeClass("large");
                        } else {
                            $playerBox.addClass("large");
                        }
                        break;
                    case 88: // X
                        if ($playerBox.hasClass("spin")) {
                            $playerBox.removeClass("spin");
                        } else {
                            $playerBox.addClass("spin");
                        }
                        break;
                    case 13: // Enter
                        break;
    }
}; 

在我们的集线器连接区域,我们需要添加新的DOM绑定。

 

$.connection.hub.start().done(function () {
    var color = getRandomColor();
    $displayColor.val(color);
    lobby.server.login($displayName.val(), color);
                
    $("#sendmessage").click(function () {
        var $message = $("#message");
        lobby.server.send($displayName.val(), $message.val());
        $message.val("").focus();
    });
    $("#play").click(function() {
        box.server.create($displayName.val(), $displayColor.val());
        $("#play").attr("disabled", "disabled");
    });
    $(document).keydown(function (e) {
        if (e.which == 39 || e.which == 37 || e.which == 38 ||
             e.which == 40 || e.which == 90 || e.which == 88 ||
             e.which == 13) {
            box.server.move($displayName.val(), e.which);
        }
    });
}); 

 

 

 

构建并运行项目。当您单击“播放”按钮时,您的玩家方框就会出现!您可以使用箭头键移动它,使用“Z”键调整它的大小,使用“X”键使其旋转。

继续并将此代码签入,Windows Azure将处理部署!   

 

挑战二总结

在本次挑战中,我们涵盖了很多内容——从源代码管理到部署,再到聊天和可移动的彩色方框。如果您想仔细查看我们的代码,请随时在本文章顶部下载源代码。或者,您可以访问我们为本次比赛设置的网站:http://proprane.azurewebsites.net  

留意Bob!他肯定藏在那页面的某个地方。在下一个挑战中,我们将研究如何将SQL集成到我们的网站中,以辅助身份验证和授权,改进我们的SignalR实现,等等!敬请关注!

在Azure上使用SQL  

我们希望让用户能够登录,跟踪已玩的游戏以及输赢。 这将需要某种数据库。 值得庆幸的是,Azure使我们能够轻松地创建一个数据库并将其连接到我们的网站。

我们不想做常规的事情,我们要挑战自己。 由于Windows Azure允许我们创建10个免费网站,所以我们认为充分利用它们会很酷。 我们将有一个中央API站点连接到我们的主用户数据库。 所有登录和玩家统计信息都将存储在那里,我们创建的每个游戏都可以调用它。

大厅和我们创建的每个游戏都是它们自己的独立网站。 这使我们受益。 它将保持代码的整洁,允许我们独立跟踪改进和错误修复,并分担服务器负载。 如果所有东西都在一个网站上,它很快就会变得拥挤。

创建Web API项目 

在本节中,我们将介绍如何创建存储常规用户信息的数据库。 我们还将创建连接到它的Web API项目。 

从聊天到仪表板 

让我们以我们之前制作的聊天网站为基础,将其增强为一个完整的用户仪表板。

玩游戏 

终于到了! 好的,这里没有什么特别的,但我们将创建一个简单的游戏,玩家可以与之互动,然后将信息保存回我们的中央数据库。 这更多的是一个概念验证,而不是一个实际的游戏。 那将是下一个挑战! 

 

© . All rights reserved.