Project 3 扩展:远程游戏共享¶
作者:Boren Tsai
原始页面:https://sp21.datastructur.es/materials/proj/proj3/proj3GameSharing本文件为完整中文说明。类名、方法签名、命令、IP、端口和程序输出保持原样。
一、介绍¶
这一扩展允许两名学生远程玩对方的 BYOW 游戏。主机运行 BYOWServer,远程玩家运行 BYOWClient。
整体模型类似联网游戏:
- 客户端负责本地显示、音频、UI 和采集用户输入;
- 远程服务器接收并执行输入;
- 服务器把正确游戏状态和画布信息发回客户端;
- 客户端显示服务器计算出的结果。
需要在 Engine 中新增:
二、获取 Networking 骨架¶
重新从 skeleton 拉取代码,得到:
这两个类已经完整实现,不需要修改。
你只需:
- 在
Engine.java实现interactWithRemoteClient; - 修改
Main.main; - 使用服务器 API 替代本地输入和画布发送。
interactWithRemoteClient 接受的启动参数格式是:
三、修改 Main¶
骨架原先包含:
需要:
- 把
main声明为可抛出IOException; - 创建
Engine; - 调用
interactWithRemoteClient(args[1])。
参考:
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();
}
}
四、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()
}
构造函数¶
创建服务器时传入端口号:
端口可以任意选择,建议至少四位,如 4005。
实例化时服务器打印:
构造函数会阻塞,直到客户端连接。连接成功后打印:
sendCanvasConfig¶
告诉客户端创建多大的 StdDraw 画布。
- 单位为像素;
- 必须与
TERenderer中setCanvasSize参数一致; - 默认 StdDraw 画布是
512 × 512; - 每次改变画布大小时准确调用一次。
sendCanvas¶
把主机当前 StdDraw 画布内容发送给客户端。
每次更新屏幕后调用,包括:
- 调用
StdDraw.showCanvas(); - 调用
TERenderer.renderFrame(...); - 菜单或 HUD 重绘。
clientHasKeyTyped¶
作用对应:
远程模式中使用服务器方法,而不是直接读取主机键盘。
clientNextKeyTyped¶
作用对应:
返回客户端输入的下一个字符。
stopConnection¶
通知客户端停止显示画布并终止连接。建议游戏退出前调用。
五、实现建议¶
interactWithRemoteClient 应与:
行为高度相似。良好设计应复用:
- 菜单状态机;
- 种子输入;
- avatar 移动;
- 世界更新;
- HUD;
- 保存与退出。
差异主要是:
| 本地键盘模式 | 远程模式 |
|---|---|
StdDraw.hasNextKeyTyped() |
server.clientHasKeyTyped() |
StdDraw.nextKeyTyped() |
server.clientNextKeyTyped() |
| 本地画布显示 | 每次更新后 server.sendCanvas() |
| 本地退出 | 退出前 server.stopConnection() |
若现有代码把输入源抽象成接口,通常可以避免大量重复代码。最容易遗漏的是画布每次更新后都要发送。
六、BYOWClient¶
BYOWClient 已完整实现,直接运行其 main 方法。程序会询问:
IP addressport
本机测试填写:
示例输出:
BYOW Client. Please Enter the following information to connect to a server...
IP Address: localhost
Port (this must be a number): 4005
CONFIGURING CANVAS
端口必须与服务器启动端口相同。
七、本地测试¶
- 运行
Main,程序参数:
- 再运行
BYOWClient; - IP 输入:
- 端口输入:
应出现两个 StdDraw 窗口:
- 一个服务器窗口;
- 一个客户端窗口。
若实现正确,两者内容应完全同步,客户端按键应驱动服务器游戏。
八、支持真正远程连接¶
确认本地服务器和客户端已经镜像成功后,再配置公网隧道。
原课程推荐使用 ngrok。
安装并加入 PATH¶
下载 ngrok,把可执行文件加入环境变量:
例如位于 Downloads:
开启 TCP 隧道¶
假设服务器使用端口 4005:
ngrok 会显示类似:
其中:
- 客户端 IP:
2.tcp.ngrok.io - 客户端端口:
17993 - 输入 IP 时不要包含
tcp://。
远程游戏步骤¶
主机:
- 用
-p 4005启动Main; - 新终端执行
ngrok tcp 4005; - 把 ngrok 显示的主机名和端口发给朋友。
远程玩家:
- 运行
BYOWClient; - 输入主机提供的 ngrok 地址;
- 输入 ngrok 端口;
- 连接后即可远程操作主机上的游戏。
主机可以观看玩家操作,也可以进一步扩展成服务器同时修改世界的玩法。
九、One Point Bounty¶
理论上可以制作浏览器客户端。课程当时没有提供实现。
若有人创建能连接 BYOW Server 的网站客户端,课程奖励 1 个 bonus point,并可能把它作为以后课程资源。
十、免责声明¶
发送 StdDraw 画布会产生额外编码、传输和网络开销,因此远程游戏很可能有明显延迟。这是正常且预期的,不代表实现错误。
十一、完成检查清单¶
- [ ] 已重新拉取
Networking文件夹; - [ ] 未修改
BYOWClient和BYOWServer; - [ ]
Main.main声明throws IOException; - [ ]
-p分支调用interactWithRemoteClient; - [ ] 端口字符串正确解析为整数;
- [ ] 远程输入使用
clientHasKeyTyped/clientNextKeyTyped; - [ ] 初始化或改变画布时调用
sendCanvasConfig; - [ ] 每次重绘后调用
sendCanvas; - [ ] 退出前调用
stopConnection; - [ ] localhost 测试出现两个同步窗口;
- [ ] 远程测试使用正确 ngrok IP 和端口;
- [ ] 能接受网络延迟属于正常现象。
原始来源:CS61B Spring 2021 · 中文整理:everlasting · CC BY-NC-SA 4.0