首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Workerman Asyncio 异步游戏框架

Workerman Asyncio 异步游戏框架

作者头像
Tinywan
发布2025-10-20 17:28:05
发布2025-10-20 17:28:05
11400
代码可运行
举报
文章被收录于专栏:开源技术小栈开源技术小栈
运行总次数:0
代码可运行

概述

一个面向 Workerman + pfinal-asyncio 的异步游戏框架,让你用 async/await 编排游戏逻辑,就像写故事剧本一样。

核心功能

  • 🎮 Room 基类 - 带完整生命周期钩子的异步房间管理
  • 👥 Player 通信封装 - 简单易用的玩家消息收发
  • 📢 异步广播机制 - 支持即时和延迟广播
  • 定时事件系统 - 灵活的定时器和延迟任务
  • 🔄 房间生命周期 - onCreate、onStart、run、onDestroy 完整钩子
  • 🎯 RoomManager - 多房间管理和快速匹配
  • 🌐 GameServer - 开箱即用的 WebSocket 游戏服务器

高级功能 🆕

  • 🧪 单元测试 - 完整的 PHPUnit 测试框架
  • 🚨 异常处理 - 结构化异常系统,带上下文信息
  • 📝 日志系统 - 多级别日志,支持控制台和文件输出
  • 💾 状态持久化 - 支持 Redis、文件等多种存储方式
  • ⚖️ 负载均衡 - 多进程房间分配,支持轮询、最少连接等策略

框架定位

专为 小型多人游戏实时对战游戏 设计,适用于:

  • 🃏 卡牌游戏
  • 🎲 棋牌游戏
  • 🎯 答题游戏
  • 🏁 实时对战游戏
  • 🎮 回合制游戏

📦 安装

代码语言:javascript
代码运行次数:0
运行
复制
composer require pfinalclub/asyncio-gamekit

📋 要求

  • PHP >= 8.3
  • pfinalclub/asyncio >= 1.0
  • workerman/workerman >= 4.1

🚀 快速开始

1. 创建你的第一个游戏房间

代码语言:javascript
代码运行次数:0
运行
复制
<?php
usePfinalClub\AsyncioGamekit\Room;
usePfinalClub\AsyncioGamekit\Player;
useGenerator;
usefunctionPfinalClub\Asyncio\{run, sleep};

class MyGameRoom extends Room
{
    protectedfunction run(): Generator
    {
        // 游戏开始
        $this->broadcast('game:start', ['message' => '游戏开始!']);
        
        // 游戏主循环
        for ($round = 1; $round <= 3; $round++) {
            $this->broadcast('game:round', ['round' => $round]);
            yield sleep(5); // 每回合5秒
        }
        
        // 游戏结束
        $this->broadcast('game:end', ['message' => '游戏结束!']);
        yield from $this->destroy();
    }
}

// 运行游戏
function main(): Generator {
    $room = new MyGameRoom('room_001');
    
    $player1 = new Player('p1', null, 'Alice');
    $player2 = new Player('p2', null, 'Bob');
    
    $room->addPlayer($player1);
    $room->addPlayer($player2);
    
    yield from $room->start();
}

run(main());

2. 完整的 WebSocket 游戏服务器

代码语言:javascript
代码运行次数:0
运行
复制
<?php
use PfinalClub\AsyncioGamekit\GameServer;

$server = new GameServer('0.0.0.0', 2345, [
    'name' => 'MyGameServer',
    'count' => 4,
]);

$server->run();

客户端连接:

代码语言:javascript
代码运行次数:0
运行
复制
const ws = new WebSocket('ws://localhost:2345');

ws.onopen = () => {
    // 设置玩家名称
    ws.send(JSON.stringify({
        event: 'set_name',
        data: { name: 'Alice' }
    }));
    
    // 快速匹配
    ws.send(JSON.stringify({
        event: 'quick_match',
        data: { room_class: 'MyGameRoom' }
    }));
};

ws.onmessage = (event) => {
    const message = JSON.parse(event.data);
    console.log('收到消息:', message);
};

📚 核心 API

Room 类

房间是游戏逻辑的核心容器,提供完整的生命周期管理。

