国产+高潮+在线,国产 av 仑乱内谢,www国产亚洲精品久久,51国产偷自视频区视频,成人午夜精品网站在线观看

實(shí)時(shí)戰(zhàn)斗游戲打飛機(jī)定時(shí)發(fā)送坐標(biāo)問題

ketle

需求:
一個(gè)手機(jī)打飛機(jī)游戲,一個(gè)房間2個(gè)飛機(jī),然后各自控制飛機(jī)位置,子彈自動(dòng)發(fā)射,看誰先掛;

本來是下載了win版聊天室框架GatewayWorker來搞,正好都合適 ,有房間,有各種存儲,搞起來很順;
本來的流程是某房間 a飛機(jī)位置發(fā)生變化->服務(wù)器 服務(wù)器同時(shí)下發(fā)給a,b a飛機(jī)的位置;
現(xiàn)在因?yàn)檫@樣的方式不太好,比如延時(shí),比如碰撞等都會產(chǎn)生問題;
所以改成:

a飛機(jī)位置發(fā)生變化->服務(wù)器 ,存儲位置
服務(wù)器定時(shí)(1/60 s)下發(fā)給a,b 各自的最新位置;
這樣的話碰撞什么的都可以在服務(wù)端計(jì)算,....

然后我現(xiàn)在的解決辦法(都是在群里各位大大給的,感謝)

a飛機(jī)位置發(fā)生變化->服務(wù)器 ,存儲位置到memcache;
新開一個(gè)worker去定時(shí)讀取memcache的內(nèi)容,凡是房間內(nèi)有2個(gè)人的,下發(fā)位置給他們;
相關(guān)代碼:

use \Workerman\Worker; 
use \GatewayWorker\Lib\Gateway;
use \GatewayWorker\Lib\Store; 
use \Workerman\Autoloader;
// 自動(dòng)加載類
require_once __DIR__ . '/../../Workerman/Autoloader.php';
Autoloader::setRootPath(__DIR__);

$task = new Worker();
// 開啟多少個(gè)進(jìn)程運(yùn)行定時(shí)任務(wù),注意多進(jìn)程并發(fā)問題
$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"}');
                    }
                }
            }
        }

    });
};

然后這樣的話因?yàn)椴皇莗hp內(nèi)存直接處理, 如果客戶端連接多,memcache壓力估計(jì)非常大,求各位大大...

10055 5 10
5個(gè)回答

walkor 打賞

使用memcache不合理
每個(gè)房間每1/60秒讀一次memcache,那么1000個(gè)房間每秒讀取memcache就要讀取60000次memcache,單臺memcache服務(wù)器是很難支持這么高的訪問量的。而且這樣的設(shè)計(jì)也不合理。

基于Workerman做
坐標(biāo)從php內(nèi)存變量里面讀是最快的,實(shí)際上不推薦所有游戲都去用gatewayWorker,直接基于workerman來做更靈活,更穩(wěn)定,更高性能。例如下面的demo,是直接設(shè)置/讀取php變量,性能更高,更穩(wěn)定,擴(kuò)展性更好。

<?php
use Workerman\Worker;
use Workerman\Lib\Timer;
require_once './Workerman/Autoloader.php';
// 初始化一個(gè)worker容器
$worker = new Worker('Text://0.0.0.0:6001');
// 全局對象,保存當(dāng)前進(jìn)程內(nèi)的房間數(shù)據(jù),每個(gè)房間兩個(gè)玩家(連接對象)
// 格式[room_id1=>, room_id2=>
$rooms = array();
// 全局變量。保存當(dāng)前的連接對象,方便在任意函數(shù)中獲得當(dāng)前連接對象
$current_connection = null;
// 固定為1
$worker->count = 1;
// tcp連接建立時(shí),初始化坐標(biāo)
$worker->onConnect = function($connection)
{
    $connection->x = 0;
    $connection->y = 0;
    // 發(fā)送當(dāng)前連接的id
    $connection->send('{"type":"connection_id", "id":"'.$connection->id.'"}');
};
// 當(dāng)有客戶端發(fā)來消息時(shí)執(zhí)行的回調(diào)函數(shù)
$worker->onMessage = function($connection, $data)
{
    // 全局保存當(dāng)前對象,方便給當(dāng)前連接發(fā)送數(shù)據(jù)
    global $current_connection;
    $current_connection = $connection;
    // 客戶端傳遞的數(shù)據(jù)格式類似 
    // {"mod":"Room", "act":"join", "args":{"room_id":13}}
    $data = json_decode($data, true);
    $class = $data;
    $method = $data;
    $callback = array($class, $method);
    // 執(zhí)行某個(gè)類的某個(gè)方法
    if(is_callable($callback))
    {
        call_user_func_array($callback, $data);
    }
    else
    {
        $connection->send('{"type":"err", "msg":"invalid packet"}');
    }
};
// 當(dāng)有客戶端連接斷開時(shí)
$worker->onClose = function($connection)
{
    global $rooms;
    $room_id = isset($connection->room_id) ? $connection->room_id : null;
    // 還沒加入房間
    if($room_id === null)
    {
        return;
    }
    // 清理房間信息
    unset($rooms);
    // 如果有定時(shí)器,清理定時(shí)器
    $timer_id = isset($rooms) ? $rooms : 0;
    if($timer_id)
    {
        Timer::del($timer_id);
        unset($rooms);
    }
    if(empty($rooms)) {
        unset($rooms);
    }
    // 廣播退出事件
    Room::broadcast($room_id, array("type"=>"logout", "id"=>$connection->id));
};
// 運(yùn)行所有的worker(其實(shí)當(dāng)前只定義了一個(gè))
Worker::runAll();

