[網頁五子棋][對戰模塊]前后端交互接口(建立連接、連接響應、落子請求/響應),客戶端開發(實現棋盤/棋子繪制)

文章目錄

  • 約定前后端交互接口
    • 建立連接
    • 建立連接響應
    • 針對"落子"的請求和響應
  • 客戶端開發
    • 實現棋盤/棋子繪制
    • 部分邏輯解釋

約定前后端交互接口

對戰模塊和匹配模塊使用的是兩套邏輯,使用不同的 websocket 的路徑進行處理,做到更好的耦合

建立連接

ws://127.0.0. 1:8080/game

建立連接響應

服務器要生成一些游戲的初始信息,通過這個響應告訴客戶端

{message: 'gameReady',  // 消息的類別:游戲就緒ok: true,reason: '',roomId: '12345678',    // 玩家所處在的房間idthisUserId: 1,         // 玩家自己的idthatUserId: 2,         // 玩家的對手的idwhiteUser: 1           // 哪個玩家執白字(先手)
};
  • 這些都是玩家匹配成功之后,要由服務器生成的,然后把這個內容返回給瀏覽器

針對"落子"的請求和響應

請求:

{message: 'putChess',userId: 1,row: 0,        // 落子的坐標,往哪一行,哪一列來落子
}
  • 建議使用行和列,而不是 xy
    • row => ycol => x
    • 后面的代碼中,需要使用二維數組來表示這個棋盤,通過下標取二維數組
    • [row] => [y][col] => [x]
    • 如果使用 xy,就很別扭,和我們日常表示相悖

響應:

{message: 'putChess',userId: 1,row: 0,col: 0,winner: 0
}
  • winner 表示當前是否分出勝負
    • 如果 winner0,表示勝負未分,還需要繼續往下對戰
    • 如果 winner0,表示當前的獲勝方的用戶 id

以上交互接口的設計,其實也不一定非得按照剛才這樣寫的這種格式來進行約定,也可以有其他的約定方式

  • 不管是哪種格式,只要能夠解決我們的問題,并且編寫代碼的時候簡單方便即可

客戶端開發

實現棋盤/棋子繪制

創建 js/app.js

  • 我們不需要理解這部分內容,只需要復制粘貼即可
  • 使用一個二維數組來表示棋盤。雖然勝負是通過服務器判定的,但是客戶端的棋盤可以避免“一個位置重復落子”這樣的情況
  • oneStep 函數起到的效果是在一個指定的位置上繪制一個棋子,可以區分出繪制白子還是黑子,參數是橫坐標和縱坐標,分別對應行和列
  • onlick 來處理用戶點擊事件,當用戶點擊的時候通過這個函數來控制繪制棋子
  • me 變量用來表示當前是否輪到我落子;over 變量用來表示游戲結束
  • 這個代碼中會用到一個背景圖,放到 image 目錄中即可
// 定義全局變量,表示游戲初始化信息
let gameInfo = {  roomId: null,  thisUserId: null,  thatUserId: null,  isWhite: true,  
}  //  
// 設定界面顯示相關操作  
//  function setScreenText(me) {  let screen = document.querySelector('#screen');  if (me) {  screen.innerHTML = "輪到你落子了!";  } else {  screen.innerHTML = "輪到對方落子了!";  }  
}  //  
// 初始化 websocket//  // TODO  //  
// 初始化一局游戲  
//  
function initGame() {  // 是我下還是對方下. 根據服務器分配的先后手情況決定  let me = gameInfo.isWhite;  // 游戲是否結束  let over = false;  let chessBoard = [];  //初始化chessBord數組(表示棋盤的數組)  for (let i = 0; i < 15; i++) {  chessBoard[i] = [];  for (let j = 0; j < 15; j++) {  chessBoard[i][j] = 0;  }  }  let chess = document.querySelector('#chess');  let context = chess.getContext('2d');  context.strokeStyle = "#BFBFBF";  // 背景圖片  let logo = new Image();  logo.src = "image/五子棋棋盤.jpg"  logo.onload = function () {  context.drawImage(logo, 0, 0, 450, 450);  initChessBoard();  }  // 繪制棋盤網格  function initChessBoard() {  for (let i = 0; i < 15; 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();  }  }  // 繪制一個棋子, me 為 true    function oneStep(i, j, isWhite) {  context.beginPath();  context.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI);  context.closePath();  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 (over) {  return;  }  if (!me) {  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) {  // 發送坐標給服務器, 服務器要返回結果  send(row, col);  // 留到瀏覽器收到落子響應的時候再處理(收到響應再來畫棋子)  oneStep(col, row, gameInfo.isWhite);  chessBoard[row][col] = 1;  }  }  // TODO 實現發送落子請求邏輯和處理落子響應邏輯  
}  initGame();

