Everlasting Pages

返回

Project 3:游戏共享

目录#

作者:Boren Tsai

我们为项目 3:BYOW 新增了一项功能,使任意两名学生都可以远程游玩对方制作的游戏。

为疫情期间的安全欢呼吧。

介绍#

现在有两名 61B 学生,Alice 和 Bob。Alice 和 Bob 都制作了非常棒的游戏,也都想玩对方的作品;但由于居家避疫规定,他们无法见面。

Alice 非常沮丧,于是来到 Office Hours 表达自己的失望。幸运的是,助教 Arjun 接下了 Alice 的求助单,并带来了一个令人兴奋的消息:Alice 和 Bob 仍然可以玩对方的游戏!

Arjun 首先让 Alice 再次从 skeleton 拉取代码,然后解释说,Alice 可以使用课程提供的 BYOWServer 托管游戏,而 Bob 可以使用 BYOWClient 连接并游玩这个游戏。

Arjun 把这种方案类比为在线游玩 Minecraft。

客户端是用户实际用来玩游戏的程序。客户端负责所有本地计算,例如:

  • 图形;
  • 音频;
  • UI(User Interface,用户界面);
  • 记录用户输入。

与此同时,远程服务器——也就是不在你本地电脑上的服务器——通过互联网监听并执行客户端的输入。

随后,服务器把客户端正确渲染游戏状态、输出正确音频等操作所需的信息发送回客户端。

更多信息可以在这里找到。

为了让学生能够相互分享游戏,你需要在 Engine 类中实现一个新方法:

interactWithRemoteClient
java

网络功能#

为了实现上述功能,我们在 proj3 中加入了一层网络功能。

核心功能已经放在 Networking 文件夹中。你会在其中找到两个类:

  • BYOWClient
  • BYOWServer

重要:要获得这个文件夹,你需要重新从 skeleton 拉取代码。

你不需要修改这两个文件中的任何一个。

如上所述,你需要在 Engine.java 中实现:

interactWithRemoteClient
java

从方法名称可以看出,你会在这个方法中使用 BYOWServerBYOWClient 交互。

这些类已经完整实现,你不需要作任何调整。

interactWithRemoteClient 接收的输入格式为:

-p [4-digit port number]
text

也就是:

-p [四位端口号]
text

Main#

BYOW 服务器的“入口”已经存在于你的代码中:

else if (args.length == 2 && args[0].equals("-p")) {
    System.out.println("Coming soon.");
}
java

你需要把这条打印语句替换为支持服务器所需的代码。

此外,你还需要修改 main 方法的定义,使其抛出 IOException

下面提供我们的 main 方法作为参考。代码中开头的 + 用于表示需要新增的行:

为了把远程游戏共享加入项目,我们在下面提供了文档和进一步的实现指南。

BYOWServer#

我们提供了一个 BYOWServer 类,它会为你完成所有网络魔法。

你不需要修改这个类,不过如果愿意,也可以自行修改。

BYOWServer 提供以下接口:

public class BYOWServer {
    public BYOWServer(int port)

    public void sendCanvasConfig(int width, int height)
    public void sendCanvas()

    public boolean clientHasKeyTyped()
    public char clientNextKeyTyped()

    public void stopConnection()
}
java

创建 BYOWServer 时,必须提供一个 port 端口号。

端口号可以是你自行选择的任意整数。我们建议选择至少四位的端口号,例如:

4005
text

这个数字完全由你自行决定。

如果以后学习网络课程,例如 CS 168,你会了解端口的具体含义。

实例化 BYOWServer 时,它会输出:

Server started. Waiting for client to connect…
text

随后,构造器会一直等待,直到客户端建立连接。

客户端成功连接后,构造器会输出:

Client connected!
text

为了与远程玩家通信,我们提供了以下方法。

1. sendCanvasConfig#

第一个方法:

sendCanvasConfig
java

用于告诉客户端应创建多大的 StdDraw 窗口。

参数单位是像素,并且应与你在 TERenderer 类第 35 行调用 setCanvasSize 时提供的参数一致。

每当调整画布大小时,应当恰好调用一次这个函数。

供参考,默认的 StdDraw 画布大小为:

512 × 512 pixels
text

2. sendCanvas#

第二个方法:

sendCanvas
java

会把托管游戏的电脑上 StdDraw 窗口中的内容发送给客户端。

每次更新屏幕时都应调用它,例如在以下情况之后:

StdDraw.showCanvas()
java

或者调用:

TERenderer.renderFrame(...)
java

3. clientHasKeyTyped#

第三个方法:

clientHasKeyTyped
java

StdDraw 中的:

hasNextKeyTyped
java

作用类似。

你应使用:

clientHasKeyTyped()
java

代替:

StdDraw.hasNextKeyTyped()
java

4. clientNextKeyTyped#

