Эх сурвалжийг харах

添加游戏大厅前端界面、游戏房间、前端界面、用户注册、用户登录界面

unknown 8 сар өмнө
parent
commit
8d11893adf

+ 122 - 0
source/wwwroot/game_hall.html

@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>游戏大厅</title>
+    <link rel="stylesheet" href="./css/common.css">
+    <link rel="stylesheet" href="./css/game_hall.css">
+</head>
+<body>
+    <div class="nav">网络五子棋对战游戏</div>
+    <!-- 整个页面的容器元素 -->
+    <div class="container">
+        <!-- 这个 div 在 container 中是处于垂直水平居中这样的位置的 -->
+        <div>
+            <!-- 展示用户信息 -->
+            <div id="screen"></div>
+            <!-- 匹配按钮 -->
+            <div id="match-button">开始匹配</div>
+        </div>
+    </div>
+
+    <script src="./js/jquery.min.js"></script>
+    <script>
+        ws_hdl = null;
+        //设置离开当前页面后立即断开websocket链接
+        window.onbeforeunload = function () {
+            ws_hdl.close();
+        }
+
+        // 获取玩家信息展示在游戏大厅与websocket长连接切换
+        function get_user_info() {
+            // 通过ajax向服务器发送获取用户信息请求
+            $.ajax({
+                url: "/info",
+                type: "get",
+                success: function(res) {
+                    var info_html = "<p>" + "姓名: " + res.username + "  积分:" + res.score + "</br>" + 
+                        "  战斗场次: " + res.total_count + "  胜利场次: " + res.win_count + "</p>";
+                    var screen_div = document.getElementById("screen");
+                    screen_div.innerHTML = info_html;
+
+                    // 获取玩家信息成功之后将http短连接协议切换为websocket长连接切换
+                    ws_url = "ws://" + location.host + "/hall";
+                    ws_hdl = new WebSocket(ws_url);
+                    // 为websocket各种触发事件设置回调函数
+                    ws_hdl.onopen = ws_onopen;
+                    ws_hdl.onclose = ws_onclose;
+                    ws_hdl.onerror = ws_onerror;
+                    ws_hdl.onmessage = ws_onmessage;
+                },
+                // 获取失败则返回登录页面并提示错误信息
+                error: function(xhr) {
+                    alert(JSON.stringify(xhr));
+                    location.replace("/login.html");
+                }
+            })
+        }
+
+        // 匹配按钮一共有两种状态 -- 未开始匹配(unmatched)和匹配中(matching)
+        var button_statu = "unmatched";
+        // 为匹配按钮添加点击事件
+        var button_ele = document.getElementById("match-button");
+        button_ele.onclick = function() {
+            // 在没有匹配状态下点击按钮,则发送开始匹配请求
+            if(button_statu == "unmatched") {
+                var req = { optype: "match_start" };
+                ws_hdl.send(JSON.stringify(req));
+            }
+            // 在匹配状态下点击按钮,则范式停止匹配请求
+            else if(button_statu == "matching") {
+                var req = { optype: "match_stop" };
+                ws_hdl.send(JSON.stringify(req));
+            }
+        }
+
+        function ws_onopen() {
+            console.log("游戏大厅长连接建立成功");
+        }
+        function ws_onclose() {
+            console.log("游戏大厅长连接断开");
+        }
+        function ws_onerror() {
+            console.log("游戏大厅长连接建立出错");
+        }
+
+        // 服务器响应处理函数
+        function ws_onmessage(evt) {
+            // 判断请求是否被成功处理,如果处理失败,则提示错误信息并跳转登录页面
+            var resp = JSON.parse(evt.data);
+            if(resp.result == false) {
+                alert(evt.data)
+                location.replace("/login.html");
+                return;
+            }
+            // 根据不同的响应类型进行不同的操作(成功建立大厅长连接、开始匹配、停止匹配、匹配成功以及未知响应类型)
+            if(resp.optype == "hall_ready") {} 
+            else if(resp.optype == "match_start") {
+                console.log("玩家已成功加入匹配队列");
+                button_statu = "matching";
+                button_ele.innerHTML = "匹配中... (点击停止匹配)";
+            } 
+            else if(resp.optype == "match_stop") {
+                console.log("玩家已从匹配队列中移除");
+                button_statu = "unmatched";
+                button_ele.innerHTML = "开始匹配";
+            } 
+            else if(resp.optype == "match_success") {
+                alert("匹配成功");
+                location.replace("/game_room.html");
+            }
+            else {
+                alert(evt.data);
+                location.replace("/login.html");
+            }
+        }
+        // 调用获取玩家信息函数
+        get_user_info();
+    </script>
+</body>
+</html>

