【五子棋实战】第5章 开发五子棋前端页面

news2024/11/17 17:32:30

【五子棋实战】第5章 开发五子棋前端页面

  • 页面设计原则
  • 开发页面
    • ## 基础HTML骨架
    • ## 添加页面响应式功能
  • 编写JS
    • ## 获取画布对象与DOM对象
    • ## 定义棋子、棋盘对象
    • ## 定义绘画对象(重要!!)
    • ## 初始化绘制棋盘
    • ## 添加点击事件 能够下棋落子
  • 继续学习下一篇实战!

页面设计原则

  1、可配置性。比如棋盘的大小可配置,棋盘边长可配置,黑白空期的值可配置;
  2、响应式。各种屏幕大小下棋盘的布局要合理;
  3、面向对象。棋子、棋盘的定义都用类来封装,代码要写的好看。


开发页面

## 基础HTML骨架

  代码如下:

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>三黄工作室 - 五子棋</title>
	<style>
		*
		{
			margin: 0;
		}
		body{
			background-image: url("img/bg.png");
		}
		#canvas_line {
			box-shadow: 0 0 5px 0px rgba(0, 0, 0, .8);
			border-radius: 5px;
			box-sizing: border-box;
			position: fixed;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
			border: 1px solid black;
			background-color: #ffbd5b;
			z-index: 5;
		}
		#canvas_chess {
			position: fixed;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
			z-index: 10;
		}
		.loading-message {
			/* background-color: #f5f5f5; */
			padding: 5px;
			text-align: center;
			font-size: 18px;
			font-weight: bold;
			color:white;
		}
		.logo{
			background-color: #FCFCFD;
			padding: 5px;
			text-align: center;
			bottom: 0px;
			position: fixed;
			width: 100%;
		}
		.button-30 {
              align-items: center;
              appearance: none;
              background-color: #FCFCFD;
              border-radius: 4px;
              border-width: 0;
              box-shadow: rgba(45, 35, 66, 0.4) 0 2px 4px,rgba(45, 35, 66, 0.3) 0 7px 13px -3px,#D6D6E7 0 -3px 0 inset;
              box-sizing: border-box;
              color: #36395A;
              cursor: pointer;
              display: inline-flex;
              font-family: "JetBrains Mono",monospace;
              height: 40px;
              justify-content: center;
              line-height: 1;
              list-style: none;
              overflow: hidden;
              padding-left: 16px;
              padding-right: 16px;
              position: relative;
              text-align: left;
              text-decoration: none;
              transition: box-shadow .15s,transform .15s;
              user-select: none;
              -webkit-user-select: none;
              touch-action: manipulation;
              white-space: nowrap;
              will-change: box-shadow,transform;
              font-size: 18px;
            }
  
            .button-30:focus {
              box-shadow: #D6D6E7 0 0 0 1.5px inset, rgba(45, 35, 66, 0.4) 0 2px 4px, rgba(45, 35, 66, 0.3) 0 7px 13px -3px, #D6D6E7 0 -3px 0 inset;
            }
  
            .button-30:hover {
              box-shadow: rgba(45, 35, 66, 0.4) 0 4px 8px, rgba(45, 35, 66, 0.3) 0 7px 13px -3px, #D6D6E7 0 -3px 0 inset;
              transform: translateY(-2px);
            }
  
            .button-30:active {
              box-shadow: #D6D6E7 0 3px 7px inset;
              transform: translateY(2px);
            }
	</style>
</head>
<body> 
	<canvas id="canvas_line" width="600px" height="600px"></canvas>
  	<canvas id="canvas_chess"></canvas>
	
	<div class="loading-message"><span style="display: none;">正在计算中...</span></div>
	<div class="loading-message"><button onclick="regreat()" class="button-30">悔棋</button></div>

	<div class="logo"><img src="img/logo.png" style="height: 30px;"/></div>
</body>
</html>

  目前的页面样式如下:

在这里插入图片描述

