我的编辑器能玩贪吃蛇,一起玩不?
Posted 华为云开发者社区
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我的编辑器能玩贪吃蛇,一起玩不?相关的知识,希望对你有一定的参考价值。
摘要:你们说,能不能把这个贪吃蛇游戏插入到编辑中呢?
本文分享自华为云社区《整个贪吃蛇到编辑器里玩吧》,原文作者:DevUI。
能不能把这个贪吃蛇游戏插入到编辑中呢?
按照以下四个步骤来就行:
- 第一步:自定义工具栏按钮
- 第二步:自定义Blot内容
- 第三步:在Quill注册自定义Blot
- 第四步:调用Quill的API插入自定义内容
第一步:自定义工具栏按钮
这个非常简单:
const TOOLBAR_CONFIG = [ [{ header: [\'1\', \'2\', \'3\', false] }], [\'bold\', \'italic\', \'underline\', \'link\'], [{ list: \'ordered\' }, { list: \'bullet\' }], [\'clean\'], [\'card\', \'divider\', \'emoji\', \'file\', \'tag\'], [\'dragon\', \'snake\'], // 新增的 ];
自定义工具栏按钮图标:
const snakeIcon = `<svg>...</svg>`; const icons = Quill.import(\'ui/icons\'); icons.snake = snakeIcon;
增加工具栏按钮事件:
const quill = new Quill(\'#editor\', { theme: \'snow\', modules: { toolbar: { container: TOOLBAR_CONFIG, handlers: { ... // 增加一个空的事件 snake(value): void { console.log(\'snake~~\'); }, }, } }, });
第二步:自定义Blot内容 SnakeBlot
不再啰嗦,参考之前的文章直接写就好:
《如何将龙插入到编辑器中? 》
《Quill富文本编辑器的实践》
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;
绘制贪吃蛇
由于对半
同学花一个小时写出来的代码实在非常优雅,忍不住将其代码贴出来了(侵删),文章源码来源于对半
同学的文章:
canvas 300行代码实现一个贪吃蛇
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 ); } } }
第三步:在Quill注册自定义Blot
有了 SnakeBlot,还需要将其注册到 Quill 中才能使用:
import SnakeBlot from \'./formats/snake\'; Quill.register(\'formats/snake\', SnakeBlot);
第四步:调用Quill的API插入自定义内容
调用完API就可以玩贪吃蛇游戏啦,开心到飞起!
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\', }); }, }, } }, });
效果图:
永远保持童心,保持对世界的好奇,你就是上帝带给这个世界最好的礼物。
以上是关于我的编辑器能玩贪吃蛇,一起玩不?的主要内容,如果未能解决你的问题,请参考以下文章