配置选项
代码语言:javascript
代码运行次数:0
运行
复制
protected function getDefaultConfig(): array
{
    return [
        'max_players' => 4,      // 最大玩家数
        'min_players' => 2,      // 最小玩家数
        'auto_start' => false,   // 是否自动开始
    ];
}
生命周期钩子
代码语言:javascript
代码运行次数:0
运行
复制
// 房间创建时(异步)
protectedfunction onCreate(): Generator
{
    $this->broadcast('room:created', ['message' => '房间已创建']);
    yield;
}

// 游戏开始时(异步)
protectedfunction onStart(): Generator
{
    $this->broadcast('game:start', ['message' => '游戏即将开始']);
    yield sleep(3);
}

// 游戏主循环(必须实现)
abstractprotectedfunction run(): Generator;

// 房间销毁时(异步)
protectedfunction onDestroy(): Generator
{
    $this->broadcast('room:destroyed', ['message' => '房间已销毁']);
    yield;
}

// 玩家加入时(同步)
protectedfunction onPlayerJoin(Player $player): void
{
    echo"{$player->getName()} 加入房间\n";
}

// 玩家离开时(同步)
protectedfunction onPlayerLeave(Player $player): void
{
    echo"{$player->getName()} 离开房间\n";
}

// 处理玩家消息(异步)
publicfunction onPlayerMessage(Player $player, string $event, mixed $data): Generator
{
    if ($event === 'action') {
        // 处理玩家动作
    }
    yield;
}
常用方法
代码语言:javascript
代码运行次数:0
运行
复制
// 广播消息
$this->broadcast('event_name', $data);
$this->broadcast('event_name', $data, $exceptPlayer); // 排除某玩家

// 异步广播(延迟)
yield from $this->broadcastAsync('event_name', $data, 2.0); // 延迟2秒

// 延迟执行
yield from $this->delay(5.0); // 延迟5秒

// 添加定时器
$timerId = $this->addTimer(1.0, function() {
    echo"每秒执行一次\n";
}, true); // true = 重复执行

// 移除定时器
$this->removeTimer($timerId);

// 玩家管理
$this->addPlayer($player);
$this->removePlayer($playerId);
$player = $this->getPlayer($playerId);
$players = $this->getPlayers();
$count = $this->getPlayerCount();

// 数据存储
$this->set('key', 'value');
$value = $this->get('key', 'default');

// 房间状态
$status = $this->getStatus(); // waiting, running, finished
$canStart = $this->canStart();

Player 类

封装玩家通信和状态管理。

代码语言:javascript
代码运行次数:0
运行
复制
// 创建玩家
$player = new Player('player_id', $connection, 'PlayerName');

// 发送消息
$player->send('event_name', ['data' => 'value']);

// 数据管理
$player->set('score', 100);
$score = $player->get('score', 0);
$hasScore = $player->has('score');

// 准备状态
$player->setReady(true);
$isReady = $player->isReady();

// 获取信息
$id = $player->getId();
$name = $player->getName();
$room = $player->getRoom();
$array = $player->toArray();

RoomManager 类

管理多个游戏房间。

代码语言:javascript
代码运行次数:0
运行
复制
$manager = new RoomManager();

// 创建房间
$room = $manager->createRoom(MyGameRoom::class, 'room_id', [
    'max_players' => 4
]);

// 玩家加入/离开房间
$manager->joinRoom($player, 'room_id');
$manager->leaveRoom($player);

// 获取房间
$room = $manager->getRoom('room_id');
$rooms = $manager->getRooms();
$playerRoom = $manager->getPlayerRoom($player);

// 快速匹配(自动创建或加入房间)
$room = $manager->quickMatch($player, MyGameRoom::class, [
    'max_players' => 4
]);

// 删除房间
yield from $manager->removeRoom('room_id');

// 统计信息
$stats = $manager->getStats();

GameServer 类

WebSocket 游戏服务器。

代码语言:javascript
代码运行次数:0
运行
复制
$server = new GameServer('0.0.0.0', 2345, [
    'name' => 'GameServer',
    'count' => 4,           // Worker 进程数
    'protocol' => 'websocket',
]);

