The technology used
- es6
- canvas
canvas
The Canvas API provides a way to draw graphics using JavaScript and HTML elements. It can be used for animation, game graphics, data visualization, image editing, and real-time video processing.
I met a canvas
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="Width = device - width, initial - scale = 1.0, the maximum - scale = 1, minimum - scale = 1, the user - scalable = no"
/>
<title>First canvas. HTML</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
canvas {
background-color: aqua;
}
</style>
</head>
<body>
<canvas></canvas>
</body>
</html>
Copy the code
It can be seen that Canvas is an inline element with a default width and height of 300*150.
Draw a straight line lineTo
The following code draws a diagonal line
// 1 gets the DOM element
const canvas = document.querySelector('canvas');
// 2 Get the canvas object
const ctx = canvas.getContext('2d');
// 3 Set the starting point
ctx.moveTo(0.1);
// 4 Set the destination
ctx.lineTo(300.150);
/ / 5 stroke
ctx.stroke();
Copy the code
Resize canvas
Note that if you want to change the width and height of the Canvas tag, you cannot change it directly in CSS, otherwise you will stretch the canvas. You can only change width and height on the attributes of the tag
The wrong sample
canvas {
width: 600px;
height: 300px;
}
Copy the code
The correct sample
<canvas width="600" height="300"></canvas>
Copy the code
Modify the strokeStyle color
When we don’t want the default black line, we can use strokeStyle to change the color
ctx.strokeStyle = 'pink';
ctx.stroke();
Copy the code
Draw arc
// Arc (center x, center y, radius length, start radian, end radian)
ctx.arc(300.150.100.0.Math.PI * 2);
ctx.stroke();
Copy the code
It can also be changed to a filled arc fill
ctx.arc(300.150.100.0.Math.PI * 2);
ctx.fill();
Copy the code
If you want to change the color of the fill, use fillStyle
ctx.fillStyle = 'yellow';
ctx.fill();
Copy the code
show time
In the following code example, the annotated representation is new code
Set up static structures
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="Width = device - width, initial - scale = 1.0, the maximum - scale = 1, minimum - scale = 1, the user - scalable = no"
/>
<title>gobang</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
text-align: center;
height: 100vh;
}
canvas {
/* You can write your own background color instead of the following four lines */
background-image: url(./images/20211227092309212.jpg);
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
</style>
</head>
<body>
<canvas></canvas>
</body>
</html>
Copy the code
Create a new class and declare related methods
In the following code example, the annotated representation is new code
There are four main functions
- Initialize related properties such as checkerboard width and height
- Declares a method for drawing a chess board
- Declares the method of clicking on the board to play chess
- Declare how to judge victory in chess
class Gobang {
/** constructor */
constructor() {}
/** Initialize the canvas */
init() {}
/** draw the board */
drawCheckerBroad() {}
/** Canvas bind click event to implement chess function */
checkerBroadEvent() {}
/** determine whether the victory ** /
victory(){}}Copy the code
Initialize the canvas
In the following code example, the annotated representation is new code
The attributes that need to be initialized are
The requirement is that you want a board with 18 by 18 squares, so you need 19 lines, each of which is 20 by 20
this.canvas
Used to bind click events laterthis.checkerBoradWidth
Used to declare the size of a gridthis.lineNums
Used to declare how many lines to draw on a checkerboardthis.blaorwh
Used to declare whether the current chess player is yellow or whitethis.chessMartrixs
Checkerboard position matrix, used to record the positions of chess pieces and determine victory
init() {
// The width of the grid
this.checkerBoradWidth = 20;
this.lineNums = 19;
// White or yellow is yellow
this.blaorwh = 'yellow';
// Store the positions of the chess pieces in the two-dimensional array 19*19
this.chessMartrixs = [];
for (let i = 0; i <= this.lineNums; i++) {
this.chessMartrixs.push(
new Array(this.lineNums).fill(0.0.this.lineNums)
);
}
this.canvas = document.querySelector('canvas');
// Set the canvas size to exactly the size of 20 squares
this.canvas.width = this.checkerBoradWidth * (this.lineNums - 1);
this.canvas.height = this.checkerBoradWidth * (this.lineNums - 1);
this.ctx = this.canvas.getContext('2d');
}
Copy the code
Describe the board
In the following code example, the annotated representation is new code
The requirement is that you want a board with 18 by 18 squares, so you need 19 lines, each of which is 20 by 20
// Create a new path
this.ctx.beginPath();
// Set the line color
this.ctx.strokeStyle = '#ccc';
// Walk over every line on the drawing board
for (let i = 0; i < this.lineNums; i++) {
// Draw the horizontal line checkerBoradWidth is the width of the checkerboard grid
this.ctx.moveTo(0, i * this.checkerBoradWidth);
this.ctx.lineTo(
// lineNums is the number of lines
this.lineNums * this.checkerBoradWidth,
i * this.checkerBoradWidth
);
// Draw vertical lines
this.ctx.moveTo(i * this.checkerBoradWidth, 0);
this.ctx.lineTo(
i * this.checkerBoradWidth,
this.lineNums * this.checkerBoradWidth
);
}
this.ctx.stroke();
Copy the code
We then call the methods that initialize the canvas and draw the checkerboard in the constructor, and instantiate them
constructor() {
this.init();
this.drawCheckerBroad();
}
Copy the code
instantiation
const gobang = new Gobang();
Copy the code
In effect
Click on the board to play chess
In the following code example, the annotated representation is new code
Bind the click event to the Canvas tag, get the mouse coordinate, and then draw the circle in place
checkerBroadEvent() {
// Be careful to use the arrow function, otherwise it can lead to this pointing problem
this.canvas.addEventListener('click'.(e) = > {
// Get the coordinates of the mouse in the canvas
const x = e.offsetX;
const y = e.offsetY;
// Each click reopens the path
this.ctx.beginPath();
// Draw the chess pieces according to the clicked coordinates
this.ctx.arc(x, y, this.checkerBoradWidth / 2.0.2 * Math.PI);
// Determine white or black
if (this.blaorwh === 'yellow') {
/ / yellow
this.ctx.fillStyle = 'yellow';
} else {
// White stroke is easy to confuse with background
this.ctx.fillStyle = '#fff';
this.ctx.stroke();
}
this.ctx.fill();
this.blaorwh = this.blaorwh === 'yellow' ? 'white' : 'yellow';
});
}
Copy the code
It is also called in the constructor
constructor() {
this.init();
this.drawCheckerBroad();
this.checkerBroadEvent(); // Click the mouse to play chess
}
Copy the code
Two problems arise
-
The chess position is not in the center of the line segment, it may be skewed
-
The same position, can put countless pieces (need to determine whether there are already pieces)
We need to fix it
Fixed standard positions in chess
In the following code example, the annotated representation is new code
Mainly by judging the current chess coordinate position and horizontal or vertical direction on which line segment position close, then set chess position is equal to the distance from the nearest line segment coordinates.
/** Canvas bind click event to implement chess function */
checkerBroadEvent() {
// Be careful to use the arrow function, otherwise it can lead to this pointing problem
this.canvas.addEventListener('click'.(e) = > {
const x = e.offsetX;
const y = e.offsetY;
// To set the center of the arc, add 20px for each grid
let arcX, arcY;
// it is used to record the coordinate points such as (0,1), (1,3), etc
for (let i = 0; i <= this.lineNums; i++) {
// Determine the horizontal direction of the mouse's x coordinate
if (
Math.abs(x - i * this.checkerBoradWidth) <=
this.checkerBoradWidth / 2
) {
arcX = i * this.checkerBoradWidth;
}
// Determine which side line the mouse is perpendicular to
if (
Math.abs(y - i * this.checkerBoradWidth) <=
this.checkerBoradWidth / 2
) {
arcY = i * this.checkerBoradWidth; }}// If another location is selected, return directly
if (arcX === undefined || arcY === undefined) return;
this.ctx.beginPath();
//...
});
}
Copy the code
Check if there are already chess pieces in the current position
In the following code example, the annotated representation is new code
Use a two-dimensional array this.checkerBoradWidth to record the coordinate position of the chess, and determine whether there are pieces in the current position when the chess is played again
checkerBroadEvent() {
this.canvas.addEventListener('click'.(e) = > {
const x = e.offsetX;
const y = e.offsetY;
let arcX, arcY;
Record the position of the current chess piece in the chess matrix
let chessX, chessY;
for (let i = 0; i <= this.lineNums; i++) {
if (
Math.abs(x - i * this.checkerBoradWidth) <=
this.checkerBoradWidth / 2
) {
arcX = i * this.checkerBoradWidth;
// Record the position of the current piece
chessX = i;
}
if (
Math.abs(y - i * this.checkerBoradWidth) <=
this.checkerBoradWidth / 2
) {
arcY = i * this.checkerBoradWidth;
// Record the position of the current piecechessY = i; }}// If another location is selected, return directly
if (arcX === undefined || arcY === undefined) return;
// If someone did, return
if (this.chessMartrixs[chessY][chessX]) return;
// Store a copy of the current chess position in the matrix
this.chessMartrixs[chessY][chessX] = this.blaorwh;
this.ctx.beginPath();
this.ctx.arc(
arcX,
arcY,
this.checkerBoradWidth / 2.0.2 * Math.PI
);
if (this.blaorwh === 'yellow') {
this.ctx.fillStyle = 'yellow';
} else {
this.ctx.fillStyle = '#fff';
this.ctx.stroke();
}
this.ctx.fill();
this.blaorwh = this.blaorwh === 'yellow' ? 'white' : 'yellow';
});
}
Copy the code
Judge the winner. – Point
Our approach to determining whether a player has won is as follows
Victory is represented by 5 pieces of the same color on any of the following four axes (which are connected by two short axes)
Looking at the diagram above, a rule emerges: We need to set up a key array to determine whether the pieces are connected
[[-1, -1], [...1.0], [1, -1], [0.1]]
Copy the code
-
Let’s say we iterate over the array above let’s say we get the first element [-1,-1]
-
At the same time, when we take the inverse of [-1,-1], we also get [1,1], and then we can determine a long axis
-
At this point, we take [-1,-1] separately open traversal, calculate the number of pieces in this direction
-
At the same time, we take [1,1] also began to traverse, calculate the number of pieces in this direction
-
If they add up to 5 or more, victory is declared
code
/** * Determine whether a contestant has won */
victory(matrix, x, y, borw) {
// Determine the four axes of victory conditions
let victoryUnits = [
[-1, -1], [...1.0],
[1, -1],
[0.1]];const getLineNums = (matrix, direcsx, x, y, borw) = > {
// Count the number of chessmen of the same color
let results = 0;
for (let i = 0; i < 5; i++) {
const vicx = x + i * direcsx[0];
const vicy = y + i * direcsx[1];
// Check that the position is not exceeded
if( matrix[vicy] ! = =undefined&& matrix[vicy][vicx] ! = =undefined &&
borw === matrix[vicy][vicx]
) {
// Check whether it is equal to the current color
results++;
} else {
break; }}return results;
};
// Determine victory
const result = victoryUnits.some((item) = > {
// Count the number of pieces of the same color on one side of the short axis
const n1 = getLineNums(matrix, item, x, y, borw);
// Count the number of pieces of the same color on the other short axis
const n2 = getLineNums(
matrix,
item.map((v) = > -v),
x,
y,
borw
);
// Because I am one of them
return n1 + n2 - 1> =5;
});
return result;
}
Copy the code
The complete code
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="Width = device - width, initial - scale = 1.0, the maximum - scale = 1, minimum - scale = 1, the user - scalable = no"
/>
<title>H5 - gobang</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
text-align: center;
height: 100vh;
}
canvas {
background-image: url(./images/20211227092309212.jpg);
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
</style>
</head>
<body>
<canvas></canvas>
<script>
class Gobang {
constructor() {
this.init();
this.drawCheckerBroad();
this.checkerBroadEvent();
}
init() {
this.checkerBoradWidth = 20;
this.lineNums = 19;
this.blaorwh = 'yellow';
this.chessMartrixs = [];
for (let i = 0; i <= this.lineNums; i++) {
this.chessMartrixs.push(
new Array(this.lineNums).fill(0.0.this.lineNums)
);
}
this.canvas = document.querySelector('canvas');
this.canvas.width = this.checkerBoradWidth * (this.lineNums - 1);
this.canvas.height = this.checkerBoradWidth * (this.lineNums - 1);
this.ctx = this.canvas.getContext('2d');
}
drawCheckerBroad() {
this.ctx.beginPath();
this.ctx.strokeStyle = '#ccc';
for (let i = 0; i < this.lineNums; i++) {
this.ctx.moveTo(i * this.checkerBoradWidth, 0);
this.ctx.lineTo(
i * this.checkerBoradWidth,
this.lineNums * this.checkerBoradWidth
);
this.ctx.moveTo(0, i * this.checkerBoradWidth);
this.ctx.lineTo(
this.lineNums * this.checkerBoradWidth,
i * this.checkerBoradWidth
);
}
this.ctx.stroke();
}
checkerBroadEvent() {
this.canvas.addEventListener('click'.(e) = > {
const x = e.offsetX;
const y = e.offsetY;
let arcX, arcY;
let chessX, chessY;
for (let i = 0; i <= this.lineNums; i++) {
if (
Math.abs(x - i * this.checkerBoradWidth) <=
this.checkerBoradWidth / 2
) {
arcX = i * this.checkerBoradWidth;
chessX = i;
}
if (
Math.abs(y - i * this.checkerBoradWidth) <=
this.checkerBoradWidth / 2
) {
arcY = i * this.checkerBoradWidth; chessY = i; }}if (arcX === undefined || arcY === undefined) return;
if (this.chessMartrixs[chessY][chessX]) return;
this.chessMartrixs[chessY][chessX] = this.blaorwh;
this.ctx.beginPath();
this.ctx.arc(
arcX,
arcY,
this.checkerBoradWidth / 2.0.2 * Math.PI
);
if (this.blaorwh === 'yellow') {
this.ctx.fillStyle = 'yellow';
} else {
this.ctx.fillStyle = '#fff';
this.ctx.stroke();
}
this.ctx.fill();
if (
this.victory(this.chessMartrixs, chessX, chessY, this.blaorwh)
) {
console.log(this.blaorwh + 'victory');
return;
}
this.blaorwh = this.blaorwh === 'yellow' ? 'white' : 'yellow';
});
}
victory(matrix, x, y, borw) {
let victoryUnits = [
[-1, -1], [...1.0],
[1, -1],
[0.1]];const getLineNums = (matrix, direcsx, x, y, borw) = > {
let results = 0;
for (let i = 0; i < 5; i++) {
const vicx = x + i * direcsx[0];
const vicy = y + i * direcsx[1];
if( matrix[vicy] ! = =undefined&& matrix[vicy][vicx] ! = =undefined &&
borw === matrix[vicy][vicx]
) {
results++;
} else {
break; }}return results;
};
const result = victoryUnits.some((item) = > {
const n1 = getLineNums(matrix, item, x, y, borw);
const n2 = getLineNums(
matrix,
item.map((v) = > -v),
x,
y,
borw
);
return n1 + n2 - 1> =5;
});
returnresult; }}const gobang = new Gobang();
</script>
</body>
</html>
Copy the code