canvasHTML5 引入的一個標簽,畫布

  • “可以在畫布上畫畫”
  • 此處棋盤和棋子,都是畫上去的。canvas 這個標簽有一組配套的 jscanvas api,通過這個 api 就可以實現一些“畫畫”的效果
    • 例如,展示一個棋盤,就畫很多的直線,就能構成棋盤的網格
    • 表示一個棋子,就畫一個圓圈,并填充上顏色
    • 還需要響應點擊事件,在鼠標落子的地方來畫圓圈
  • canvas api 里面能做的事情比較多,比較復雜,不是重點

部分邏輯解釋

image.png|337

  • 表示當前游戲中的棋盤,通過這個棋盤來表示當前哪個位置上有子了
  • 當玩家點擊的時候,如果有子的位置就不能再繼續落子了
  • 0 用來表示是空閑位置,非 0 表示已經有子了

image.png|334

  • 針對 chess (棋盤 canvas) 設定了點擊回調
  • e 是點擊回調中的事件參數,這里就會記錄點擊的實際位置 (坐標)
  • Math.floor(x/30) 是為了讓點擊操作能夠對應到網格線上
    • 總體的棋盤尺寸是 450px * 450px,整個棋盤上面是 15行15列
    • 每一行每一列占用的尺寸就是 30px
  • oneStep 就是走一步 (里面繪制一個棋子)
  • 標記為 1,就是這個位置有子,不能落子了

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/82932.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/82932.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/82932.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

電工基礎【2】自鎖、互鎖、正反轉電路

04 自鎖、正反轉電路 我們講一下這個自鎖和正反轉。 自鎖電路圖示例圖 加了一個這個 KM1 自鎖。加了 KM1 的輔助觸頭&#xff0c;它怎么實現呢&#xff1f;它怎么就自鎖了呢&#xff1f;沒加它的時候為什么是點動&#xff1f;加它為什么自鎖&#xff1f; 講解一下。首先我們…

TypeScript 中感嘆號(!)兩種位置用法

這是一個非常好的問題&#xff01; 在 TypeScript 中&#xff0c;感嘆號&#xff08;!&#xff09;有兩種位置用法&#xff0c;它們含義完全不同&#xff1a; ? 一、后置感嘆號 !&#xff08;非空斷言&#xff09; process.env.ADMIN_PRIVATE_KEY! ? 作用&#xff1a; 告…

t014-項目申報管理系統 【springBoot 含源碼】

項目演示視頻 摘 要 傳統信息的管理大部分依賴于管理人員的手工登記與管理&#xff0c;然而&#xff0c;隨著近些年信息技術的迅猛發展&#xff0c;讓許多比較老套的信息管理模式進行了更新迭代&#xff0c;項目信息因為其管理內容繁雜&#xff0c;管理數量繁多導致手工進行…

【C++】STL詳解(四)---Stack和Queue

文章目錄 Stack定義方式使用方式 Queue定義方式使用方式 Stack Stack是一種容器&#xff0c;是基本的數據結構之一&#xff0c;特點是先進后出。 定義方式 方式一&#xff1a;普通定義方式 stack<int> st1;方式二&#xff1a; stack<int,vector<int>> …

解決 xmlsec.InternalError: (-1, ‘lxml xmlsec libxml2 library version mismatch‘)

解決 xmlsec.InternalError: (-1, ‘lxml & xmlsec libxml2 library version mismatch’) 錯誤信息如下&#xff1a; Traceback (most recent call last):File "/home/mobsf/Mobile-Security-Framework-MobSF/manage.py", line 18, in <module>execute_f…

SpringBoot自定義實體類字段的校驗注解

在Spring Boot項目中&#xff0c;我們經常需要對請求參數進行格式或業務規則的校驗。雖然Spring Boot提供了如NotNull、Size等基礎校驗注解&#xff0c;但在實際開發中往往無法滿足復雜的業務需求。但是在Controller層寫大量的 if 語句的判斷邏輯又實在不優雅&#xff0c;好在 …

實現單例模式的6種方法(Python)