+ 246 - 0
source/wwwroot/game_room.html

@@ -0,0 +1,246 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>游戏房间</title>
+    <link rel="stylesheet" href="css/common.css">
+    <link rel="stylesheet" href="css/game_room.css">
+</head>
+<body>
+    <div class="nav">网络五子棋对战游戏</div>
+    <div class="container">
+        <div id="chess_area">
+            <!-- 棋盘区域, 需要基于 canvas 进行实现 -->
+            <canvas id="chess" width="450px" height="450px"></canvas>
+            <!-- 显示区域 -->
+            <div id="screen"> 等待玩家连接中... </div>
+        </div>
+        <div id="chat_area" width="400px" height="300px">
+            <div id="chat_show">
+                <p id="self_msg">你好!</p></br>
+                <p id="peer_msg">你好!</p></br>
+            </div>
+            <div id="msg_show">
+                <input type="text" id="chat_input">
+                <button id="chat_button">发送</button>
+            </div>
+        </div>
+    </div>
+    <script>
+        let chessBoard = [];
+        let BOARD_ROW_AND_COL = 15;
+        let chess = document.getElementById('chess');
+        //获取chess控件区域2d画布
+        let context = chess.getContext('2d');
+
+        // 将http协议切换为游戏房间的websocket长连接协议
+        var ws_url = "ws://" + location.host + "/room";
+        var ws_hdl = new WebSocket(ws_url);
+
+        // 设置离开当前页面立即断开websocket连接
+        window.onbeforeunload = function () {
+            ws_hdl.close();
+        }
+
+        // 保存房间信息与是否轮到己方走棋
+        var room_info;
+        var is_me;
+
+        function initGame() {
+            initBoard();
+            // 背景图片
+            let logo = new Image();
+            logo.src = "image/sky.jpeg";
+            logo.onload = function () {
+                // 绘制图片
+                context.drawImage(logo, 0, 0, 450, 450);
+                // 绘制棋盘
+                drawChessBoard();
+            }
+        }
+        function initBoard() {
+            for (let i = 0; i < BOARD_ROW_AND_COL; i++) {
+                chessBoard[i] = [];
+                for (let j = 0; j < BOARD_ROW_AND_COL; j++) {
+                    chessBoard[i][j] = 0;
+                }
+            }
+        }
+        // 绘制棋盘网格线
+        function drawChessBoard() {
+            context.strokeStyle = "#BFBFBF";
+            for (let i = 0; i < BOARD_ROW_AND_COL; i++) {
+                //横向的线条
+                context.moveTo(15 + i * 30, 15);
+                context.lineTo(15 + i * 30, 430); 
+                context.stroke();
+                //纵向的线条
+                context.moveTo(15, 15 + i * 30);
+                context.lineTo(435, 15 + i * 30); 
+                context.stroke();
+            }
+        }
+        //绘制棋子
+        function oneStep(i, j, isWhite) {
+            if (i < 0 || j < 0) return;
+            context.beginPath();
+            context.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI);
+            context.closePath();
+            //createLinearGradient() 方法创建放射状/圆形渐变对象
+            var gradient = context.createRadialGradient(15 + i * 30 + 2, 15 + j * 30 - 2, 13, 15 + i * 30 + 2, 15 + j * 30 - 2, 0);
+            // 区分黑白子
+            if (!isWhite) {
+                gradient.addColorStop(0, "#0A0A0A");
+                gradient.addColorStop(1, "#636766");
+            } else {
+                gradient.addColorStop(0, "#D1D1D1");
+                gradient.addColorStop(1, "#F9F9F9");
+            }
+            context.fillStyle = gradient;
+            context.fill();
+        }
+        //棋盘区域的点击事件
+        chess.onclick = function (e) {
+            // 如果当前轮到对方走棋,则直接返回
+            if(is_me == false) {
+                return;
+            }
+            let x = e.offsetX;
+            let y = e.offsetY;
+            // 注意, 横坐标是列, 纵坐标是行
+            // 这里是为了让点击操作能够对应到网格线上
+            let col = Math.floor(x / 30);
+            let row = Math.floor(y / 30);
+            if (chessBoard[row][col] != 0) {
+                alert("当前位置已有棋子");
+                return;
+            }
+            // 发送走棋请求
+            send_chess(row, col);
+        }
+        // 发送走棋请求(websocket长连接通信,直接使用ws_hdl.send,而不是通过ajax)
+        function send_chess(r, c) {
+            var chess_info = {
+                optype: "put_chess",
+                room_id: room_info.room_id,
+                uid: room_info.uid,
+                row: r,
+                col: c
+            };
+            ws_hdl.send(JSON.stringify(chess_info));
+            console.log("click:" + JSON.stringify(chess_info));
+        }
+        // 聊天动作
+        // 给消息发送按钮添加点击事件
+        var chat_button_div = document.getElementById("chat_button");
+        chat_button_div.onclick = function() {
+            // 获取聊天输入框中的消息
+            var chat_msg = {
+                optype: "chat",
+                room_id: room_info.room_id,
+                uid: room_info.uid,
+                message: document.getElementById("chat_input").value
+            };
+            // 将消息发送给服务器
+            ws_hdl.send(JSON.stringify(chat_msg)); 
+        }        
+        // websocket各种事件的执行函数
+        ws_hdl.onopen = function() {
+            console.log("游戏房间长连接建立成功");
+        }
+        ws_hdl.onclose = function() {
+            console.log("游戏房间长连接断开");
+        }
+        ws_hdl.onerror = function() {
+            console.log("游戏房间长连接建立出错");
+        }
+        // 更新screen显示的内容
+        function set_screen(me) {
+            var screen_div = document.getElementById("screen");
+            if(me) screen_div.innerHTML = "轮到己方走棋...";
+            else screen_div.innerHTML = "轮到对方走棋...";
+        }
+        ws_hdl.onmessage = function(evt) {
+            console.log("message:" + evt.data);
+            var resp = JSON.parse(evt.data);
+            // 收到room_ready响应消息
+            if(resp.optype == "room_ready") {
+                // 保存房间信息与执棋用户
+                room_info = resp; 
+                // 规定白棋先走
+                is_me = (room_info.uid == room_info.white_id ? true : false);
+                if(resp.result == false) {
+                    alert(resp.reason);
+                    location.replace("/login.html");
+                } 
+                else {
+                    // 更新screen显示的内容
+                    set_screen(is_me);
+                    // 初始化游戏
+                    initGame();
+                }
+            }
+            // 收到put_chess响应消息
+            else if(resp.optype == "put_chess") {
+                // 判断走棋是否成功
+                if(resp.result == false) {
+                    alert(resp.reason);
+                    return;
+                }
+                // 下棋坐标为-1表示对方掉线
+                if(resp.row != -1 && resp.col != -1) {
+                    // 绘制棋子
+                    isWhite = (resp.uid == room_info.white_id ? true : false);
+                    oneStep(resp.col, resp.row, isWhite);
+                    // 更新棋盘
+                    chessBoard[resp.row][resp.col] = 1;                
+                }
+                // 更新执棋玩家
+                is_me = !is_me;
+                // 更新screen显示的内容
+                set_screen(is_me);
+                // 判断是否有胜利者
+                winner = resp.winner;
+                if(winner == 0) return;
+                // 更新screen信息
+                var screen_div = document.getElementById("screen");
+                if(winner == room_info.uid) screen_div.innerHTML = resp.reason;
+                else screen_div.innerHTML = "游戏失败,再接再厉";
+                // 在chess_area区域下方添加返回大厅按钮
+                var chess_area_div = document.getElementById("chess_area");
+                var button_div = document.createElement("div");
+                button_div.innerHTML = "返回大厅";
+                button_div.onclick = function() {
+                    ws_hdl.close();
+                    location.replace("/game_hall.html");
+                }
+                chess_area_div.appendChild(button_div);
+            }
+            // 收到chat响应消息
+            else if(resp.optype == "chat") {
+                if(resp.result == false) {
+                    alert(resp.reason);
+                    document.getElementById("chat_input").value = "";
+                    return;
+                }
+                // 创建一个子控件,将消息内嵌到其中
+                var msg_div = document.createElement("p");
+                msg_div.innerHTML = resp.message;
+                // 添加属性
+                if(resp.uid == room_info.uid) msg_div.setAttribute("id", "self_msg");
+                else msg_div.setAttribute("id", "peer_msg");
+                // 添加换行
+                var br_div = document.createElement("br");
+                // 将消息与换行子控件渲染到聊天显示框中
+                var msg_show_div = document.getElementById("chat_show");
+                msg_show_div.appendChild(msg_div);
+                msg_show_div.appendChild(br_div);
+                // 清空输入框内容
+                document.getElementById("chat_input").value = "";
+            }
+        }
+    </script>
+</body>
+</html>

