Room 桌游类、房间类的实战
介绍
现在,我们基于 Room + 领域事件做了一个实战。 整体比较简单,多名玩家在房间里猜拳(石头、剪刀、布)得分。
实战包括了前后端,前端使用 FXGL 引擎, 这样开发者在学习时只需 JDK 环境,而不需要安装其他游戏引擎的环境。
源码统计与功能介绍
基于 Room 模块的扩展,只用数百行代码就完成了下述功能
- 登录
- 玩家进入大厅(地图)
- 玩家可在大厅移动
- 玩家移动时相互可见
- 玩家离开大厅(玩家下线)
- 查询房间列表
- 房间信息实时变更通知(房间内有玩家数量变化,等待中、游戏中 ...等状态)
- 玩家创建房间
- 玩家进入房间
- 玩家退出房间
- 解散房间
- 玩家准备
- 开始游戏
- 玩家在房间内的玩法操作
- 及各种验证,断言 + 异常机制 = 清晰简洁的代码
Room 模块很好的帮助开发者屏蔽这些重复性的工作, 并可为项目中的功能模块结构、开发流程等进行清晰的组织定义,减少了后续的项目维护成本。 更重要的是有相关文档,将来当你的团队有新进成员时,可以快速的上手。
图文展示
大厅
启动游戏后玩家会将加入大厅(类似地图),多名玩家相互可见,并且玩家可以在大厅内移动。
创建房间
[玩家1] 创建一个房间并加入。
大厅的玩家可以看见当前的房间列表信息,房间列表信息会实时的变化,比如游戏开始后会由等待中变成游戏中。 房间内的玩家数有变更时,也会实时的更新。
玩家可以创建一个房间,等待其他玩家的加入,也可以加入一个已经存在的房间与其他玩家共同游戏。
玩家在房间内
图中,两个玩家在同一房间内,房主可操作的按钮为退出房间和开始游戏;其他玩家则为退出房间和准备。
准备
玩家准备时,按钮则变为取消准备。同时,玩家的准备信息将实时的更新到左侧的面板中。
游戏开始
游戏开始后,每个玩家可以选择要出的(石头、剪刀、布),选择好后会显示到左边的面板中。 右边是当前房间内的得分排行,得分最高的排在前。
游戏时,每局有一定的时间供玩家选择,倒计时结束后会公布结算结果。
如果倒计时结束玩家没有选择,那么服务器会强制帮未操作的玩家做出随机选择。
游戏结束
游戏结束后,玩家可以离开房间。
获取源码
符合以下条件的可通过 Email 免费获取
- 已经购买了 回合制网络游戏 MMO 永久产品的开发者。
- 购买了闭源授权的企业。
- 在 2024 年 5 月前有过捐赠行为(至少为 1 星)的支持者。(需要发送捐赠截图)
单独购买
该实战源码支持单独购买 998元。 有效期: 永久。
QQ: 262610965
备注: 购买 Room 实战。
部分源码展示
玩法操作
// 验证与实际业务逻辑分离
// 将玩家的选择(石头、剪刀、布)广播给房间内的其他玩家。
public class ChooseOperationHandler implements OperationHandler {
@Override
public void verify(PlayerOperationContext context) {
// 玩家操作的数据
FightOperationCommand command = context.getCommand();
int elementIndex = command.elementIndex;
// 验证玩家的操作数据是否合法(石头、剪刀、布)
GameCode.illegalOperation.assertTrue(FiveElementKit.verify(elementIndex));
}
@Override
public void process(PlayerOperationContext context) {
FightRoomEntity room = context.getRoom();
long userId = context.getUserId();
// 将玩家的选择(石头、剪刀、布)保存到当前对局中
var fightRound = room.getCurrentFightRound();
var item = fightRound.getItemByUserId(userId);
var command = context.getCommand();
item.setElementIndex(command.elementIndex);
// 房间内广播 - 有玩家做了选择
MyBroadcastKit.operation(userId, room);
}
}
操作扩展配置
public final class MyOperationRunner implements Runner {
@Override
public void onStart(BarSkeleton skeleton) {
var factory = FightRoomService.me().getOperationFactory();
// ------ mapping internal operation ------
// 进入房间、准备、退出房间、开始游戏
factory.mapping(InternalOperationEnum.enterRoom, new EnterRoomOperationHandler());
factory.mapping(InternalOperationEnum.ready, new ReadyOperationHandler());
factory.mapping(InternalOperationEnum.quitRoom, new QuitRoomOperationHandler());
factory.mapping(InternalOperationEnum.startGame, new StartGameOperationHandler());
// ------ mapping user operation ------
factory.mappingUser(FightOperation.choose, new ChooseOperationHandler());
}
}