// 坐標(biāo)類
class Location
{
    public static function update($x, $y)
    {
        global $current_connection;
        $current_connection->x = $x;
        $current_connection->y = $y;
    }
}

// 房間類
class Room
{
    // 加入房間
    // {"mod":"Room", "act":"join", "args":{"room_id":13}}
    public static function join($room_id)
    {
        global $rooms, $current_connection;
        $players = self::getPlayers($room_id);
        $player_count = count($players);
        // 房間已經(jīng)滿了
        if($player_count === 2)
        {
            return $current_connection->send('{"type":"err", "msg":"room full"}');
        }
        // 加入房間
        $rooms = $current_connection;
        // 用一個(gè)臨時(shí)屬性room_id存儲當(dāng)前連接的房間號
        $current_connection->room_id = $room_id;
        // 已經(jīng)兩人,開始戰(zhàn)斗
        if($player_count+1 === 2)
        {
            // 發(fā)個(gè)包給客戶端,開始戰(zhàn)斗
            self::broadcastBeginFight($room_id);
            // 建立一個(gè)定時(shí)器發(fā)送當(dāng)前房間($room_id)玩家的坐標(biāo)
            $rooms = Timer::add(1, 'Room::broadcastLocation', array($room_id));
            var_export($rooms);
        }

    }
    // 廣播開始戰(zhàn)斗
    public static function broadcastBeginFight($room_id)
    {
        $data = array(
            'type' => 'begin_fight'
        );
        self::broadcast($room_id, $data);
    }
    // 廣播坐標(biāo)
    public static function broadcastLocation($room_id)
    {
        list($player1_connection, $player2_connection) = array_values(self::getPlayers($room_id));
        $location_data = array(
            'type' => 'location',
            'data' => array(
                array($player1_connection->id, $player1_connection->x, $player1_connection->y),
                array($player2_connection->id, $player2_connection->x, $player2_connection->y)
            )
        );
        self::broadcast($room_id, $location_data);
    }
    // 向某個(gè)room廣播
    public static function broadcast($room_id, array $data)
    {
        $data_buffer = json_encode($data);
        foreach(self::getPlayers($room_id) as $connection)
        {
            $connection->send($data_buffer);
        }
    }
    // 獲得某個(gè)room的玩家連接對象
    protected static function getPlayers($room_id)
    {
        global $rooms;
        if(!isset($rooms))
        {
            return array();
        }
        $connections = $rooms;
        return $connections;
    }

}

以上代碼親測ok

多進(jìn)程
上面的demo是單進(jìn)程的,并且只能設(shè)置成單進(jìn)程,目的是為了讓同一個(gè)房間的用戶都在一個(gè)進(jìn)程里面,方便共享坐標(biāo)等數(shù)據(jù)。

多進(jìn)程的方法就是啟動(dòng)多個(gè)上面的實(shí)例,每個(gè)實(shí)例一個(gè)端口,客戶端根據(jù)需要選擇連哪個(gè)服務(wù)器。
例如
1、每個(gè)實(shí)例作為一個(gè)區(qū),每個(gè)區(qū)多個(gè)房間。用戶選擇某個(gè)區(qū)的某個(gè)房間進(jìn)入
2、也可以把端口號+roomid作為房間號??梢愿鶕?jù)房間號得到端口號和實(shí)際的room_id

分布式部署
由于每個(gè)實(shí)例都是獨(dú)立的,完全可以部署在不同的服務(wù)器上,組成一個(gè)集群。
房間號規(guī)則可以為 ip+port+room_id

擴(kuò)展閱讀
單個(gè)進(jìn)程內(nèi)如果有阻塞操作,比如讀數(shù)據(jù)庫/redis等存儲,會導(dǎo)致進(jìn)程阻塞,解決方法是建議一些任務(wù)進(jìn)程,處理阻塞任務(wù),然后異步通知游戲進(jìn)程
參考 http://wenda.workerman.net/?/question/358

  • 暫無評論
walkor 打賞

上面demo測試方法
demo使用的是Text協(xié)議,可以改成其它協(xié)議如websocket。
Text協(xié)議測試方法:

telnet 127.0.0.1 6001
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
{"type":"connection_id", "id":"2"}
{"mod":"Room", "act":"join", "args":{"room_id":13}}
{"type":"begin_fight"}
{"type":"location","data":}
{"type":"location","data":}
{"mod":"Location", "act":"update", "args":{"x":13, "y":56}}
{"type":"location","data":}
{"type":"location","data":}
{"type":"location","data":}
{"type":"location","data":}
{"type":"location","data":}
{"type":"location","data":}
{"type":"location","data":}
{"type":"location","data":}

說明:
加入房間的包
{"mod":"Room", "act":"join", "args":{"room_id":13}}
更新坐標(biāo)的包
{"mod":"Location", "act":"update", "args":{"x":13, "y":56}}

  • 暫無評論
ketle

謝謝 walkor 等下我試試

  • 暫無評論
wk617070321

多房間棋牌游戲好像也可以這樣干

  • 暫無評論
muyu

舉報(bào):加入房間下標(biāo)是palyers,刪除客戶端下表是players,到時(shí)導(dǎo)致運(yùn)行時(shí)刪不掉用戶會一直在!

  • walkor 2017-10-10

    已經(jīng)更正,感謝你的舉報(bào)

年代過于久遠(yuǎn),無法發(fā)表回答
??