## 添加页面响应式功能

  现在的手机版页面如下,可以发现手机版的棋盘太小、按钮太小、下方的logo太小。

在这里插入图片描述
  于是我们添加响应式功能,在<head>里面添加<meta>头,在<style>里面追加手机页面下的css样式:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
/* 在设备宽度小于600像素时,调整div的大小 */
@media (max-width: 600px) {
	#canvas_line{
		width: 100%;
	}
	#canvas_chess{
		width: 100%;
	}
}

  添加之后,手机版页面就刚好了:

在这里插入图片描述


编写JS

## 获取画布对象与DOM对象

  代码如下:

// 画布
var canvas_chess = document.getElementById("canvas_chess");
var context_chess = canvas_chess.getContext('2d');

var canvas_line = document.getElementById("canvas_line");
var context_line = canvas_line.getContext('2d');

  这段代码主要是获取两个画布元素,并分别创建了两个2D绘图上下文对象。这些上下文对象可以用于在画布上进行绘制和操作,例如绘制图形、文本等。

  获取Dom元素是为了得到元素的长宽、偏移量等;获取画布元素是为了绘制图形;获取2个一个是线条容器、一个是棋子容器。

## 定义棋子、棋盘对象

  代码如下:

// 落子状态 'z'为空 'b'为黑 'w'为白
const white_flag = '1';
const black_flag = '-1';
const blank_flag = '0';
// 棋盘边长
const len = 15;

class Chess {
	constructor(x, y, z) {
		// 横坐标
		this.x = x;
		// 纵坐标
		this.y = y;
		// 落子状态 '0'为空 '-1'为黑 '1'为白
		this.z = z;
	}
}

class Board {
	constructor() {
		// 棋盘边长
		this.len = len;
		// 棋盘棋局状态值 value[len][len]
		this.value = Array.from(Array(this.len), () => new Array(this.len).fill(blank_flag));
		// 棋盘棋局状态值 value[len][len]
		this.chessList = [];
	}
}

  上述代码定义了两个类,ChessBoard

  Chess 类表示一个棋子,具有横坐标 x、纵坐标 y 和落子状态 z 的属性。
  Board 类表示一个棋盘,具有棋盘边长 len、棋局状态值 value 和棋子列表 chessList 的属性。value 是一个二维数组,用于存储棋盘上每个位置的落子状态。chessList 则是用于存储已下的棋子对象。
  此外,代码中还定义了常量 white_flagblack_flagblank_flag,分别表示白棋、黑棋和空白位置的落子状态。

## 定义绘画对象(重要!!)

  代码如下:

class Draw {
	constructor(canvas_line, context_line, canvas_chess, context_chess) {
		// 样式
		this.style = {
			// 棋盘边长
			len : len,
			// 棋盘线条颜色
			lineColor : "#555",
			// 棋盘线条间隔
			lineWidth : 40,
		}
		// 棋盘线条居中时,需要的偏移量
		this.style['offSet'] = (canvas_line.width - this.style.len * this.style.lineWidth) / 2;
		// dom对象
		this.dom = {
			l : canvas_line,
			c : canvas_chess
		}
		// context对象
		this.context ={
			l : context_line,
			c : context_chess
		}
		// 根据线条数、间隔大小 设置棋盘宽、高
		canvas_chess.height = this.style.len * this.style.lineWidth;
		canvas_chess.width = this.style.len * this.style.lineWidth; 
	}

	// 绘制棋盘线条
	drawChessBoard(){
		let style = this.style;

		let color = style.lineColor;
		let w = style.lineWidth;
		let o = style.offSet;
		let len = style.len;
		let h = w / 2;
		let c = this.context.l;

		for(var i=0; i < len; i++){
			c.strokeStyle = color;
			c.moveTo(h + i*w + o, h + o);//垂直方向画线
			c.lineTo(h + i*w + o, h * (2 * len - 1) + o);
			c.stroke();
			c.moveTo(h + o, h + i*w + o);//水平方向画线
			c.lineTo(h * (2 * len - 1) + o , h + i*w + o);
			c.stroke();
		}
	}

