[网页五子棋][对战模块]前后端交互接口(建立连接、连接响应、落子请求/响应),客户端开发(实现棋盘/棋子绘制)

article/2025/7/14 17:18:53

文章目录

  • 约定前后端交互接口
    • 建立连接
    • 建立连接响应
    • 针对"落子"的请求和响应
  • 客户端开发
    • 实现棋盘/棋子绘制
    • 部分逻辑解释

约定前后端交互接口

对战模块和匹配模块使用的是两套逻辑,使用不同的 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.hkcw.cn/article/aLMnOpcltK.shtml

相关文章

Redisson学习专栏(三):高级特性与实战(Spring/Spring Boot 集成,响应式编程,分布式服务,性能优化)

文章目录 前言一、Spring Boot深度整合实战1.1 分布式缓存管理1.2 声明式缓存1.3 响应式编程 二、分布式服务治理2.1 服务端实现2.2 客户端调用2.3 高级特性2.4 服务治理功能 三、分布式任务调度引擎四、连接池配置与网络参数调优4.1 连接池配置4.2 网络参数调优4.3 集群模式特…

行程规划:智能规划,轻松旅行

在旅行中&#xff0c;一个好的行程规划是成功旅行的关键。它不仅能帮助你合理安排时间&#xff0c;还能让你的旅行更加经济、高效。成都为普云科技有限公司推出的“行程规划”APP&#xff0c;就是这样一个贴心的旅行助手。它不仅能让你自由记录旅游路线&#xff0c;还能实时记账…

动态报表筛选多项时的优化处理

如图所示 在有比较麻烦且数量比较的动态筛选条件时&#xff0c;就可以单独用一个页面&#xff0c;来囊括所有的参数选项&#xff0c;依次把从接口那得到的筛选列表按id来成数组&#xff0c;依次判断返回赋即可&#xff0c;非常方便

PSpice软件快速入门系列--07.如何进行Worst Case最坏情况分析

背景介绍&#xff1a;由于电路特性受电路中不同元器件的影响程度不同&#xff0c;当电路中不同元器件分别变化时&#xff0c;即使元器件值的变化相同&#xff0c;但电路特性变化的绝对值不会相同&#xff0c;而且其变化的方向也可能不同。PSpice提供了最坏情况分析&#xff0c;…

从收货到上架,海外仓系统如何智能优化入库管理?

在全球电商交易蓬勃发展的当下&#xff0c;跨境电商市场规模持续扩大&#xff0c;海外仓的重要性愈发凸显。其中高效、精准的入库管理&#xff0c;不仅是提升海外仓运营效率的关键&#xff0c;更是赢得客户信任、增强市场竞争力的核心要素。然而&#xff0c;传统的入库模式往往…

特朗普称美国汽车制造商“必须在国内生产整车”

当地时间5月30日,美国总统特朗普表示,包括特斯拉在内的美国汽车制造商必须在美国生产整车和所有零部件,而不是在国外生产。特朗普表示,之前汽车制造商在加拿大、墨西哥、欧洲生产零部件,这让他很困扰,但在接下来的一年里,这些汽车制造商“必须在美国生产整车”。(总台记…

特朗普称6月4日起把进口钢铁关税提高至50%

当地时间5月30日,美国总统特朗普在宾夕法尼亚州举行的一场集会上表示,将把进口钢铁的关税从25%提高至50%。随后,特朗普在社交媒体平台上发文表示,该决定从自6月4日起生效。美国白宫当天在社交媒体上发布公告称,“为进一步保护美国钢铁行业免受外国和不公平竞争的影响,从下…

官方通报:跳至兵马俑三号坑男子已被控制

造成两尊铠甲武士俑损坏 官方通报跳至兵马俑三号坑男子已被控制陕西省西安市公安局临潼分局今日发布警情通报,跳至兵马俑三号坑男子已被公安机关控制。2025年5月30日17时30分许,孙某(男,30岁)进入兵马俑景区参观时,翻越遗址坑护栏及防护网跳至三号坑内推拉陶俑,造成两尊…

【速通RAG实战:进阶】21、取长补短:LangChain与LlamaIndex等RAG框架的企业级融合实践

一、RAG框架的现状与核心挑战 (一)主流框架的优势与局限 LangChain、LlamaIndex等RAG框架已成为构建智能问答系统的基础设施,但在企业级落地中暴露出以下矛盾: 灵活性与专业性的冲突:LangChain的模块化设计支持复杂工作流,但对垂直领域(如医疗、金融)的深度优化不足;…

宝塔部署 Vue + NestJS 全栈项目

这里写自定义目录标题 前言一、Node.js版本管理器1、安装2、配置 二、NestJS项目管理&#xff08;等同Node项目&#xff09;1、Git安装2、拉取项目代码3、无法自动认证4、添加Node项目5、配置防火墙&#xff08;两道&#xff09; 三、Vue项目管理1、项目上传2、Nginx安装3、配置…

MES系统:助力企业数字化转型

MES管理系统是一个高效、灵活的生产管理系统&#xff0c;能够帮助企业提高生产效率和产品质量&#xff0c;从而获得更大的商业价值。如果你是一家制造企业&#xff0c;那么MES管理系统是你不能错过的重要工具。 一、MES系统核心功能大揭秘&#xff1a; 1、计划管理&#xff1a…

当客服遇见大模型:知识管理智能化转型

数字化转型浪潮下&#xff0c;客服中心作为企业服务前沿阵地&#xff0c;正经历一场深刻变革。面对日益多元、个性化的客户需求&#xff0c;传统依赖人工维护的知识管理体系已难以为继。AI大模型的崛起&#xff0c;为客服中心开辟了新赛道——这不仅是技术迭代&#xff0c;更是…

[NOIP 2001 普及组] 求先序排列 Java

import java.util.*;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);String infixOrder sc.nextLine(); // 中序String postOrder sc.nextLine(); // 后序sc.close();System.out.println(preOrder(infixOrder, postOrder))…

