需求:
一个手机打飞机游戏,一个房间2个飞机,然后各自控制飞机位置,子弹自动发射,看谁先挂;
本来是下载了win版聊天室框架GatewayWorker来搞,正好都合适 ,有房间,有各种存储,搞起来很顺;
本来的流程是某房间 a飞机位置发生变化->服务器 服务器同时下发给a,b a飞机的位置;
现在因为这样的方式不太好,比如延时,比如碰撞等都会产生问题;
所以改成:
a飞机位置发生变化->服务器 ,存储位置
服务器定时(1/60 s)下发给a,b 各自的最新位置;
这样的话碰撞什么的都可以在服务端计算,....
然后我现在的解决办法(都是在群里各位大大给的,感谢)
a飞机位置发生变化->服务器 ,存储位置到memcache;
新开一个worker去定时读取memcache的内容,凡是房间内有2个人的,下发位置给他们;
相关代码:
use \Workerman\Worker;
use \GatewayWorker\Lib\Gateway;
use \GatewayWorker\Lib\Store;
use \Workerman\Autoloader;
// 自动加载类
require_once __DIR__ . '/../../Workerman/Autoloader.php';
Autoloader::setRootPath(__DIR__);
$task = new Worker();
// 开启多少个进程运行定时任务,注意多进程并发问题
$task->count = 1;
$task->onWorkerStart = function($task)
{
$time_interval = 0.0166;
$time_interval = 2.5;
\Workerman\Lib\Timer::add($time_interval, function()
{
echo "task run\n";
//Gateway::
//Gateway::sendToClient(1, '3333');
$all_room_key = "ALL_ROOM";
$room_key_pre = "ROOM_";
$store = Store::instance('room');
$all_room = $store->get($all_room_key);
if ( $all_room )
{
foreach ( $all_room as $kk => $vv )
{
$room_id = $kk;
$room_info = $store->get($room_key_pre.$room_id);
if ( count($room_info) > 1 )
{
//{"d":{"y":68,"x":477,"uid":7,"timestamp":54.353},"cmd":"updatePosition"}
$time = explode ( " ", microtime () );
$timestamp = $time +$time ;
foreach ( $room_info as $kk2 => $vv2 )
{
Gateway::sendToClient($kk, '{"d":{"y":'.$vv2.',"x":'.$vv2.',"uid":'.$vv2.',"timestamp":'.$timestamp.'},"cmd":"updatePosition"}');
}
}
}
}
});
};
然后这样的话因为不是php内存直接处理, 如果客户端连接多,memcache压力估计非常大,求各位大大...
使用memcache不合理
每个房间每1/60秒读一次memcache,那么1000个房间每秒读取memcache就要读取60000次memcache,单台memcache服务器是很难支持这么高的访问量的。而且这样的设计也不合理。
基于Workerman做
坐标从php内存变量里面读是最快的,实际上不推荐所有游戏都去用gatewayWorker,直接基于workerman来做更灵活,更稳定,更高性能。例如下面的demo,是直接设置/读取php变量,性能更高,更稳定,扩展性更好。
以上代码亲测ok
多进程
上面的demo是单进程的,并且只能设置成单进程,目的是为了让同一个房间的用户都在一个进程里面,方便共享坐标等数据。
多进程的方法就是启动多个上面的实例,每个实例一个端口,客户端根据需要选择连哪个服务器。
例如
1、每个实例作为一个区,每个区多个房间。用户选择某个区的某个房间进入
2、也可以把端口号+roomid作为房间号。可以根据房间号得到端口号和实际的room_id
分布式部署
由于每个实例都是独立的,完全可以部署在不同的服务器上,组成一个集群。
房间号规则可以为 ip+port+room_id
扩展阅读
单个进程内如果有阻塞操作,比如读数据库/redis等存储,会导致进程阻塞,解决方法是建议一些任务进程,处理阻塞任务,然后异步通知游戏进程
参考 http://wenda.workerman.net/?/question/358
上面demo测试方法
demo使用的是Text协议,可以改成其它协议如websocket。
Text协议测试方法:
说明:
加入房间的包
{"mod":"Room", "act":"join", "args":{"room_id":13}}
更新坐标的包
{"mod":"Location", "act":"update", "args":{"x":13, "y":56}}
谢谢 walkor 等下我试试
多房间棋牌游戏好像也可以这样干
举报:加入房间下标是palyers,删除客户端下表是players,到时导致运行时删不掉用户会一直在!
已经更正,感谢你的举报