	/**
	 * 绘制单个棋子
	 * @param {*} j 横坐标
	 * @param {*} i 纵坐标
	 * @param {*} k 颜色 黑or白
	 * @param {*} first 是否需要绘制小红点
	 */
	drawChess(Chess, first = false){
		let j = Chess.x;
		let i = Chess.y;
		let k = Chess.z;

		let style = this.style;

		let w = style.lineWidth;
		let h = w / 2;
		let c = this.context.c;

		c.beginPath();
		c.arc(h + i*w, h+j*w, h-2, 0, 2 * Math.PI);//绘制棋子
		var g=c.createRadialGradient(h+i*w,h+j*w,13,h+i*w,h+j*w,0);//设置渐变
		if(k == black_flag){
			g.addColorStop(0,'#0A0A0A');//黑棋
			g.addColorStop(1,'#636766');	
		}else if(k == white_flag){
			g.addColorStop(0,'#D1D1D1');//白棋
			g.addColorStop(1,'#F9F9F9');
		}
		c.fillStyle=g;
		c.fill();
		c.closePath();
		if(first){
			c.fillStyle = 'red';
			c.fillRect(h*0.75 + i*w, h*0.75+j*w, h/2, h/2)
		}
	}

	// 绘制现有棋子
	drawChessAll(list) {
		// 清空棋子canvas
		let dom_c = this.dom.c;
		dom_c.height = dom_c.height;
		// 依次绘制棋子
		for(let i in list){
			if(i == list.length - 1)
				this.drawChess(list[i], true);
			else
				this.drawChess(list[i]);
		}
	}
}

  上述代码定义了一个名为 Draw 的类。

  Draw 类具有以下属性和方法:

  - 属性:
   - style:包含样式信息的对象,包括棋盘边长 (len)、棋盘线条颜色 (lineColor) 和棋盘线条间隔 (lineWidth)。
   - dom:包含存储 Canvas DOM 对象的属性 lc
   - context:包含存储 Canvas 上下文对象的属性 lc

  - 构造函数:
   - 接受两个 Canvas DOM 对象和对应的上下文对象作为参数,用于初始化 Draw 对象。
   - 在构造函数中,根据传入的参数设置样式、计算偏移量,并设置棋盘 Canvas 的宽度和高度。

  - 方法:
   - drawChessBoard():绘制棋盘线条的方法。这里有好多数学计算,再结合canvas线条绘制的api。
   - drawChess(Chess, first = false):绘制单个棋子的方法。接受 Chess 对象作为参数,包含棋子的横坐标 x、纵坐标 y 和落子状态 z。可选择是否绘制小红点。
   - drawChessAll(list):绘制现有棋子的方法。接受一个棋子对象列表作为参数,依次绘制列表中的棋子。

## 初始化绘制棋盘

  代码如下:

// 棋盘
let board = new Board();
// 绘画器
let draw = new Draw(canvas_line, context_line, canvas_chess, context_chess);

// 玩家
let currentPlayer = 1;

       
//绘制棋盘
   draw.drawChessBoard();

  目前的页面样式如下:

在这里插入图片描述

## 添加点击事件 能够下棋落子

  代码如下:

function clk (e){
		$("span").css("display","block");
		canvas_chess.onclick= null;

		var x = e.offsetY;//相对于棋盘左上角的x坐标
		var y = e.offsetX;//相对于棋盘左上角的y坐标
		// var i = Math.floor(x / draw.style.lineWidth);
		// var j = Math.floor(y / draw.style.lineWidth);
		var i = Math.floor(x * canvas_chess.width / canvas_chess.offsetWidth / draw.style.lineWidth);
		var j = Math.floor(y * canvas_chess.width / canvas_chess.offsetWidth / draw.style.lineWidth);

		if( board.value[i][j] == blank_flag ) {
			if(currentPlayer == 1){
				var c = new Chess(i,j,black_flag);
				board.value[i][j]=black_flag;
			}else{
				var c = new Chess(i,j,white_flag);
				board.value[i][j]=white_flag;
			}
			board.chessList.push(c);
			draw.drawChessAll(board.chessList);
			if(checkWin(board.chessList, currentPlayer) === true){
				alert((currentPlayer == 1? "black" : "white") + "win !!");
				return;
			}
			// 切换玩家
			currentPlayer = (currentPlayer === 1) ? 2 : 1;
		}else{
			$("span").css("display","none");
			canvas_chess.onclick= clk;
		}
	}

  这样我们就可以自己交替着下黑子和白子了。于是前端页面基本结束。