$server->run();
内置系统事件

客户端可以发送以下系统事件:

事件

说明

数据

set_name

设置玩家名称

{name: "PlayerName"}

create_room

创建房间

{room_class: "ClassName", config: {...}}

join_room

加入房间

{room_id: "room_id"}

leave_room

离开房间

{}

quick_match

快速匹配

{room_class: "ClassName", config: {...}}

get_rooms

获取房间列表

{}

get_stats

获取统计信息

{}

🎯 示例

示例 1:简单倒计时游戏

运行:

代码语言:javascript
代码运行次数:0
运行
复制
php examples/SimpleGame.php

示例 2:卡牌游戏

运行:

代码语言:javascript
代码运行次数:0
运行
复制
php examples/CardGame.php

示例 3:WebSocket 猜数字游戏

启动服务器:

代码语言:javascript
代码运行次数:0
运行
复制
php examples/WebSocketServer.php

然后在浏览器中打开 examples/client.html 连接游戏服务器。

示例 4:高级游戏(新特性展示)🆕

展示日志、异常处理、持久化等新特性:

代码语言:javascript
代码运行次数:0
运行
复制
php examples/AdvancedGame.php

🆕 新特性使用

日志系统

代码语言:javascript
代码运行次数:0
运行
复制
use PfinalClub\AsyncioGamekit\Logger\LoggerFactory;
usePfinalClub\AsyncioGamekit\Logger\LogLevel;

// 配置日志
LoggerFactory::configure([
    'min_level' => LogLevel::INFO,
    'console' => ['enabled' => true, 'color' => true],
    'file' => [
        'enabled' => true,
        'path' => 'logs/game.log',
        'max_size' => 10 * 1024 * 1024,
    ],
]);

// 记录日志
LoggerFactory::info('Game started', ['room_id' => 'room_001']);
LoggerFactory::error('Error: {message}', ['message' => 'Connection lost']);

异常处理

代码语言:javascript
代码运行次数:0
运行
复制
use PfinalClub\AsyncioGamekit\Exceptions\RoomException;

try {
    $room->addPlayer($player);
} catch (RoomException $e) {
    // 获取结构化异常信息
    $player->send('error', [
        'message' => $e->getMessage(),
        'code' => $e->getCode(),
        'context' => $e->getContext()
    ]);
}

状态持久化

代码语言:javascript
代码运行次数:0
运行
复制
use PfinalClub\AsyncioGamekit\Persistence\{FileAdapter, RedisAdapter, RoomStateManager};

// 使用文件存储
$adapter = new FileAdapter('storage/game');
$stateManager = new RoomStateManager($adapter);

// 或使用 Redis(推荐)
$adapter = RedisAdapter::create('127.0.0.1', 6379);
$stateManager = new RoomStateManager($adapter);

// 保存和恢复房间状态
$stateManager->saveRoomState($room);
$state = $stateManager->getRoomState('room_001');

负载均衡

代码语言:javascript
代码运行次数:0
运行
复制
use PfinalClub\AsyncioGamekit\LoadBalance\{
    RoomDistributor,
    LeastConnectionsBalancer
};

// 创建负载均衡器
$balancer = new LeastConnectionsBalancer();
$distributor = new RoomDistributor($balancer);

// 注册工作进程
$distributor->registerWorker(1, ['connections' => 10]);
$distributor->registerWorker(2, ['connections' => 5]);

// 分配房间(会选择连接数最少的进程)
$workerId = $distributor->assignRoom('room_001');

单元测试

代码语言:javascript
代码运行次数:0
运行
复制
# 安装 PHPUnit
composer require --dev phpunit/phpunit

# 运行测试
./vendor/bin/phpunit

# 运行特定测试
./vendor/bin/phpunit tests/RoomTest.php

🏗️ 高级用法

自定义定时任务

代码语言:javascript
代码运行次数:0
运行
复制
protected function run(): Generator
{
    // 添加定时器
    $timerId = $this->addTimer(1.0, function() {
        $elapsed = time() - $this->get('start_time');
        $this->broadcast('game:timer', ['elapsed' => $elapsed]);
    }, true);
    
    $this->set('start_time', time());
    
    // 游戏逻辑
    yield sleep(60);
    
    // 清理定时器
    $this->removeTimer($timerId);
}

