PHP + SWOOLE 实现弹幕功能

HTML + JS: 【网上找到弹幕代码】

<meta charset="utf-8"/>
<div class="container">
    <div id="content" class="content">
        <img src="./1.png"/>
    </div>
    <div class="content-opt">
        <div id="content-text" class="content-text"></div>
        <div class="content-input">
            <input id="text" type="text">
            <button id="send">发送</button>
        </div>
    </div>
</div>

<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<style>
* {
box-sizing: border-box;
outline: none;
}

p {
margin: .5em;
word-break: break-all;
}

.container {
position: relative;
width: 700px;
height: 500px;
margin: auto;
padding-right: 200px;
}

.content {
width: 100%;
height: 100%;
border: 1px solid #ccc;
}

.content-opt {
position: absolute;
top: 0;
right: 0;
width: 200px;
height: 100%;
}

.content-text {
height: calc(100% - 30px);
margin-bottom: 30px;
border: 1px solid #ccc;
overflow: auto;
}

.content-input {
position: absolute;
bottom: 0;
width: 100%;
height: 30px;
border: 1px solid #ccc;
}
.content-input input {
width: 70%;
padding: 2px;
border-radius: 5px;
}

.content-input button {
padding: 3px 10px;
border: none;
border-radius: 5px;
background: rgb(90, 154, 214);
}
</style>
<script>

    (function() {
        class Barrage {
            constructor(id) {
                this.domList = [];
                this.dom = document.querySelector('#' + id);
                if (this.dom.style.position == '' || this.dom.style.position == 'static') {
                    this.dom.style.position = 'relative';
                }
                this.dom.style.overflow = 'hidden';
                let rect = this.dom.getBoundingClientRect();
                this.domWidth = rect.right - rect.left;
                this.domHeight = rect.bottom - rect.top;
            }

            shoot(text) {
                let div = document.createElement('div');
                div.style.position = 'absolute';
                div.style.left = this.domWidth + 'px';
                div.style.top = (this.domHeight - 20) * +Math.random().toFixed(2) + 'px';
                div.style.whiteSpace = 'nowrap';
                div.style.color = '#' + Math.floor(Math.random() * 256).toString(10);
                div.innerHTML = text;
                this.dom.appendChild(div);
//                $(this).append(div);

                let roll = (timer) =>{
                    let now = +new Date();
                    roll.last = roll.last || now;
                    roll.timer = roll.timer || timer;
                    let left = div.offsetLeft;
                    let rect = div.getBoundingClientRect();
                    if (left < (rect.left - rect.right)) {
                        this.dom.removeChild(div);
                    } else {
                        if (now - roll.last >= roll.timer) {
                            roll.last = now;
                            left -= 3;
                            div.style.left = left + 'px';
                        }
                        requestAnimationFrame(roll);
                    }
                }
                roll(50 * +Math.random().toFixed(2));
            }

        }

        let barage = new Barrage('content');
         function appendList(text) {
//            let p = document.createElement('p');
//            p.innerText = text;
//            document.querySelector('#content-text').appendChild(p);
            $('#content-text').append( '<p>'+text+'</p>');
        }

        document.querySelector('#send').onclick = () =>{
            let text = document.querySelector('#text').value;

//            alert(text);
            // 弹幕信息推送到服务端
            var json = '{"type":"danmu","room_id":'+room_id+',"content":"'+text+'"}';

            websocket.send( json );

//        barage.shoot(text);
//
//        appendList(text);
        };

        const textList = [
        ];
        textList.forEach((s) =>{
            barage.shoot(s);
            appendList(s);
        });



        var room_id = 1;
        var wsServer = 'ws://**.**.**.**:9501';
        var websocket = new WebSocket(wsServer);
        var user_name = '用户'+ Math.ceil(Math.random()*10000);
        websocket.onopen = function (evt) {
            console.log("Connected to WebSocket server.");
            var json = '{"type":"connect","user_name" : "'+user_name+'","room_id":'+room_id+' }';
            console.log( '房间的数据:' + json );
            websocket.send(  json );
        };

        websocket.onclose = function (evt) {
            console.log("Disconnected");
        };

        websocket.onmessage = function (evt) {
            console.log('Retrieved data from server: ' + evt.data);


            var obj = JSON.parse( evt.data );

            if( obj.type == 'danmu' ){
                var text = obj.content;
                barage.shoot(text);
                appendList(text);
            }

        };

        websocket.onerror = function (evt, e) {
            console.log('Error occured: ' + evt.data);
        };

 })();


</script>

php代码:

<?php
/**
 * Created by PhpStorm.
 * User: LiKang
 * Date: 2019/8/26
 * Time: 14:16
 */

//创建websocket服务器对象,监听0.0.0.0:9501端口
$ws = new swoole_websocket_server( "0.0.0.0", 9501 );

//监听WebSocket连接打开事件
$ws->on('open', function ($ws, $request) {
    $ws->push( $request->fd, json_encode([]) );
});

//监听WebSocket消息事件
$ws->on('message', function ($ws, $frame) {

    $data = json_decode( $frame -> data , true  );

    $danmu_obj = new DanMu();

    $data['fd'] = $frame -> fd;

    if( $data['type'] == 'connect' ){

        $data = $danmu_obj ->Connect( $data );

        $return = [
            'type' => 'join',
            'data' => $data
        ];

        $ws->push($frame->fd, json_encode( $return )  );
    }elseif( $data['type'] == 'danmu' ){

        # 接受用户的弹幕信息,并且通知到房间的所有人
        $room_user = $danmu_obj -> getRoomUser( $data['room_id'] );

        foreach( $room_user  as $k => $v )
        {
            if( $v['fd'] == $frame ->fd  ){
                $user_name = $v['user_name'];
                break;
            }
        }

        $message_data = [
            'content' => '<span class="name">'.$user_name
                .'</span> : '.$data['content'],
            'type'=>'danmu'
        ];

        foreach( $room_user as $k => $v ){
            var_dump($v);
            $ws -> push( $v['fd'] , json_encode( $message_data ) );
        }

    }

//    echo "Message: {$frame->data}\n";
});
//监听WebSocket连接关闭事件
$ws->on('close', function ($ws, $fd) {
    echo "client-{$fd} is closed\n";
});

$ws->start();


class DanMu{
    public $redis_obj;

    public function __construct()
    {
        $this->redis_obj = new Swoole\Coroutine\Redis();

        $this->redis_obj->connect('127.0.0.1', 6379);
    }

    /**
     * 用户进入房间,加入对应的房间
     */
    public function Connect( $data )
    {

        $this_join = $this -> joinRoom( $data  , $data['room_id'] );

        return $this_join;

    }

    /**
     * @param $data
     * @param $room_id
     */
    private function joinRoom( $data , $room_id )
    {
        $key = 'Room:Room_' . $room_id ;

        $json  = $this -> redis_obj -> get( $key );

        $room_data = json_decode( $json  ,true  );

        $this_join = [
            [
                'user_name' => $data['user_name'],
                'room_id' => $data['room_id'],
                'fd' => $data['fd']
            ]
        ];


        $all = array_merge( (array) $room_data , $this_join  );

        $this -> redis_obj -> set( $key , json_encode($all) );

        return $this_join;

    }

    public function getRoomUser( $room_id  ){
        $key = 'Room:Room_' . $room_id ;

        $json  = $this -> redis_obj -> get( $key );

        $room_data = json_decode( $json  ,true  );

        return $room_data;
    }

}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奇葩也是花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值