继续学习下一篇实战!

  【五子棋实战】第6章 调用接口进行联调

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/676349.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Network 之十三 NC-SI 原理、拓扑结构、RBT 接口及仲裁、协议格式

最近&#xff0c;正在学习 NC-SI 的使用方法&#xff0c;于是开始各种 Google 查找 NC-SI 的资料进行学习。最详细还是得直接看 NC-SI 规范文档 DSP0222&#xff0c;以下就是记录的一些感觉 NC-SI 规范中比较重要的点以及我的一些理解&#xff0c;以备后续查阅。 有任何疑问&am…

OpenGL之模板测试

文章目录 模板测试模板函数物体轮廓源代码 模板测试 当片段着色器处理完一个片段之后&#xff0c;模板测试(Stencil Test)会开始执行&#xff0c;和深度测试一样&#xff0c;它也可能会丢弃片段。接下来&#xff0c;被保留的片段会进入深度测试&#xff0c;它可能会丢弃更多的片…

Git下:Git命令使用-详细解读

目录 一、Git 安装 二、Git 配置 三、Git 工作流程 四、Git 工作区、暂存区和版本库 五、常用 Git 命令清单 1. 创建仓库 2. 增加/删除文件 3. 代码提交 4. 分支管理 5. 标签 6. 查看历史提交 7. 远程仓库同步 8. 撤销操作 六、Git 常用命令速查表 七、Git 电子…

时序预测的深度学习算法全面盘点

1.概述 深度学习方法是一种利用神经网络模型进行高级模式识别和自动特征提取的机器学习方法&#xff0c;近年来在时序预测领域取得了很好的成果。常用的深度学习模型包括循环神经网络&#xff08;RNN&#xff09;、长短时记忆网络&#xff08;LSTM&#xff09;、门控循环单元&…

第五十一章 协助调查

眼前一个红彤彤的东西缓缓升起。 旭日东升&#xff1f;可现在才升未免太晚了些&#xff0c;升起的速度也未免太快了些&#xff0c;这红日么&#xff0c;也未免太小了些&#xff0c;而且&#xff0c;刚升起的朝阳&#xff0c;也未免显得太红太亮了些。 “是谁呀&#xff0c;水烧…

C语言数据存储 —— 浮点型篇

C语言数据存储 —— 浮点型篇 前言1. 一个常见问题2. 浮点数存储规则2.1 有效数字M一些特别的规定2.2 有效数字E一些特别的规定2.2.1 E如何存入内存2.2.2 E如何从内存中取出 3. 前面问题的解释。4. 结尾 前言 浮点数在内存中的存储方式对程序员来说非常重要。理解浮点数的存储…

数据结构:二叉树经典例题(单选题)-->你真的掌握二叉树了吗?(第一弹)

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关二叉树的经典例题&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数…

消防通道堵塞识别 opencv

消防通道堵塞识别系统通过opencvpython网络模型技术&#xff0c;消防通道堵塞识别对消防通道的状态进行实时监测&#xff0c;检测到消防通道被堵塞时&#xff0c;将自动发出警报提示相关人员及时采取措施。OpenCV的全称是Open Source Computer Vision Library&#xff0c;是一个…

linux-centOS7.9通过docker安装cwmp server:drumsergio/genieacs

