• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

五子棋第5章 开发五子棋前端页面

武飞扬头像
征途黯然.
帮助1

页面设计原则

  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章 调用接口进行联调

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgeihcj
系列文章
更多 icon
同类精品
更多 icon
继续加载