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 类中实现一个新方法:
interactWithRemoteClientjava网络功能#
为了实现上述功能,我们在 proj3 中加入了一层网络功能。
核心功能已经放在 Networking 文件夹中。你会在其中找到两个类:
BYOWClientBYOWServer
重要:要获得这个文件夹,你需要重新从
skeleton拉取代码。你不需要修改这两个文件中的任何一个。
如上所述,你需要在 Engine.java 中实现:
interactWithRemoteClientjava从方法名称可以看出,你会在这个方法中使用 BYOWServer 与 BYOWClient 交互。
这些类已经完整实现,你不需要作任何调整。
interactWithRemoteClient 接收的输入格式为:
-p [4-digit port number]text也就是:
-p [四位端口号]textMain#
BYOW 服务器的“入口”已经存在于你的代码中:
else if (args.length == 2 && args[0].equals("-p")) {
System.out.println("Coming soon.");
}java你需要把这条打印语句替换为支持服务器所需的代码。
此外,你还需要修改 main 方法的定义,使其抛出 IOException。
下面提供我们的 main 方法作为参考。代码中开头的 + 用于表示需要新增的行:
+ public static void main(String[] args) throws IOException {
if (args.length > 2) {
System.out.println("Can only have two arguments - the flag and input string");
System.exit(0);
} else if (args.length == 2 && args[0].equals("-s")) {
Engine engine = new Engine();
engine.interactWithInputString(args[1]);
System.out.println(engine.toString());
} else if (args.length == 2 && args[0].equals("-p")) {
+ Engine engine = new Engine();
+ engine.interactWithRemoteClient(args[1]);
} else {
Engine engine = new Engine();
engine.interactWithKeyboard();
}
}java为了把远程游戏共享加入项目,我们在下面提供了文档和进一步的实现指南。
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 端口号。
端口号可以是你自行选择的任意整数。我们建议选择至少四位的端口号,例如:
4005text这个数字完全由你自行决定。
如果以后学习网络课程,例如 CS 168,你会了解端口的具体含义。
实例化 BYOWServer 时,它会输出:
Server started. Waiting for client to connect…text随后,构造器会一直等待,直到客户端建立连接。
客户端成功连接后,构造器会输出:
Client connected!text为了与远程玩家通信,我们提供了以下方法。
1. sendCanvasConfig#
第一个方法:
sendCanvasConfigjava用于告诉客户端应创建多大的 StdDraw 窗口。
参数单位是像素,并且应与你在 TERenderer 类第 35 行调用 setCanvasSize 时提供的参数一致。
每当调整画布大小时,应当恰好调用一次这个函数。
供参考,默认的 StdDraw 画布大小为:
512 × 512 pixelstext2. sendCanvas#
第二个方法:
sendCanvasjava会把托管游戏的电脑上 StdDraw 窗口中的内容发送给客户端。
每次更新屏幕时都应调用它,例如在以下情况之后:
StdDraw.showCanvas()java或者调用:
TERenderer.renderFrame(...)java3. clientHasKeyTyped#
第三个方法:
clientHasKeyTypedjava与 StdDraw 中的:
hasNextKeyTypedjava作用类似。
你应使用:
clientHasKeyTyped()java代替:
StdDraw.hasNextKeyTyped()java4. clientNextKeyTyped#
第四个方法:
clientNextKeyTypedjava与 StdDraw 中的:
nextKeyTypedjava作用类似。
你应使用:
clientNextKeyTyped()java代替:
StdDraw.nextKeyTyped()java5. stopConnection#
第五个方法:
stopConnectionjava用于通知客户端停止显示 StdDraw 画布,然后终止连接。
我们建议你在游戏退出前调用这个方法。
我们建议创建一个行为与 interactWithKeyboard 非常相似的 interactWithRemoteClient 方法。
如果设计合理,可以避免代码重复。不过,你可能会发现,让代码在正确时机调用 sendCanvas 会稍微有些麻烦。
供参考,Josh Hug 在一年没有看过自己的 BYOW 客户端代码后,为其加入服务器功能大约花了 30 分钟。
BYOWClient#
我们还提供了一个 BYOWClient 类。
这个类已经完整实现,可以直接运行。
运行它的 main 方法后,程序会提示你输入:
IP addressport
如果想在本机测试,请在 IP address 中输入:
localhosttext然后在程序询问 port 时,输入实例化 BYOWServer 时使用的相同端口号。
例如,如果你采用了我们的建议,端口号就是:
4005text示例输出如下:
BYOW Client. Please Enter the following information to connect to a server...
IP Address: localhost
Port (this must be a number): 4005
CONFIGURING CANVAStext测试你的代码#
完成 interactWithRemoteClient 后,先使用以下命令行参数运行 Main:
-p 4005text也可以使用你自己选择的其他端口号。
随后运行 BYOWClient,并输入:
localhosttext以及相同的端口号。
你应当看到两个 StdDraw 窗口打开:
- 一个代表服务器;
- 一个代表客户端。
如果实现正确,这两个窗口应当显示完全相同的内容。
支持远程游戏#
当你成功让服务器端和客户端的两个 StdDraw 窗口彼此同步后,就可以开始支持真正的远程游戏了。
如果你还没有实现
interactWithRemoteClient,请立刻返回前面的步骤,直到完成它。
正确实现 interactWithRemoteClient 后,你就可以开始支持远程游戏。
首先,你还需要下载一个非常酷的软件:
ngroktext请在这里 ↗注册账户并下载它。
把 ngrok 可执行文件添加到 PATH 环境变量中。
原说明给出的终端命令是:
export PATH=$PATH:[path to ngrok executable]bash例如,如果可执行文件位于 Downloads 文件夹中,可以使用:
export PATH=$PATH:~/Downloads/bash现在,假设:
- 已经把
ngrok可执行文件加入PATH; - 服务器使用端口
4005。
打开一个新终端并运行:
ngrok tcp 4005bash这条命令会把服务器正在使用的:
localhost:4005text通过 tcp 协议暴露到整个互联网,使其他人能够连接。
运行后,终端应类似下图:

