Summary: You guys, can you insert this snake game into the editor?
This article is shared from the HUAWEI cloud community " Let's play ", the original author: DevUI.
insert this snake game into the editor?
Just follow the four steps below:
- Step 1: Customize toolbar buttons
- Step 2: Customize Blot content
- Step 3: Register custom Blot on Quill
- Step 4: Call Quill's API to insert custom content
Step 1: Customize toolbar buttons
This is very simple:
const TOOLBAR_CONFIG = [
[{ header: ['1', '2', '3', false] }],
['bold', 'italic', 'underline', 'link'],
[{ list: 'ordered' }, { list: 'bullet' }],
['clean'],
['card', 'divider', 'emoji', 'file', 'tag'],
['dragon', 'snake'], // 新增的
];
Customize toolbar button icons:
const snakeIcon = `<svg>...</svg>`;
const icons = Quill.import('ui/icons');
icons.snake = snakeIcon;
Add toolbar button event:
const quill = new Quill('#editor', {
theme: 'snow',
modules: {
toolbar: {
container: TOOLBAR_CONFIG,
handlers: {
...
// 增加一个空的事件
snake(value): void {
console.log('snake~~');
},
},
}
},
});
Step 2: Customize Blot content SnakeBlot
No longer verbose, just refer to the previous article and write it directly:
"How to insert the dragon into the editor? 》
"Practice of Quill Rich Text Editor"
snake.ts
import Quill from 'quill';
import GreedySnake from '../../shared/greedy-snake';
const BlockEmbed = Quill.import('blots/block/embed');
class SnakeBlot extends BlockEmbed {
static blotName = 'snake';
static tagName = 'canvas';
static create(value): any {
const node = super.create(value);
const { id, width, height } = value;
node.setAttribute('id', id || SnakeBlot.blotName);
if (width !== undefined) {
node.setAttribute('width', width);
}
if (height !== undefined) {
node.setAttribute('height', height);
}
// 绘制贪吃蛇游戏的代码参考对半同学的文章:https://juejin.cn/post/6959789039566192654
new GreedySnake(node).start();
return node;
}
}
export default SnakeBlot;
Draw greedy snake
Since the code written by half of the students in an hour is really elegant, I couldn't help posting the code (invasion). The source code of the article comes from the article of half of the students:
Canvas 300 lines of code to achieve a greedy snake
greedy-snake.ts
// 大小为64 * 40
export default class GreedySnake {
canvas;
ctx;
maxX;
maxY;
itemWidth;
direction;
speed;
isStop;
isOver;
isStart;
score;
timer;
j;
canChange;
grid;
snake;
food;
// mask;
// scoreDom;
constructor(container) {
this.canvas = typeof container === 'string' ? document.querySelector(container) : container;
this.canvas.setAttribute('width', 640);
this.canvas.setAttribute('height', 400);
this.canvas.setAttribute('style', 'border: solid 2px #ddd');
this.ctx = this.canvas.getContext('2d');
this.maxX = 64; // 最大行
this.maxY = 40; // 最大列
this.itemWidth = 10; // 每个点的大小
this.direction = 'right'; // up down right left 方向
this.speed = 150; // ms 速度
this.isStop = false; // 是否暂停
this.isOver = false; // 是否结束
this.isStart = false; // 是否开始
this.score = 0; // 分数
this.timer = null; // 移动定时器
this.j = 1;
this.canChange = true;
this.grid = new Array();
// this.scoreDom = document.querySelector('#score');
// this.mask = document.querySelector('#mask');
for (let i = 0; i < this.maxX; i++) {
for (let j = 0; j < this.maxY; j++) {
this.grid.push([i, j]);
}
}
this.drawGridLine();
this.getDirection();
document.addEventListener('keydown', (event) => {
if (event.keyCode === 13) {
if (!this.isStart) return;
this.start();
}
});
}
// 开始
start(): void {
if (this.timer) {
clearTimeout(this.timer);
}
if (!this.isStart) {
this.isStart = true;
}
this.score = 0;
this.speed = 150;
this.isStop = false;
this.isOver = false;
this.direction = 'right';
this.createSnake();
this.createFood();
this.draw();
this.move();
// this.mask.style.display = 'none';
}
// 创建蛇主体
createSnake(): void {
this.snake = [
[4, 25],
[3, 25],
[2, 25],
[1, 25],
[0, 25]
];
}
// 移动
move(): void {
if (this.isStop) {
return;
}
let [x, y] = this.snake[0];
switch (this.direction) {
case 'left':
x--;
break;
case 'right':
x++;
break;
case 'up':
y--;
break;
case 'down':
y++;
break;
}
// 如果下一步不是食物的位置
if (x !== this.food[0] || y !== this.food[1]) {
this.snake.pop();
} else {
this.createFood();
}
if (this.over([x, y])) {
this.isOver = true;
// this.mask.style.display = 'block';
// this.mask.innerHTML = '结束';
return;
}
if (this.completed()) {
// this.mask.style.display = 'block';
// this.mask.innerHTML = '恭喜您,游戏通关';
return;
}
this.snake.unshift([x, y]);
this.draw();
this.canChange = true;
this.timer = setTimeout(() => this.move(), this.speed);
}
// 暂停游戏
stop(): void {
if (this.isOver) {
return;
}
this.isStop = true;
// this.mask.style.display = 'block';
// this.mask.innerHTML = '暂停';
}
// 继续游戏
continue(): void {
if (this.isOver) {
return;
}
this.isStop = false;
this.move();
// this.mask.style.display = 'none';
}
getDirection(): void {
// 上38 下40 左37 右39 不能往相反的方向走
document.onkeydown = (e) => {
// 在贪吃蛇移动的间隔内不能连续改变两次方向
if (!this.canChange) {
return;
}
switch (e.keyCode) {
case 37:
if (this.direction !== 'right') {
this.direction = 'left';
this.canChange = false;
}
break;
case 38:
if (this.direction !== 'down') {
this.direction = 'up';
this.canChange = false;
}
break;
case 39:
if (this.direction !== 'left') {
this.direction = 'right';
this.canChange = false;
}
break;
case 40:
if (this.direction !== 'up') {
this.direction = 'down';
this.canChange = false;
}
break;
case 32:
// 空格暂停与继续
if (!this.isStop) {
this.stop();
} else {
this.continue();
}
break;
}
};
}
createPos(): any {
// tslint:disable-next-line: no-bitwise
const [x, y] = this.grid[(Math.random() * this.grid.length) | 0];
for (const item of this.snake) {
if (item[0] === x && item[1] === y) {
return this.createPos();
}
}
// for (let i = 0; i < this.snake.length; i++) {
// if (this.snake[i][0] === x && this.snake[i][1] === y) {
// return this.createPos();
// }
// }
return [x, y];
}
// 生成食物
createFood(): void {
this.food = this.createPos();
// 更新分数
// this.scoreDom.innerHTML = 'Score: ' + this.score++;
if (this.speed > 50) {
this.speed--;
}
}
// 结束
over([x, y]): boolean {
if (x < 0 || x >= this.maxX || y < 0 || y >= this.maxY) {
return true;
}
if (this.snake.some(v => v[0] === x && v[1] === y)) {
return true;
}
}
// 完成
completed(): boolean {
if (this.snake.length === this.maxX * this.maxY) {
return true;
}
}
// 网格线
drawGridLine(): void {
for (let i = 1; i < this.maxY; i++) {
this.ctx.moveTo(0, i * this.itemWidth);
this.ctx.lineTo(this.canvas.width, i * this.itemWidth);
}
for (let i = 1; i < this.maxX; i++) {
this.ctx.moveTo(i * this.itemWidth, 0);
this.ctx.lineTo(i * this.itemWidth, this.canvas.height);
}
this.ctx.lineWidth = 1;
this.ctx.strokeStyle = '#ddd';
this.ctx.stroke();
}
// 绘制
draw(): void {
// 清空画布
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.drawGridLine();
this.ctx.fillStyle = '#000';
this.ctx.fillRect(
this.food[0] * this.itemWidth + this.j,
this.food[1] * this.itemWidth + this.j,
this.itemWidth - this.j * 2,
this.itemWidth - + this.j * 2
);
// tslint:disable-next-line: no-bitwise
this.j ^= 1;
this.ctx.fillStyle = 'green';
this.ctx.fillRect(
this.snake[0][0] * this.itemWidth + 0.5,
this.snake[0][1] * this.itemWidth + 0.5,
this.itemWidth - 1,
this.itemWidth - 1
);
this.ctx.fillStyle = 'red';
for (let i = 1; i < this.snake.length; i++) {
this.ctx.fillRect(
this.snake[i][0] * this.itemWidth + 0.5,
this.snake[i][1] * this.itemWidth + 0.5,
this.itemWidth - 1,
this.itemWidth - 1
);
}
}
}
Step 3: Register custom Blot on Quill
With SnakeBlot, you also need to register it in Quill before you can use it:
import SnakeBlot from './formats/snake';
Quill.register('formats/snake', SnakeBlot);
Step 4: Call Quill's API to insert custom content
After calling the API, you can play the snake game, so happy to fly!
const quill = new Quill('#editor', {
theme: 'snow',
modules: {
toolbar: {
container: TOOLBAR_CONFIG,
handlers: {
...
snake(value): void {
console.log('snake~~');
const index = this.quill.getSelection().index;
// 插入自定义内容
this.quill.insertEmbed(index, 'snake', {
id: 'canvas-snake',
});
},
},
}
},
});
Effect picture:
Always keep your childish innocence, keep your curiosity about the world, you are the best gift God brings to this world.
Click to follow and learn about Huawei Cloud's fresh technology for the first time~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。