可蓝牙通信、光电隔离型RS-485集线器——DAM-3222

产品概述 DAM-3222是一款防各类浪涌设计光电隔离型RS-485集线器&#xff0c;集成2路RS485路主机和1路RS485从机接口。支持有线串口连接电脑上位机配置&#xff0c;还支持蓝牙通信&#xff0c;手机蓝牙可通过微信小程序进行参数配置&#xff0c;在安装现场也可以轻松通过手机修…

数据结构 --链表

前言 今天把链表重新用c写了一遍&#xff0c;首先单纯的写一个链表并不困难&#xff0c;无非是定义一个结构体ListNode&#xff0c;设置变量data和下一个指针的地址next&#xff0c;然后完成增删查改的操作&#xff0c;需要注意的是在删除节点的时候记得先保存当前需要删除的节…

【原理扫描】不安全的crossdomain.xml文件和CORS(跨站资源共享)原始验证失败验证与彻底方案

不安全的crossdomain.xml文件【原理扫描】 CORS(跨站资源共享)原始验证失败【原理扫描】 吐槽一下 该漏扫是通过内网漏扫部署服务进行扫描内网minio端口探测到该minio配置不当造成的威胁。 通过nginx配置无效&#xff0c;且必须从MINIO本身解决&#xff1b;MINIO配置存在兼容…

【Web应用】若依框架:基础篇11功能详解-系统接口

文章目录 ⭐前言⭐一、课程讲解⭐二、自己动手实操⭐总结 标题详情作者JosieBook头衔CSDN博客专家资格、阿里云社区专家博主、软件设计工程师博客内容开源、框架、软件工程、全栈&#xff08;,NET/Java/Python/C&#xff09;、数据库、操作系统、大数据、人工智能、工控、网络、…

每日一题:H指数

继续给大家带来每日一题 题目描述 给你一个整数数组 citations &#xff0c;其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。 根据维基百科上 h 指数的定义&#xff1a;h 代表“高引用次数” &#xff0c;一名科研人员的 h 指数 是指…

MPU9250_WE库详解

MPU9250_WE库 https://docs.arduino.cc/libraries/mpu9250_we/ https://github.com/wollewald/MPU9250_WE 三款MPU6050、MPU6500、MPU9250陀螺仪 其初始化以及函数应用方法基本一致,创建初始化对象名称有所差异 初始化相关函数 用于初始化传感器。该函数会尝试与传感器建…

onlyoffice docspace 协作空间企业版使用秘籍-1.如何连接外部存储

背景介绍 ONLYOFFICE 协作空间是一个可在自定义房间中协作处理文本文档、电子表格、演示文稿、表格和 PDF 文件的平台。用户可设置灵活的访问权限&#xff0c;与同事、客户及合作伙伴共享房间和文档。最棒的一个功能是支持文档的中文全文检索功能,方便根据内容找到需要的文档。…