异步任务编排

代码语言:javascript
代码运行次数:0
运行
复制
use functionPfinalClub\Asyncio\{create_task, gather};

protectedfunction run(): Generator
{
    // 并发执行多个任务
    $task1 = create_task($this->taskA());
    $task2 = create_task($this->taskB());
    
    $results = yield gather($task1, $task2);
    
    // 继续游戏逻辑...
}

privatefunction taskA(): Generator
{
    yield sleep(2);
    return'Result A';
}

privatefunction taskB(): Generator
{
    yield sleep(1);
    return'Result B';
}

超时控制

代码语言:javascript
代码运行次数:0
运行
复制
use functionPfinalClub\Asyncio\wait_for;
usePfinalClub\Asyncio\TimeoutException;

protectedfunction run(): Generator
{
    try {
        // 等待玩家响应,最多10秒
        $result = yield wait_for($this->waitForPlayerAction(), 10.0);
    } catch (TimeoutException $e) {
        // 超时处理
        $this->broadcast('game:timeout', ['message' => '超时!']);
    }
}

房间间通信

代码语言:javascript
代码运行次数:0
运行
复制
// 通过 RoomManager 实现房间间通信
$roomManager = new RoomManager();

$room1 = $roomManager->getRoom('room_001');
$room2 = $roomManager->getRoom('room_002');

// Room1 广播消息给 Room2 的玩家
foreach ($room2->getPlayers() as $player) {
    $player->send('cross_room_message', ['from' => $room1->getId()]);
}

🎮 完整游戏示例

查看 examples/ 目录了解更多完整示例:

  • SimpleGame.php - 简单的倒计时游戏
  • CardGame.php - 回合制卡牌游戏
  • WebSocketServer.php - 完整的 WebSocket 游戏服务器
  • AdvancedGame.php 🆕 - 展示新特性的高级示例
  • client.html - 网页游戏客户端

🔧 配置建议

生产环境配置

代码语言:javascript
代码运行次数:0
运行
复制
$server = new GameServer('0.0.0.0', 2345, [
    'name' => 'ProductionGameServer',
    'count' => 8,  // 根据 CPU 核心数调整
]);

调试模式

代码语言:javascript
代码运行次数:0
运行
复制
// 开启 Workerman 调试模式
use Workerman\Worker;

Worker::$daemonize = false;
Worker::$stdoutFile = '/tmp/workerman.log';

📖 与 Python asyncio 对比

功能

Python asyncio

pfinal-asyncio-gamekit

协程定义

async def

function(): \Generator

等待协程

await expr

yield expr

睡眠

await asyncio.sleep(1)

yield sleep(1)

并发任务

asyncio.gather()

yield gather()

创建任务

asyncio.create_task()

create_task()

事件循环

asyncio.run()

run()

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-10-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 核心功能
  • 高级功能 🆕
  • 框架定位
  • 📦 安装
  • 📋 要求
  • 🚀 快速开始
    • 1. 创建你的第一个游戏房间
    • 2. 完整的 WebSocket 游戏服务器
  • 📚 核心 API
    • Room 类
      • 配置选项
      • 生命周期钩子
      • 常用方法
    • Player 类
    • RoomManager 类
    • GameServer 类
      • 内置系统事件
  • 🎯 示例
    • 示例 1:简单倒计时游戏
    • 示例 2:卡牌游戏
    • 示例 3:WebSocket 猜数字游戏
    • 示例 4:高级游戏(新特性展示)🆕
  • 🆕 新特性使用
    • 日志系统
    • 异常处理
    • 状态持久化
    • 负载均衡
    • 单元测试
  • 🏗️ 高级用法
    • 自定义定时任务
    • 异步任务编排
    • 超时控制
    • 房间间通信
  • 🎮 完整游戏示例
  • 🔧 配置建议
    • 生产环境配置
    • 调试模式
  • 📖 与 Python asyncio 对比
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档