一、安装环境 #查看centOS版本 [rootMiWiFi-R4CM-srv network-scripts]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) #自动查找最新安装包并升级 [rootMiWiFi-R4CM-srv ~]# sudo yum upgrade 二、关闭firewalld、NetworkManager、selinux 关闭防火墙、…

【黑马头条-Java微服务项目】

黑马头条-Java微服务项目 (一)、项目介绍1.项目背景介绍(1).基本介绍(2).业务说明(3).项目术语介绍 2.技术栈说明(1).技术栈-基础六层技术(2).技术栈-服务四层技术(3).技术栈-分布 (二)、nacos环境搭建 (一)、项目介绍 1.项目背景介绍 (1).基本介绍 随着智能手机的普及&…

在线选课的微信小程序(微信前端+网站后端)

目录 一、前言 二、微信小程序端&#xff08;老师、学生&#xff09; 1.学生用户前端小程序界面 2.老师前端小程序界面 三、后端&#xff08;管理员、老师、学生&#xff09; 3.老师后端 4.管理员后端 四、代码获取与调试 一、前言 这是一个在线选课的微信小程序&#…

PID控制算法: 3、Tuning Changes(参数调整)

改变控制参数积分项对输出结果的影响 可靠的控制系统应该有能力实时变更系统的参数 The Beginner’s PID acts a little crazy if you try to change the tunings while it’s running. Let’s see why. Here is the state of the beginner’s PID before and after the param…

STM32F4 点亮灯泡【顺序点亮、按键点亮】

一、顺序点亮灯泡 ①初始化 在user.c文件中&#xff0c;我们需要对LED进行初始化设置。 在函数LED_GPIO_Config中&#xff0c;可以修改代码如下&#xff1a; /*********************************************************************** LED初始化 备注 LED 接在GPC14引脚上…

【Springboot集成Neo4j完整版教程】

&#x1f680; Neo4j &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;C…

基于Python+OpenCV图像识别的连连看辅助工具(深度学习+机器视觉)含全部工程源码及视频演示

目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境Pycharm 环境 模块实现1. 获取句柄2. 图像划分3. 建立矩阵4. 矩阵求解 系统测试工程源代码下载其它资料下载 前言 本项目目标是利用pywin32来获取游戏图像信息&#xff0c;并利用OpenCV进行识别和处理&#xff…

2023学习日志

[牛客网习题练习] 此系列文章仅是对个人学习的记录如有错误望大家指正与谅解。 1.题目描述&#xff1a;输入一个长度为 n 字符串&#xff0c;打印出该字符串中字符的所有排列&#xff0c;你可以以任意顺序返回这个字符串数组。 例如输入字符串ABC,则输出由字符A,B,C所能排列出…

文本分析-使用Python做词频统计分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

【JDK】二、环境变量从jdk17切换为jdk8后不生效的解决办法

环境变量从jdk17切换为jdk8后不生效的解决办法 一、问题描述二、环境变量为java17时的截图三、修改为java8时的截图四、解决办法1、原因分析 2、删除jdk17和jdk8默认的配置或者把默认的下移&#xff0c;统一使用自己的%JAVA_HOME%.3、同样我们把JAVA_HOME改成17 重启后&#xf…

面试题:mybatis中# 和 $ 的区别

面试题&#xff1a;mybatis中# 和 $ 的区别 一、主要区别如下&#xff1a; 1、#{}可以理解为预处理&#xff0c;而${}是直接替换。 #传入的参数在SQL中显示为字符串&#xff0c;会对自动传入的数据加上双引号。 $传入的参数在SQL中直接显示为传入的值 2、#{}试用于所有类型…

不要再封装各种Util工具类了,这个神级框架你值得拥有!

一、功能 二、安装 三、简单测试 今天给大家推荐一个非常好用的Java工具类库&#xff0c;企业级常用工具类&#xff0c;基本都有&#xff0c;能避免重复造轮子及节省大量的开发时间&#xff0c;非常不错&#xff0c;值得大家去了解使用。 Hutool 谐音 “糊涂”&#xff0c;…