+ 67 - 0
source/wwwroot/login.html

@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>登录</title>
+
+    <link rel="stylesheet" href="./css/common.css">
+    <link rel="stylesheet" href="./css/login.css">
+</head>
+<body>
+    <div class="nav">
+        网络五子棋对战游戏
+    </div>
+    <div class="login-container">
+        <!-- 登录界面的对话框 -->
+        <div class="login-dialog">
+            <!-- 提示信息 -->
+            <h3>登录</h3>
+            <!-- 这个表示一行 -->
+            <div class="row">
+                <span>用户名</span>
+                <input type="text" id="user_name">
+            </div>
+            <!-- 这是另一行 -->
+            <div class="row">
+                <span>密码</span>
+                <input type="password" id="password">
+            </div>
+            <!-- 提交按钮 -->
+            <div class="row">
+                <!--为按钮添加点击事件,调用登录函数-->
+                <button id="submit" onclick="login()">提交</button>
+            </div>
+        </div>
+
+    </div>
+
+    <script src="./js/jquery.min.js"></script>
+    <script>
+        function login() {
+            // 获取输入框中的username和password
+            var log_info = {
+                username: document.getElementById("user_name").value,
+                password: document.getElementById("password").value
+            };
+            // 通过ajax向服务器发送登录请求
+            $.ajax({
+                url: "/login",
+                type: "post",
+                data: JSON.stringify(log_info),
+                // 请求成功返回游戏大厅页面,请求失败则清空输入框中的内容并提示错误信息
+                success: function(res) {
+                    alert("登录成功");
+                    window.location.assign("/game_hall.html");
+                },
+                error: function(xhr) {
+                    document.getElementById("user_name").value = "";
+                    document.getElementById("password").value = "";
+                    alert(JSON.stringify(xhr));
+                }
+            })
+        }
+    </script>
+</body>
+</html>

