game_room.html 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>游戏房间</title>
  8. <link rel="stylesheet" href="css/common.css">
  9. <link rel="stylesheet" href="css/game_room.css">
  10. </head>
  11. <body>
  12. <div class="nav">网络五子棋对战游戏</div>
  13. <div class="container">
  14. <div id="chess_area">
  15. <!-- 棋盘区域, 需要基于 canvas 进行实现 -->
  16. <canvas id="chess" width="450px" height="450px"></canvas>
  17. <!-- 显示区域 -->
  18. <div id="screen"> 等待玩家连接中... </div>
  19. </div>
  20. <div id="chat_area" width="400px" height="300px">
  21. <div id="chat_show">
  22. <p id="self_msg">你好!</p></br>
  23. <p id="peer_msg">你好!</p></br>
  24. </div>
  25. <div id="msg_show">
  26. <input type="text" id="chat_input">
  27. <button id="chat_button">发送</button>
  28. </div>
  29. </div>
  30. </div>
  31. <script>
  32. let chessBoard = [];
  33. let BOARD_ROW_AND_COL = 15;
  34. let chess = document.getElementById('chess');
  35. //获取chess控件区域2d画布
  36. let context = chess.getContext('2d');
  37. // 将http协议切换为游戏房间的websocket长连接协议
  38. var ws_url = "ws://" + location.host + "/room";
  39. var ws_hdl = new WebSocket(ws_url);
  40. // 设置离开当前页面立即断开websocket连接
  41. window.onbeforeunload = function () {
  42. ws_hdl.close();
  43. }
  44. // 保存房间信息与是否轮到己方走棋
  45. var room_info;
  46. var is_me;
  47. function initGame() {
  48. initBoard();
  49. // 背景图片
  50. let logo = new Image();
  51. logo.src = "image/sky.jpeg";
  52. logo.onload = function () {
  53. // 绘制图片
  54. context.drawImage(logo, 0, 0, 450, 450);
  55. // 绘制棋盘
  56. drawChessBoard();
  57. }
  58. }
  59. function initBoard() {
  60. for (let i = 0; i < BOARD_ROW_AND_COL; i++) {
  61. chessBoard[i] = [];
  62. for (let j = 0; j < BOARD_ROW_AND_COL; j++) {
  63. chessBoard[i][j] = 0;
  64. }
  65. }
  66. }
  67. // 绘制棋盘网格线
  68. function drawChessBoard() {
  69. context.strokeStyle = "#BFBFBF";
  70. for (let i = 0; i < BOARD_ROW_AND_COL; i++) {
  71. //横向的线条
  72. context.moveTo(15 + i * 30, 15);
  73. context.lineTo(15 + i * 30, 430);
  74. context.stroke();
  75. //纵向的线条
  76. context.moveTo(15, 15 + i * 30);
  77. context.lineTo(435, 15 + i * 30);
  78. context.stroke();
  79. }
  80. }
  81. //绘制棋子
  82. function oneStep(i, j, isWhite) {
  83. if (i < 0 || j < 0) return;
  84. context.beginPath();
  85. context.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI);
  86. context.closePath();
  87. //createLinearGradient() 方法创建放射状/圆形渐变对象
  88. var gradient = context.createRadialGradient(15 + i * 30 + 2, 15 + j * 30 - 2, 13, 15 + i * 30 + 2, 15 + j * 30 - 2, 0);
  89. // 区分黑白子
  90. if (!isWhite) {
  91. gradient.addColorStop(0, "#0A0A0A");
  92. gradient.addColorStop(1, "#636766");
  93. } else {
  94. gradient.addColorStop(0, "#D1D1D1");
  95. gradient.addColorStop(1, "#F9F9F9");
  96. }
  97. context.fillStyle = gradient;
  98. context.fill();
  99. }
  100. //棋盘区域的点击事件
  101. chess.onclick = function (e) {
  102. // 如果当前轮到对方走棋,则直接返回
  103. if(is_me == false) {
  104. return;
  105. }
  106. let x = e.offsetX;
  107. let y = e.offsetY;
  108. // 注意, 横坐标是列, 纵坐标是行
  109. // 这里是为了让点击操作能够对应到网格线上
  110. let col = Math.floor(x / 30);
  111. let row = Math.floor(y / 30);
  112. if (chessBoard[row][col] != 0) {
  113. alert("当前位置已有棋子");
  114. return;
  115. }
  116. // 发送走棋请求
  117. send_chess(row, col);
  118. }
  119. // 发送走棋请求(websocket长连接通信,直接使用ws_hdl.send,而不是通过ajax)
  120. function send_chess(r, c) {
  121. var chess_info = {
  122. optype: "put_chess",
  123. room_id: room_info.room_id,
  124. uid: room_info.uid,
  125. row: r,
  126. col: c
  127. };
  128. ws_hdl.send(JSON.stringify(chess_info));
  129. console.log("click:" + JSON.stringify(chess_info));
  130. }
  131. // 聊天动作
  132. // 给消息发送按钮添加点击事件
  133. var chat_button_div = document.getElementById("chat_button");
  134. chat_button_div.onclick = function() {
  135. // 获取聊天输入框中的消息
  136. var chat_msg = {
  137. optype: "chat",
  138. room_id: room_info.room_id,
  139. uid: room_info.uid,
  140. message: document.getElementById("chat_input").value
  141. };
  142. // 将消息发送给服务器
  143. ws_hdl.send(JSON.stringify(chat_msg));
  144. }
  145. // websocket各种事件的执行函数
  146. ws_hdl.onopen = function() {
  147. console.log("游戏房间长连接建立成功");
  148. }
  149. ws_hdl.onclose = function() {
  150. console.log("游戏房间长连接断开");
  151. }
  152. ws_hdl.onerror = function() {
  153. console.log("游戏房间长连接建立出错");
  154. }
  155. // 更新screen显示的内容
  156. function set_screen(me) {
  157. var screen_div = document.getElementById("screen");
  158. if(me) screen_div.innerHTML = "轮到己方走棋...";
  159. else screen_div.innerHTML = "轮到对方走棋...";
  160. }
  161. ws_hdl.onmessage = function(evt) {
  162. console.log("message:" + evt.data);
  163. var resp = JSON.parse(evt.data);
  164. // 收到room_ready响应消息
  165. if(resp.optype == "room_ready") {
  166. // 保存房间信息与执棋用户
  167. room_info = resp;
  168. // 规定白棋先走
  169. is_me = (room_info.uid == room_info.white_id ? true : false);
  170. if(resp.result == false) {
  171. alert(resp.reason);
  172. location.replace("/login.html");
  173. }
  174. else {
  175. // 更新screen显示的内容
  176. set_screen(is_me);
  177. // 初始化游戏
  178. initGame();
  179. }
  180. }
  181. // 收到put_chess响应消息
  182. else if(resp.optype == "put_chess") {
  183. // 判断走棋是否成功
  184. if(resp.result == false) {
  185. alert(resp.reason);
  186. return;
  187. }
  188. // 下棋坐标为-1表示对方掉线
  189. if(resp.row != -1 && resp.col != -1) {
  190. // 绘制棋子
  191. isWhite = (resp.uid == room_info.white_id ? true : false);
  192. oneStep(resp.col, resp.row, isWhite);
  193. // 更新棋盘
  194. chessBoard[resp.row][resp.col] = 1;
  195. }
  196. // 更新执棋玩家
  197. is_me = !is_me;
  198. // 更新screen显示的内容
  199. set_screen(is_me);
  200. // 判断是否有胜利者
  201. winner = resp.winner;
  202. if(winner == 0) return;
  203. // 更新screen信息
  204. var screen_div = document.getElementById("screen");
  205. if(winner == room_info.uid) screen_div.innerHTML = resp.reason;
  206. else screen_div.innerHTML = "游戏失败,再接再厉";
  207. // 在chess_area区域下方添加返回大厅按钮
  208. var chess_area_div = document.getElementById("chess_area");
  209. var button_div = document.createElement("div");
  210. button_div.innerHTML = "返回大厅";
  211. button_div.onclick = function() {
  212. ws_hdl.close();
  213. location.replace("/game_hall.html");
  214. }
  215. chess_area_div.appendChild(button_div);
  216. }
  217. // 收到chat响应消息
  218. else if(resp.optype == "chat") {
  219. if(resp.result == false) {
  220. alert(resp.reason);
  221. document.getElementById("chat_input").value = "";
  222. return;
  223. }
  224. // 创建一个子控件,将消息内嵌到其中
  225. var msg_div = document.createElement("p");
  226. msg_div.innerHTML = resp.message;
  227. // 添加属性
  228. if(resp.uid == room_info.uid) msg_div.setAttribute("id", "self_msg");
  229. else msg_div.setAttribute("id", "peer_msg");
  230. // 添加换行
  231. var br_div = document.createElement("br");
  232. // 将消息与换行子控件渲染到聊天显示框中
  233. var msg_show_div = document.getElementById("chat_show");
  234. msg_show_div.appendChild(msg_div);
  235. msg_show_div.appendChild(br_div);
  236. // 清空输入框内容
  237. document.getElementById("chat_input").value = "";
  238. }
  239. }
  240. </script>
  241. </body>
  242. </html>