前言
最近在项目中一直在开发即时消息的应用场景,本次将通过Laravel来构建一个即时的匹配系统,可适用于基本的即时对战小游戏,需要用到的知识点如下:
- Laravel
- Redis
- Laravel-echo
- VueJs
下面开始实战操作:
安装项目依赖
composer install predis //安装redis扩展包
npm install laravel-echo //安装laravel-echo客户端
npm install -g laravel-echo-server //安装laravel-echo-server 服务端
具体部署教程可参照之前写的博客:
打造你的Laravel即时应用
创建比赛系统
在我们的这个基础系统中,需要用户(user)和比赛(game),比赛主要是用于将匹配到的用户放到一起,下面将通过3张表来完成这个系统的的初始设计。
1.比赛表设计
$table->unsignedInteger('user_id')->index();
$table->unsignedInteger('rival_id')->index()->comment('对手ID');
$table->unsignedInteger('winner_id')->default(0)->comment('胜利者ID');
$table->unsignedInteger('reward')->default(0)->comment('奖励');
$table->json('data')->nullable()->comment('比赛数据');
$table->tinyInteger('status')->default(0)->comment('比赛状态');
$table->timestamps();
$table->timestamp('end_at')->nullable()->comment('结束时间');
2.用户匹配表设计
$table->increments('id');
$table->unsignedInteger('user_id')->unique();
$table->tinyInteger('online_status')->default(0);
$table->timestamp('online_at')->nullable()->index();
$table->unsignedInteger('in_game_id')->default(0)->comment('在房间ID');
$table->timestamps();
构建视图
我们通过Vue来实现一个简单的视图,运用到了props、axios等基础组件来实现.
{{ gameStatus }}
如果你使用的css框架是bootstrap,构建出来的应该会是这样。
完善后端匹配逻辑
提高一个matchUser的接口给前端来进行调用,首先会去查询user_games的记录,不存在则创建一条,稍后再查询当前是否有正在进行中的比赛,存在的话,则抛出异常提醒用户,否则进入匹配队列。
//查找或创建用户
$userGame = UserGame::firstOrCreate(['user_id' => $user->id]);
//是否有游戏中,防止重复请求
$game = $userGame->hasPlaying();
throw_if(!is_null($game), GameException::class, '您已在PK中,请进入游戏!');
//用户上线
$userGame->online();
//分发到匹配队列中
dispatch(new MatchGame($this))->onQueue('game-match');
当用户成功进入匹配队列后,我们会将所有匹配中的用户进行对手分配,每次获取两个用户为一局比赛,逻辑如下:
UserGame::with('user')->onlined()->orderBy('online_at')->chunk(100, function ($collect) {
foreach ($collect->chunk(2) as $userGames) {
if (count($userGames) < 2) {
continue;
}
$user1 = $userGames->first()->user;
$user2 = $userGames->last()->user;
$game = $this->gameService->createGame($user1, $user2);
//发送socket通知双方用户开始
$this->gameService->sendSocket($game, 'NewGame');
}
});
完善前端匹配接口 && 挂载Echo
当匹配接口和匹配队列完成后,就开始对视图进行绑定及挂载Echo socket通信。
{{ gameStatus }}
效果展示
运行指令:
laravel-echo-server start //开启socket服务
php artisan queue:work //开启队列消费
php artisan queue:work --queue=game-match //开启匹配队列消费
结尾
本篇主要通过后端角度出发,来使用队列技术,实现了用户的即时匹配系统,核心知识点主要在laravel队列和laravel-echo的使用,通过队列将匹配中的用户进行组合,创建一局新比赛,通过服务端广播NewGame,客户端监听NewGame事件来达到即时匹配的效果。