+ 72 - 0
source/wwwroot/register.html

@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>注册</title>
+    <link rel="stylesheet" href="./css/common.css">
+    <link rel="stylesheet" href="./css/login.css">
+</head>
+<body>
+    <div class="nav">
+        网络五子棋对战游戏 
+    </div>
+    <div class="login-container">
+        <!-- 登录界面的对话框 -->
+        <div class="login-dialog">
+            <!-- 提示信息 -->
+            <h3>注册</h3>
+            <!-- 这个表示一行 -->
+            <div class="row">
+                <span>用户名</span>
+                <input type="text" id="user_name" name="username">
+            </div>
+            <!-- 这是另一行 -->
+            <div class="row">
+                <span>密码</span>
+                <input type="password" id="password" name="password">
+            </div>
+            <!-- 提交按钮 -->
+            <div class="row">
+                <!--给提交按钮添加点击事件 -- 调用注册函数reg-->
+                <button id="submit" onclick="reg()">提交</button>
+            </div>
+        </div>
+    </div> 
+
+    <script src="js/jquery.min.js"></script>
+    <script>
+        // 封装实现注册函数
+        function reg() {
+            // 获取输入框中的username和password,并将它们组织成json格式字符串
+            var reg_info = {
+                username: document.getElementById("user_name").value,
+                password: document.getElementById("password").value
+            };
+            // 通过ajax向服务器发送注册请求
+            $.ajax({
+                url: "/reg",
+                type: "post",
+                data: JSON.stringify(reg_info),
+                // 请求失败,清空输入框中的内容并提示错误信息;请求成功,则返回用户登录页面
+                success: function(res) {
+                    if(res.result == false) {
+                        document.getElementById("user_name").value = "";
+                        document.getElementById("password").value = "";
+                        alert(res.reason);
+                    } else {
+                        alert(res.reason);
+                        window.location.assign("/login.html");
+                    }
+                },
+                error: function(xhr) {
+                    document.getElementById("user_name").value = "";
+                    document.getElementById("password").value = "";
+                    alert(JSON.stringify(xhr));
+                }
+            })
+        }
+    </script>
+</body>
+</html>

+ 43 - 0
source/wwwroot/test_ws.html

@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Test Websocket</title>
+</head>
+<body>
+    <input type="text" id="message">
+    <button id="submit">提交</button>
+
+    <script>
+        // 创建 websocket 实例
+        let websocket = new WebSocket("ws://192.168.51.100:8888");
+        // 处理连接打开的回调函数
+        websocket.onopen = function() {
+            console.log("连接建立");
+        }
+        // 处理收到消息的回调函数
+        // 控制台打印消息
+        websocket.onmessage = function(e) {
+            console.log("收到消息: " + e.data);
+        }
+        // 处理连接异常的回调函数
+        websocket.onerror = function() {
+            console.log("连接异常");
+        }
+        // 处理连接关闭的回调函数
+        websocket.onclose = function() {
+            console.log("连接关闭");
+        }
+
+        // 实现点击按钮后, 通过 websocket 发送请求
+        let input = document.querySelector('#message');
+        let button = document.querySelector('#submit');
+        button.onclick = function() {
+            console.log("发送消息: " + input.value);
+            websocket.send(input.value);
+        }
+    </script>
+</body>
+</html>