“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”
preface
Hello everyone, MY name is Lin Sanxin. I believe you have read my previous entry to Canvas article. In order to let her enter canvas for 10 minutes, I stayed up late and wrote three small projects and this article. Today, I have written three interesting little games on Canvas to make you happy. Yes, I only have you in my heart, not her.
Now is midnight, let’s open to 🐍 🐍 🐍 🐍 🐍 🐍 🐍 🐍 🐍 🐍, write this article while debugging!!!!!!
Snake 🐍
The final result is as follows:The implementation steps are as follows:
- 1. Draw the snake
- 2. Get the snake moving
- 3, random food
- 4. Snakes eat food
- 5, edge detection and collision detection
1. Draw the snake
In fact, it is very simple to draw a snake. A snake consists of a head and a body, which can be represented by a square. The head of a snake is a square, while the body of a snake can be many squares
You can draw a gridctx.fillRect
To draw, use the head of the snakehead
While the snake body is usedAn array of body
To represent the
// html
<canvas id="canvas" width="800" height="800"></canvas>
// js
draw()
function draw() {
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// The small square constructor
function Rect(x, y, width, height, color) {
this.x = x
this.y = y
this.width = width
this.height = height
this.color = color
}
Rect.prototype.draw = function () {
ctx.beginPath()
ctx.fillStyle = this.color
ctx.fillRect(this.x, this.y, this.width, this.height)
ctx.strokeRect(this.x, this.y, this.width, this.height)
}
// The snake constructor
function Snake(length = 0) {
this.length = length
/ / the snake
this.head = new Rect(canvas.width / 2, canvas.height / 2.40.40.'red')
/ / snake
this.body = []
let x = this.head.x - 40
let y = this.head.y
for (let i = 0; i < this.length; i++) {
const rect = new Rect(x, y, 40.40.'yellow')
this.body.push(rect)
x -= 40
}
}
Snake.prototype.drawSnake = function () {
// Draw the head of the snake
this.head.draw()
// Draw the body of the snake
for (let i = 0; i < this.body.length; i++) {
this.body[i].draw()
}
}
const snake = new Snake(3)
snake.drawSnake()
}
Copy the code
2. Get the snake moving
There are two ways a snake can move:
- 1. Snakes start by default by moving to the right
- 2, through the direction key control, to move in different directions
In both cases, you move one square per second
To get the snake to move, the principle is very simple. Let me use the snake moving to the right as an example:
- 1. The head of the snake moves one square distance to the right first, and the body of the snake does not move
- 2, the snake
The first
Add a square - 3, snake
The tail
Square off - 4, use the timer, resulting in the snake moving to the right of the vision
Snake.prototype.moveSnake = function () {
// Put the head of the snake on the head of the snake
const rect = new Rect(this.head.x, this.head.y, this.head.width, this.head.height, 'yellow')
this.body.unshift(rect)
this.body.pop()
// Control the coordinates of the snake head according to the direction
switch (this.direction) {
case 0:
this.head.x -= this.head.width
break
case 1:
this.head.y -= this.head.height
break
case 2:
this.head.x += this.head.width
break
case 3:
this.head.y += this.head.height
break}}document.onkeydown = function (e) {
// Keyboard events
e = e || window.event
// Left 37 upper 38 right 39 lower 40
switch (e.keyCode) {
case 37:
console.log(37)
// The three-way expression prevents pressing left when moving right.
snake.direction = snake.direction === 2 ? 2 : 0
snake.moveSnake()
break
case 38:
console.log(38)
snake.direction = snake.direction === 3 ? 3 : 1
break
case 39:
console.log(39)
snake.direction = snake.direction === 0 ? 0 : 2
break
case 40:
console.log(40)
snake.direction = snake.direction === 1 ? 1 : 3
break}}const snake = new Snake(3)
// The default direction is 2, which is right
snake.direction = 2
snake.drawSnake()
function animate() {
/ / empty first
ctx.clearRect(0.0, canvas.width, canvas.height)
/ / move
snake.moveSnake()
/ / draw
snake.drawSnake()
}
var timer = setInterval(() = > {
animate()
}, 100)}Copy the code
The results are as follows:
3. Randomly drop food
To randomly place food, that is, to draw a random square on the canvas, pay attention to the following two points:
- 1. Coordinates should be on the canvas
Within the scope of
- 2, food
Not on the body or the head of a snake
(This will knock the snake out)
function randomFood(snake) {
let isInSnake = true
let rect
while (isInSnake) {
const x = Math.round(Math.random() * (canvas.width - 40) / 40) * 40
const y = Math.round(Math.random() * (canvas.height - 40) / 40) * 40
console.log(x, y)
// Make sure it's a multiple of 40
rect = new Rect(x, y, 40.40.'blue')
// Determine if the food overlaps with the snakehead
if ((snake.head.x === x && snake.head.y === y) || snake.body.find(item= > item.x === x && item.y === y)) {
isInSnake = true
continue
} else {
isInSnake = false}}return rect
}
const snake = new Snake(3)
// The default direction is 2, which is right
snake.direction = 2
snake.drawSnake()
// Create a random food instance
var food = randomFood(snake)
// Draw the food
food.draw()
function animate() {
/ / empty first
ctx.clearRect(0.0, canvas.width, canvas.height)
/ / move
snake.moveSnake()
/ / draw
snake.drawSnake()
food.draw()
}
Copy the code
The effect is as follows: Random food is drawn:
4. Snakes eat food
In fact, the snake eats food, which is very simple to understand, that is, when the snake’s head moves to the coordinate overlap with the food, it is considered to have eaten the food. Note two points:
- 1, after eating the food, the snake body to
Extend by one space
- 2, after eating food, random food to
Commutation position
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// A variable that defines whether food is eaten globally
let isEatFood = false
Snake.prototype.moveSnake = function () {
// Put the head of the snake on the head of the snake
const rect = new Rect(this.head.x, this.head.y, this.head.width, this.head.height, 'yellow')
this.body.unshift(rect)
// Determine whether the snake head overlaps with the food. If it overlaps, it is eaten; if it does not overlap, it is not eaten
isEatFood = food && this.head.x === food.x && this.head.y === food.y
// Let's insert a square at the head of the snake
if(! isEatFood) {// The tail is removed before it is eaten, which is equivalent to the whole snake not getting longer
this.body.pop()
} else {
// After eating, the snake does not remove its tail, which is equivalent to lengthening the whole snake by one square
// And when you eat it, you have to regenerate a random food
food = randomFood(this)
food.draw()
isEatFood = false
}
// Control the coordinates of the snake head according to the direction
switch (this.direction) {
case 0:
this.head.x -= this.head.width
break
case 1:
this.head.y -= this.head.height
break
case 2:
this.head.x += this.head.width
break
case 3:
this.head.y += this.head.height
break}}Copy the code
5. Touch boundaries and touch yourself
We all know that when the head of the snake hits the edge, or the body of the snake, the game ends
Snake.prototype.drawSnake = function () {
// If you do
if (isHit(this)) {
// Clear the timer
clearInterval(timer)
const con = confirm('All toldThe ${this.body.length - this.length}Food, start over)
// Whether to reopen
if (con) {
draw()
}
return
}
// Draw the head of the snake
this.head.draw()
// Draw the body of the snake
for (let i = 0; i < this.body.length; i++) {
this.body[i].draw()
}
}
function isHit(snake) {
const head = snake.head
// Whether the left and right borders are touched
const xLimit = head.x < 0 || head.x >= canvas.width
// Whether the upper and lower boundaries are touched
const yLimit = head.y < 0 || head.y >= canvas.height
// Whether to hit the snake body
const hitSelf = snake.body.find(({ x, y }) = > head.x === x && head.y === y)
If one of the three is true, the game is over
return xLimit || yLimit || hitSelf
}
Copy the code
Since then, snake 🐍 small game complete:
6. All codes:
draw()
function draw() {
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// A variable that defines whether food is eaten globally
let isEatFood = false
// The small square constructor
function Rect(x, y, width, height, color) {
this.x = x
this.y = y
this.width = width
this.height = height
this.color = color
}
Rect.prototype.draw = function () {
ctx.beginPath()
ctx.fillStyle = this.color
ctx.fillRect(this.x, this.y, this.width, this.height)
ctx.strokeRect(this.x, this.y, this.width, this.height)
}
// The snake constructor
function Snake(length = 0) {
this.length = length
/ / the snake
this.head = new Rect(canvas.width / 2, canvas.height / 2.40.40.'red')
/ / snake
this.body = []
let x = this.head.x - 40
let y = this.head.y
for (let i = 0; i < this.length; i++) {
const rect = new Rect(x, y, 40.40.'yellow')
this.body.push(rect)
x -= 40
}
}
Snake.prototype.drawSnake = function () {
// If you do
if (isHit(this)) {
// Clear the timer
clearInterval(timer)
const con = confirm('All toldThe ${this.body.length - this.length}Food, start over)
// Whether to reopen
if (con) {
draw()
}
return
}
// Draw the head of the snake
this.head.draw()
// Draw the body of the snake
for (let i = 0; i < this.body.length; i++) {
this.body[i].draw()
}
}
Snake.prototype.moveSnake = function () {
// Put the head of the snake on the head of the snake
const rect = new Rect(this.head.x, this.head.y, this.head.width, this.head.height, 'yellow')
this.body.unshift(rect)
// Determine whether the snake head overlaps with the food. If it overlaps, it is eaten; if it does not overlap, it is not eaten
isEatFood = food && this.head.x === food.x && this.head.y === food.y
// Let's insert a square at the head of the snake
if(! isEatFood) {// The tail is removed before it is eaten, which is equivalent to the whole snake not getting longer
this.body.pop()
} else {
// After eating, the snake does not remove its tail, which is equivalent to lengthening the whole snake by one square
// And when you eat it, you have to regenerate a random food
food = randomFood(this)
food.draw()
isEatFood = false
}
// Control the coordinates of the snake head according to the direction
switch (this.direction) {
case 0:
this.head.x -= this.head.width
break
case 1:
this.head.y -= this.head.height
break
case 2:
this.head.x += this.head.width
break
case 3:
this.head.y += this.head.height
break}}document.onkeydown = function (e) {
// Keyboard events
e = e || window.event
// Left 37 upper 38 right 39 lower 40
switch (e.keyCode) {
case 37:
console.log(37)
// The three-way expression prevents pressing left when moving right.
snake.direction = snake.direction === 2 ? 2 : 0
snake.moveSnake()
break
case 38:
console.log(38)
snake.direction = snake.direction === 3 ? 3 : 1
break
case 39:
console.log(39)
snake.direction = snake.direction === 0 ? 0 : 2
break
case 40:
console.log(40)
snake.direction = snake.direction === 1 ? 1 : 3
break}}function randomFood(snake) {
let isInSnake = true
let rect
while (isInSnake) {
const x = Math.round(Math.random() * (canvas.width - 40) / 40) * 40
const y = Math.round(Math.random() * (canvas.height - 40) / 40) * 40
console.log(x, y)
// Make sure it's a multiple of 40
rect = new Rect(x, y, 40.40.'blue')
// Determine if the food overlaps with the snakehead
if ((snake.head.x === x && snake.head.y === y) || snake.body.find(item= > item.x === x && item.y === y)) {
isInSnake = true
continue
} else {
isInSnake = false}}return rect
}
function isHit(snake) {
const head = snake.head
// Whether the left and right borders are touched
const xLimit = head.x < 0 || head.x >= canvas.width
// Whether the upper and lower boundaries are touched
const yLimit = head.y < 0 || head.y >= canvas.height
// Whether to hit the snake body
const hitSelf = snake.body.find(({ x, y }) = > head.x === x && head.y === y)
If one of the three is true, the game is over
return xLimit || yLimit || hitSelf
}
const snake = new Snake(3)
// The default direction is 2, which is right
snake.direction = 2
snake.drawSnake()
// Create a random food instance
var food = randomFood(snake)
// Draw the food
food.draw()
function animate() {
/ / empty first
ctx.clearRect(0.0, canvas.width, canvas.height)
/ / move
snake.moveSnake()
/ / draw
snake.drawSnake()
food.draw()
}
var timer = setInterval(() = > {
animate()
}, 100)}Copy the code
The stars of attachment
The effect is as follows, isn’t it cool, guys (you can download the background image yourself) :
This small game can be divided into the following steps:
- 1. Draw a single little star and make it
mobile
- 2, build
One hundred
Little stars - 3. When the stars are close to each other, proceed
attachment
- 4, the mouse
The mobile generation
Little stars - 5. Mouse click
Five little stars
1. Draw a single little star and move it
In fact, moving the stars is very simple, is to clear after redrawing the stars, and use the timer, there will be a moving vision. Note this: bounce when you hit the boundary.
// html
<style>
#canvas {
background: URL (./ light emissary.jpg)0 0/cover no-repeat;
}
</style>
<canvas id="canvas"></canvas>
// js
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// Get the width and height of the current view
let aw = document.documentElement.clientWidth || document.body.clientWidth
let ah = document.documentElement.clientHeight || document.body.clientHeight
// Assign to canvas
canvas.width = aw
canvas.height = ah
// Monitor the real-time width and height as the screen changes
window.onresize = function () {
aw = document.documentElement.clientWidth || document.body.clientWidth
ah = document.documentElement.clientHeight || document.body.clientHeight
// Assign to canvas
canvas.width = aw
canvas.height = ah
}
// The color of the game is white, both solid and line
ctx.fillStyle = 'white'
ctx.strokeStyle = 'white'
function Star(x, y, r) {
// x, y are coordinates, r is radius
this.x = x
this.y = y
this.r = r
// The speed parameter ranges from -3 to 3
this.speedX = (Math.random() * 3) * Math.pow(-1.Math.round(Math.random()))
this.speedY = (Math.random() * 3) * Math.pow(-1.Math.round(Math.random()))
}
Star.prototype.draw = function () {
ctx.beginPath()
ctx.arc(this.x, this.y, this.r, 0.Math.PI * 2)
ctx.fill()
ctx.closePath()
}
Star.prototype.move = function () {
this.x -= this.speedX
this.y -= this.speedY
// When it hits the boundary, it bounces. Just reverse speed
if (this.x < 0 || this.x > aw) this.speedX *= -1
if (this.y < 0 || this.y > ah) this.speedY *= -1
}
// Draw a random star in the canvas
const star = new Star(Math.random() * aw, Math.random() * ah, 3)
star
// The movement of stars
setInterval(() = > {
ctx.clearRect(0.0, aw, ah)
star.move()
star.draw()
}, 50)
Copy the code
Achieve the following movement and rebound effects:
2. Draw 100 little stars
Create an array stars to store the stars
const stars = []
for (let i = 0; i < 100; i++) {
// Draw a random star in the canvas
stars.push(new Star(Math.random() * aw, Math.random() * ah, 3))}// The movement of stars
setInterval(() = > {
ctx.clearRect(0.0, aw, ah)
// Iterate over the moving render
stars.forEach(star= > {
star.move()
star.draw()
})
}, 50)
Copy the code
The effect is as follows:
3. When the stars are close, line up
When the difference between x and y of two stars is less than 50, a line is drawn. Just use ctx.moveTo and ctx.lineTo
function drawLine(startX, startY, endX, endY) {
ctx.beginPath()
ctx.moveTo(startX, startY)
ctx.lineTo(endX, endY)
ctx.stroke()
ctx.closePath()
}
// The movement of stars
setInterval(() = > {
ctx.clearRect(0.0, aw, ah)
// Iterate over the moving render
stars.forEach(star= > {
star.move()
star.draw()
})
stars.forEach((star, index) = > {
// Similar to bubble sort, make sure all the stars are compared to each other
for (let i = index + 1; i < stars.length; i++) {
if (Math.abs(star.x - stars[i].x) < 50 && Math.abs(star.y - stars[i].y) < 50) {
drawLine(star.x, star.y, stars[i].x, stars[i].y)
}
}
})
}, 50)
Copy the code
You can think about why two forEach’s can’t be executed together. That’s a good question to think about, or you can combine them together, try it out, and get it. Be to leave a homework for everybody ha!
The effect is as follows:
4. The mouse moves with the little star
That is, the mouse to where, the little star to where, and the little star to go where will be close to the little star line
const mouseStar = new Star(0.0.3)
canvas.onmousemove = function (e) {
mouseStar.x = e.clientX
mouseStar.y = e.clientY
}
// The movement of stars
setInterval(() = > {
ctx.clearRect(0.0, aw, ah)
// Mouse star rendering
mouseStar.draw()
// Iterate over the moving render
stars.forEach(star= > {
star.move()
star.draw()
})
stars.forEach((star, index) = > {
// Similar to bubble sort, make sure all the stars are compared to each other
for (let i = index + 1; i < stars.length; i++) {
if (Math.abs(star.x - stars[i].x) < 50 && Math.abs(star.y - stars[i].y) < 50) {
drawLine(star.x, star.y, stars[i].x, stars[i].y)
}
}
// Determine the line between the mouse stars
if (Math.abs(mouseStar.x - star.x) < 50 && Math.abs(mouseStar.y - star.y) < 50) {
drawLine(mouseStar.x, mouseStar.y, star.x, star.y)
}
})
}, 50)
Copy the code
The effect is as follows:
5 mouse click to generate five little stars
The idea is, click the mouse, generate 5 small stars, and add to the array stars
window.onclick = function (e) {
for (let i = 0; i < 5; i++) {
stars.push(new Star(e.clientX, e.clientY, 3))}}Copy the code
The effect is as follows:
Final result:
6. Full code
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// Get the width and height of the current view
let aw = document.documentElement.clientWidth || document.body.clientWidth
let ah = document.documentElement.clientHeight || document.body.clientHeight
// Assign to canvas
canvas.width = aw
canvas.height = ah
// Monitor the real-time width and height as the screen changes
window.onresize = function () {
aw = document.documentElement.clientWidth || document.body.clientWidth
ah = document.documentElement.clientHeight || document.body.clientHeight
// Assign to canvas
canvas.width = aw
canvas.height = ah
}
// The color of the game is white, both solid and line
ctx.fillStyle = 'white'
ctx.strokeStyle = 'white'
function Star(x, y, r) {
// x, y are coordinates, r is radius
this.x = x
this.y = y
this.r = r
// The speed parameter ranges from -3 to 3
this.speedX = (Math.random() * 3) * Math.pow(-1.Math.round(Math.random()))
this.speedY = (Math.random() * 3) * Math.pow(-1.Math.round(Math.random()))
}
Star.prototype.draw = function () {
ctx.beginPath()
ctx.arc(this.x, this.y, this.r, 0.Math.PI * 2)
ctx.fill()
ctx.closePath()
}
Star.prototype.move = function () {
this.x -= this.speedX
this.y -= this.speedY
// When it hits the boundary, it bounces. Just reverse speed
if (this.x < 0 || this.x > aw) this.speedX *= -1
if (this.y < 0 || this.y > ah) this.speedY *= -1
}
function drawLine(startX, startY, endX, endY) {
ctx.beginPath()
ctx.moveTo(startX, startY)
ctx.lineTo(endX, endY)
ctx.stroke()
ctx.closePath()
}
const stars = []
for (let i = 0; i < 100; i++) {
// Draw a random star in the canvas
stars.push(new Star(Math.random() * aw, Math.random() * ah, 3))}const mouseStar = new Star(0.0.3)
canvas.onmousemove = function (e) {
mouseStar.x = e.clientX
mouseStar.y = e.clientY
}
window.onclick = function (e) {
for (let i = 0; i < 5; i++) {
stars.push(new Star(e.clientX, e.clientY, 3))}}// The movement of stars
setInterval(() = > {
ctx.clearRect(0.0, aw, ah)
// Mouse star rendering
mouseStar.draw()
// Iterate over the moving render
stars.forEach(star= > {
star.move()
star.draw()
})
stars.forEach((star, index) = > {
// Similar to bubble sort, make sure all the stars are compared to each other
for (let i = index + 1; i < stars.length; i++) {
if (Math.abs(star.x - stars[i].x) < 50 && Math.abs(star.y - stars[i].y) < 50) {
drawLine(star.x, star.y, stars[i].x, stars[i].y)
}
}
if (Math.abs(mouseStar.x - star.x) < 50 && Math.abs(mouseStar.y - star.y) < 50) {
drawLine(mouseStar.x, mouseStar.y, star.x, star.y)
}
})
}, 50)
Copy the code
3. The gobang
See what will happen:
Gobang is divided into the following steps:
- 1. Draw the chessboard
- 2, black and white chess switch next,
Cannot cover a pit that has been placed
- 3. Determine whether
Five son even
If you are, you win - 4. Easter Egg: Follow
AI playing chess
(Implement a single player game)
1. Draw the board
MoveTo and CTX. LineTo are used to draw 15 lines horizontally and 15 lines vertically.
// html
#canvas {
background: #e3cdb0;
}
<canvas id="canvas" width="600" height="600"></canvas>
// js
play()
function play() {
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// Draw the chessboard
// Horizontal, a total of 15 lines
for (let i = 0; i < 15; i++) {
ctx.beginPath()
ctx.moveTo(20.20 + i * 40)
ctx.lineTo(580.20 + i * 40)
ctx.stroke()
ctx.closePath()
}
// Vertical, a total of 15 lines
for (let i = 0; i < 15; i++) {
ctx.beginPath()
ctx.moveTo(20 + i * 40.20)
ctx.lineTo(20 + i * 40.580)
ctx.stroke()
ctx.closePath()
}
}
Copy the code
Thus the chessboard is drawn:
2. Switch between black and white
- 1, click the mouse event, get the coordinates, draw the chess (
ctx.arc
) - 2. Ensure that the position played cannot be repeated
The first step is to get the mouse coordinates, but we need to notice one thing, the chess pieces can only cross the line, so after getting the mouse coordinates, we need to do something, round to the nearest line crossing point as the center of the circle
Step two, how do you make sure you don’t repeat your position? We could use a two-dimensional array, which starts at 0, becomes 1 after black, and becomes 2 after white, but one thing to note here is that the x and y of the array index are the opposite of the x and y of the canvas coordinates, so I want you to think about why the coordinates are reversed in the code.
// Whether to play black
// Black moves first
let isBlack = true
// The board is a two-dimensional array
let cheeks = []
for (let i = 0; i < 15; i++) {
cheeks[i] = new Array(15).fill(0)
}
canvas.onclick = function (e) {
const clientX = e.clientX
const clientY = e.clientY
// Round 40 to make sure the pieces are at the intersection
const x = Math.round((clientX - 20) / 40) * 40 + 20
const y = Math.round((clientY - 20) / 40) * 40 + 20
// cheeks Specifies the index of a two-dimensional array
// This is a little redundant, but it makes sense to write it this way
const cheeksX = (x - 20) / 40
const cheeksY = (y - 20) / 40
// The corresponding element is not 0, indicating that there is a move in this place, return
if (cheeks[cheeksY][cheeksX]) return
Black is 1 and white is 2
cheeks[cheeksY][cheeksX] = isBlack ? 1 : 2
ctx.beginPath()
/ / draw circles
ctx.arc(x, y, 20.0.2 * Math.PI)
// Decide whether to go black or white
ctx.fillStyle = isBlack ? 'black' : 'white'
ctx.fill()
ctx.closePath()
// Switch to black and whiteisBlack = ! isBlack }Copy the code
The effect is as follows:
3. Judge whether it is five consecutive sons
How to tell? There are four situations: up and down five even son, left and right wu Lianzi, left and right five even son, right and left five even son, as long as we each time when all the judgment of a time.
I enclose all the code
play()
function play() {
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// Draw the chessboard
// Horizontal, a total of 15 lines
for (let i = 0; i < 15; i++) {
ctx.beginPath()
ctx.moveTo(20.20 + i * 40)
ctx.lineTo(580.20 + i * 40)
ctx.stroke()
ctx.closePath()
}
// Vertical, a total of 15 lines
for (let i = 0; i < 15; i++) {
ctx.beginPath()
ctx.moveTo(20 + i * 40.20)
ctx.lineTo(20 + i * 40.580)
ctx.stroke()
ctx.closePath()
}
// Whether to play black
// Black moves first
let isBlack = true
// The board is a two-dimensional array
let cheeks = []
for (let i = 0; i < 15; i++) {
cheeks[i] = new Array(15).fill(0)
}
canvas.onclick = function (e) {
const clientX = e.clientX
const clientY = e.clientY
// Round 40 to make sure the pieces are at the intersection
const x = Math.round((clientX - 20) / 40) * 40 + 20
const y = Math.round((clientY - 20) / 40) * 40 + 20
// cheeks Specifies the index of a two-dimensional array
// This is a little redundant, but it makes sense to write it this way
const cheeksX = (x - 20) / 40
const cheeksY = (y - 20) / 40
// The corresponding element is not 0, indicating that there is a move in this place, return
if (cheeks[cheeksY][cheeksX]) return
Black is 1 and white is 2
cheeks[cheeksY][cheeksX] = isBlack ? 1 : 2
ctx.beginPath()
/ / draw circles
ctx.arc(x, y, 20.0.2 * Math.PI)
// Decide whether to go black or white
ctx.fillStyle = isBlack ? 'black' : 'white'
ctx.fill()
ctx.closePath()
// Canvas is asynchronously drawn. Make sure to draw and then check for wins and losses
setTimeout(() = > {
if (isWin(cheeksX, cheeksY)) {
const con = confirm(`${isBlack ? 'black' : 'white'}Win! Do you want to start again? `)
// Start again
ctx.clearRect(0.0.600.600)
con && play()
}
// Switch to black and whiteisBlack = ! isBlack },0)}// Determine whether there are five links
function isWin(x, y) {
const flag = isBlack ? 1 : 2
/ / up and down
if (up_down(x, y, flag)) {
return true
}
/ / left and right
if (left_right(x, y, flag)) {
return true
}
// Upper left and lower right
if (lu_rd(x, y, flag)) {
return true
}
// Upper right and lower left
if (ru_ld(x, y, flag)) {
return true
}
return false
}
function up_down(x, y, flag) {
let num = 1
/ / to find up
for (let i = 1; i < 5; i++) {
let tempY = y - i
console.log(x, tempY)
if (tempY < 0|| cheeks[tempY][x] ! == flag)break
if (cheeks[tempY][x] === flag) num += 1
}
/ / down
for (let i = 1; i < 5; i++) {
let tempY = y + i
console.log(x, tempY)
if (tempY > 14|| cheeks[tempY][x] ! == flag)break
if (cheeks[tempY][x] === flag) num += 1
}
return num >= 5
}
function left_right(x, y, flag) {
let num = 1
/ / to the left to find
for (let i = 1; i < 5; i++) {
let tempX = x - i
if (tempX < 0|| cheeks[y][tempX] ! == flag)break
if (cheeks[y][tempX] === flag) num += 1
}
/ / to the right
for (let i = 1; i < 5; i++) {
let tempX = x + i
if (tempX > 14|| cheeks[y][tempX] ! == flag)break
if (cheeks[y][tempX] === flag) num += 1
}
return num >= 5
}
function lu_rd(x, y, flag) {
let num = 1
// Look to the left
for (let i = 1; i < 5; i++) {
let tempX = x - i
let tempY = y - i
if (tempX < 0 || tempY < 0|| cheeks[tempY][tempX] ! == flag)break
if (cheeks[tempY][tempX] === flag) num += 1
}
// Look right down
for (let i = 1; i < 5; i++) {
let tempX = x + i
let tempY = y + i
if (tempX > 14 || tempY > 14|| cheeks[tempY][tempX] ! == flag)break
if (cheeks[tempY][tempX] === flag) num += 1
}
return num >= 5
}
function ru_ld(x, y, flag) {
let num = 1
// Look up right
for (let i = 1; i < 5; i++) {
let tempX = x - i
let tempY = y + i
if (tempX < 0 || tempY > 14|| cheeks[tempY][tempX] ! == flag)break
if (cheeks[tempY][tempX] === flag) num += 1
}
// Look down to the left
for (let i = 1; i < 5; i++) {
let tempX = x + i
let tempY = y - i
if (tempX > 14 || tempY < 0|| cheeks[tempY][tempX] ! == flag)break
if (cheeks[tempY][tempX] === flag) num += 1
}
return num >= 5}}Copy the code
4. Easter Egg: Play chess with AI
In fact, it is very simple, after each game, set a function: find a random position to play chess. In this way, the realization and computer chess, single player game function, this function I have achieved, but I do not write out, to everyone, as you consolidate this article homework. Ha ha ha ha
conclusion
Sleep sleep, this article has written me for 7 hours, in fact, these three small games have a lot of places can be optimized, you can put forward, learn from each other. Like brothers and sisters, thank you!! For study group, please click here