第四个方法:

clientNextKeyTyped
java

StdDraw 中的:

nextKeyTyped
java

作用类似。

你应使用:

clientNextKeyTyped()
java

代替:

StdDraw.nextKeyTyped()
java

5. stopConnection#

第五个方法:

stopConnection
java

用于通知客户端停止显示 StdDraw 画布,然后终止连接。

我们建议你在游戏退出前调用这个方法。

我们建议创建一个行为与 interactWithKeyboard 非常相似的 interactWithRemoteClient 方法。

如果设计合理,可以避免代码重复。不过,你可能会发现,让代码在正确时机调用 sendCanvas 会稍微有些麻烦。

供参考,Josh Hug 在一年没有看过自己的 BYOW 客户端代码后,为其加入服务器功能大约花了 30 分钟。

BYOWClient#

我们还提供了一个 BYOWClient 类。

这个类已经完整实现,可以直接运行。

运行它的 main 方法后,程序会提示你输入:

  • IP address
  • port

如果想在本机测试,请在 IP address 中输入:

localhost
text

然后在程序询问 port 时,输入实例化 BYOWServer 时使用的相同端口号。

例如,如果你采用了我们的建议,端口号就是:

4005
text

示例输出如下:

BYOW Client. Please Enter the following information to connect to a server...
IP Address: localhost
Port (this must be a number): 4005
CONFIGURING CANVAS
text

测试你的代码#

完成 interactWithRemoteClient 后,先使用以下命令行参数运行 Main

-p 4005
text

也可以使用你自己选择的其他端口号。

随后运行 BYOWClient,并输入:

localhost
text

以及相同的端口号。

你应当看到两个 StdDraw 窗口打开:

  • 一个代表服务器;
  • 一个代表客户端。

如果实现正确,这两个窗口应当显示完全相同的内容。

支持远程游戏#

当你成功让服务器端和客户端的两个 StdDraw 窗口彼此同步后,就可以开始支持真正的远程游戏了。

如果你还没有实现 interactWithRemoteClient,请立刻返回前面的步骤,直到完成它。

正确实现 interactWithRemoteClient 后,你就可以开始支持远程游戏。

首先,你还需要下载一个非常酷的软件:

ngrok
text

请在这里注册账户并下载它。

ngrok 可执行文件添加到 PATH 环境变量中。

原说明给出的终端命令是:

export PATH=$PATH:[path to ngrok executable]
bash

例如,如果可执行文件位于 Downloads 文件夹中,可以使用:

export PATH=$PATH:~/Downloads/
bash

现在,假设:

  • 已经把 ngrok 可执行文件加入 PATH
  • 服务器使用端口 4005

打开一个新终端并运行:

ngrok tcp 4005
bash

这条命令会把服务器正在使用的:

localhost:4005
text

通过 tcp 协议暴露到整个互联网,使其他人能够连接。

运行后,终端应类似下图:

ngrok TCP 隧道示例

在显示 Forwarding 的一行中,可以看到类似内容:

tcp://2.tcp.ngrok.io:17993 -> localhost:4005
text

实际效果是把本机的:

localhost:4005
text

暴露到互联网。

只要 ngrok 会话保持运行,发送到以下地址的全部信息:

tcp://2.tcp.ngrok.io:17993
text

都会被转发到:

localhost:4005
text

在这个示例中,ngrok 隧道的信息为:

IP address: 2.tcp.ngrok.io
port: 17993
text

注意:填写 IP address 时,不需要包含 tcp:// 前缀。

下面看看如何使用 ngrok,让互联网上的其他人连接到你的 BYOW 服务器。

首先,使用以下程序参数运行 Main 类的 main 方法:

-p 4005
text

随后,在一个新终端中运行:

ngrok tcp 4005
bash

把 ngrok 创建的隧道的以下信息发送给朋友:

  • IP address
  • port

朋友运行 BYOWClient 后,把你发送的信息输入客户端。

建立连接之后——完成!

你的朋友现在应该能够远程游玩你的游戏,而你则可以在服务器端观看整个过程。

注意:这也带来了一些很有趣的可能性,例如允许服务器在玩家游玩过程中修改世界。尽情发挥吧。

一分悬赏#

原则上,可以制作一个基于网页的客户端。

我们目前还没有实现它。

不过,如果有人创建了一个能够连接 BYOW 服务器的网站,我们将奖励你:

1 bonus point
text

也就是 1 分额外加分

未来,我们还很可能会把它作为正式课程资源使用。

免责声明#

由于保存 StdDraw 画布会产生额外开销,同时网络自身也存在限制,在使用远程功能时,你很可能会遇到延迟。

这是完全正常且符合预期的行为。

希望你能享受游玩彼此制作的游戏。


原始页面:https://sp21.datastructur.es/materials/proj/proj3/proj3GameSharing