在显示 Forwarding 的一行中,可以看到类似内容:
tcp://2.tcp.ngrok.io:17993 -> localhost:4005text实际效果是把本机的:
localhost:4005text暴露到互联网。
只要 ngrok 会话保持运行,发送到以下地址的全部信息:
tcp://2.tcp.ngrok.io:17993text都会被转发到:
localhost:4005text在这个示例中,ngrok 隧道的信息为:
IP address: 2.tcp.ngrok.io
port: 17993text注意:填写
IP address时,不需要包含tcp://前缀。
下面看看如何使用 ngrok,让互联网上的其他人连接到你的 BYOW 服务器。
首先,使用以下程序参数运行 Main 类的 main 方法:
-p 4005text随后,在一个新终端中运行:
ngrok tcp 4005bash把 ngrok 创建的隧道的以下信息发送给朋友:
IP addressport
朋友运行 BYOWClient 后,把你发送的信息输入客户端。
建立连接之后——完成!
你的朋友现在应该能够远程游玩你的游戏,而你则可以在服务器端观看整个过程。
注意:这也带来了一些很有趣的可能性,例如允许服务器在玩家游玩过程中修改世界。尽情发挥吧。
一分悬赏#
原则上,可以制作一个基于网页的客户端。
我们目前还没有实现它。
不过,如果有人创建了一个能够连接 BYOW 服务器的网站,我们将奖励你:
1 bonus pointtext也就是 1 分额外加分。
未来,我们还很可能会把它作为正式课程资源使用。
免责声明#
由于保存 StdDraw 画布会产生额外开销,同时网络自身也存在限制,在使用远程功能时,你很可能会遇到延迟。
这是完全正常且符合预期的行为。
希望你能享受游玩彼此制作的游戏。
原始页面:https://sp21.datastructur.es/materials/proj/proj3/proj3GameSharing ↗