首页 > 技术文章 > 8、WebSocket实现聊天系统

pxlsdz 2022-01-06 10:50 原文

源码地址https://gitee.com/pxlsdz/hyld

演示地址http://121.199.59.80/hyld/

修复Bug

多人游戏时,一个窗口接收q,每个窗口都会出发q命令。

解决:

game/static/js/src/playground/palyer/zbase.js

this.playground.game_map.$canvas.keydown(function (e) {// 监听键盘按键

game/static/js/src/playground/game_map/zbase.js

this.$canvas = $(`<canvas tabindex=0></canvas>`);

start() {
    this.$canvas.focus(); // 聚焦窗口
}

前端

输入框+ 类图历史记录框

game/static/js/src/playground/chat_field/zbase.js

class ChatField {
    constructor(playground) {
        this.playground = playground;

        this.$history = $(`<div class = "hyld-game-chat-field-history">聊天记录</div>`);
        this.$input = $(`<input type="text" class="hyld-game-chat-field-input">`);

        this.$history.hide();
        this.$input.hide();

        this.func_id = null; // 防止监听函数定时消失不恰当

        this.playground.$playground.append(this.$history);
        this.playground.$playground.append(this.$input);

        this.start();
    }

    start() {
        this.add_listening_events();
    }

    add_listening_events() {
        let outer = this;

        this.$input.keydown(function (e) {
            if (e.which === 27) {  // ESC
                outer.hide_input();
                return false;
            } else if (e.which === 13) { // ENTER
                let username = outer.playground.root.settings.username;
                let text = outer.$input.val();
                if (text) {
                    outer.$input.val(""); // 清空输入框
                    outer.add_message(username, text);
                    outer.playground.mps.send_message(username, text);
                }
                return false;
            }
        });
    }

    render_message(message) {
        return $(`<div>${message}</div>`);
    }

    add_message(username, text) {
        this.show_history();
        let message = `[${username}]${text}`;
        this.$history.append(this.render_message(message));
        this.$history.scrollTop(this.$history[0].scrollHeight);
    }

    show_history() {
        let outer = this;
        this.$history.fadeIn();

        if (this.func_id) clearTimeout(this.func_id);
        this.func_id = setTimeout(function () {
            outer.$history.fadeOut();
            outer.func_id = null;
        }, 3000);
    }

    show_input() {
        this.show_history();

        this.$input.show();
        this.$input.focus();
    }

    hide_input() {
        this.$input.hide();
        this.playground.game_map.$canvas.focus();
    }
}
send_message(username, text) {
    console.log(username);
    let outer = this;
    this.ws.send(JSON.stringify({
        'event': "message",
        'uuid': outer.uuid,
        'username': username,
        'text': text,
    }));
}

receive_message(uuid, username, text) {
    console.log(username);
    this.playground.chat_field.add_message(username, text);
}

后端

async def message(self, data):
    await self.channel_layer.group_send(
        self.room_name,
        {
            'type': "group_send_event",
            'event': "message",
            'uuid': data['uuid'],
            'username': data['username'],
            'text': data['text'],
        }
    )

async def group_send_event(self, data):
    await self.send(text_data=json.dumps(data))

# 接收前端信息
async def receive(self, text_data):
    data = json.loads(text_data)
    event = data['event']
    if event == "create_player":
        await self.create_player(data)
    elif event == "move_to":
        await self.move_to(data)
    elif event == "shoot_fireball":
        await self.shoot_fireball(data)
    elif event == "attack":
        await self.attack(data)
    elif event == "blink":
        await self.blink(data)
    elif event == "message":
        await self.message(data)

推荐阅读