目錄 一. 基于模塊的實現(簡單&#xff0c;易用) 二. 重新創建時報錯(不好用) 三. 只靠方法獲取實例(不好用) 四. 類裝飾器 五. 重寫__new__方法 六. 元類 七. 總結 單例模式&#xff08;Singleton Pattern&#xff09;是一種設計模式&#xff0c;其核心目標是確保一個類…

循環神經網絡(RNN)全面教程:從原理到實踐

循環神經網絡(RNN)全面教程&#xff1a;從原理到實踐 引言 循環神經網絡(Recurrent Neural Network, RNN)是處理序列數據的經典神經網絡架構&#xff0c;在自然語言處理、語音識別、時間序列預測等領域有著廣泛應用。本文將系統介紹RNN的核心概念、常見變體、實現方法以及實際…

使用Vditor將Markdown文檔渲染成網頁(Vite+JS+Vditor)

1. 引言 編寫Markdown文檔現在可以說是程序員的必備技能了&#xff0c;因為Markdown很好地實現了內容與排版分離&#xff0c;可以讓程序員更專注于內容的創作。現在很多技術文檔&#xff0c;博客發布甚至AI文字輸出的內容都是以Markdown格式的形式輸出的。那么&#xff0c;Mar…

Day 40

單通道圖片的規范寫法 import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader , Dataset from torchvision import datasets, transforms import matplotlib.pyplot as plt import warnings warnings.filterwarnings(&q…

SPSS跨域分類:自監督知識+軟模板優化

1. 圖1:SPSS方法流程圖 作用:展示了SPSS方法的整體流程,從數據預處理到模型預測的關鍵步驟。核心內容: 領域知識提取:使用三種詞性標注工具(NLTK、spaCy、TextBlob)從源域和目標域提取名詞或形容詞(如例句中提取“excellent”“good”等形容詞)。詞匯交集與聚類:對提…

2025年通用 Linux 服務器操作系統該如何選擇?

2025年通用 Linux 服務器操作系統該如何選擇&#xff1f; 服務器操作系統的選擇對一個企業IT和云服務影響很大&#xff0c;主推的操作系統在后期更換的成本很高&#xff0c;而且也有很大的遷移風險&#xff0c;所以企業在選擇服務器操作系統時要尤為重視。 之前最流行的服務器…

如何在 Django 中集成 MCP Server

目錄 背景說明第一步&#xff1a;使用 ASGI第二步&#xff1a;修改 asgi.py 中的應用第三步&#xff1a;Django 數據的異步查詢 背景說明 有幾個原因導致 Django 集成 MCP Server 比較麻煩 目前支持的 MCP 服務是 SSE 協議的&#xff0c;需要長連接&#xff0c;但一般來講 Dj…

天拓四方工業互聯網平臺賦能:地鐵電力配電室綜合監控與無人巡檢,實現效益與影響的雙重顯著提升

隨著城市化進程的不斷加快&#xff0c;城市軌道交通作為緩解交通壓力、提升出行效率的重要方式&#xff0c;在全國各大城市中得到了迅猛發展。地鐵電力配電室作為核心供電設施&#xff0c;其基礎設施的安全性、穩定性和智能化水平也面臨更高要求。 本文將圍繞“工業物聯網平臺…

算法打卡第11天

36.有效的括號 &#xff08;力扣20題&#xff09; 示例 1&#xff1a; **輸入&#xff1a;**s “()” **輸出&#xff1a;**true 示例 2&#xff1a; **輸入&#xff1a;**s “()[]{}” **輸出&#xff1a;**true 示例 3&#xff1a; **輸入&#xff1a;**s “(]”…

python 包管理工具uv

uv --version uv python find uv python list export UV_DEFAULT_INDEX"https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple" # 換成私有的repo export UV_HTTP_TIMEOUT120 uv python install 3.12 uv venv myenv --python 3.12 --seed uvhttps://docs.ast…

spring的多語言怎么實現?

1.創建springboot項目&#xff0c;并配置application.properties文件 spring.messages.basenamemessages spring.messages.encodingUTF-8 spring.messages.fallback-to-system-localefalsespring.thymeleaf.cachefalse spring.thymeleaf.prefixclasspath:/templates/ spring.t…

JAVA:Kafka 消息可靠性詳解與實踐樣例

?? 1、簡述 Apache Kafka 是高吞吐、可擴展的流處理平臺,在分布式架構中廣泛應用于日志采集、事件驅動和微服務解耦場景。但在使用過程中,消息是否會丟?何時丟?如何防止丟? 是很多開發者關心的問題。 Kafka 提供了一套完整的機制來保障消息從生產者 ? Broker ? 消費…

【AI非常道】二零二五年五月,AI非常道

經常在社區看到一些非常有啟發或者有收獲的話語&#xff0c;但是&#xff0c;往往看過就成為過眼云煙&#xff0c;有時再想去找又找不到。索性&#xff0c;今年開始&#xff0c;看到好的言語&#xff0c;就記錄下來&#xff0c;一月一發布&#xff0c;亦供大家參考。 前面的記…

C++哈希

一.哈希概念 哈希又叫做散列。本質就是通過哈希函數把關鍵字key和存儲位置建立映射關系&#xff0c;查找時通過這個哈希函數計算出key存儲的位置&#xff0c;進行快速查找。 上述概念可能不那么好懂&#xff0c;下面的例子可以輔助我們理解。 無論是數組還是鏈表&#xff0c;查…