У меня ничего не было несколько дней назад, я написал инструмент для Favicon, чтобы смотреть видео.У меня было несколько молодых братьев, как это.Я обновил несколько функций, пишу полную версию учебника, и код находится на github. .GitHub.com/ волнуйся, золото...
новые особенности
- Индикатор выполнения видео, управление громкостью видео вверх, вниз, влево и вправо, вперед и назад
- Живая веб-камера, добавьте простой ностальгический фильтр 🐶
- Змеиная игра
первый взгляд на эффект
Принцип очень простой, на фавикон можно поставить картинку 32*32, мы можем динамически модифицировать эту картинку, мы можем реализовать функции проигрывания видео, просмотра камеры и мини-игр, а также непосредственно смотреть полную версию код.
проиграть видео
См. предыдущую статью о функции видео.nuggets.capable/post/684490…
Регуляторы громкости и видео
Документ прослушивает события клавиатуры и обрабатывает их по-разному для движений вверх, вниз, влево и вправо.
const DIRECTION = {
37:'left',
// 上
38:'up',
// 右
39:'right',
// 下
40:'down',
}
const directions = {
left: ()=> this.video.currentTime-=5,
right: ()=> this.video.currentTime+=5,
up: ()=> this.video.volume+=0.1,
down: ()=> this.video.volume-=0.1,
}
document.onkeydown = (event)=> {
// 左上右下 37 38 39 40
let key = event.keyCode
if(key in DIRECTION){
directions[DIRECTION[key]]()
}
}
возьми
индикатор выполнения видео
В соответствии с currentTime и продолжительностью вы можете получить событие воспроизведения и общую продолжительность видео.
Согласно этой статьеAnimating URLs with Javascript and EmojisВдохновленный , используйте эмодзи для создания графического индикатора выполнения
formatTime(second){
const m = Math.floor(second/60) + ''
const s = parseInt(second%60) + ''
return m.padStart(2,'0')+":"+s.padStart(2,'0')
}
showProgress(){
const current = this.video.currentTime
const total = this.video.duration
const per = Math.floor((current/total)*4)
console.log((current/total).toFixed(2))
const p = ['🌑', '🌒', '🌓', '🌔', '🌝'][per]
document.title = `${p}${this.formatTime(current)}/${this.formatTime(total)}`
}
Эффект
камера
Это очень просто реализовать с помощью webrtc, вроде бы функции для птичек нет, это чисто развлечение, можно следить есть ли за тобой босс Попробуйте добавить распознавание лиц позже, чтобы идентифицировать босса, или, если вы слишком счастливо улыбаетесь, отправьте напоминание
let video = document.createElement('video')
video.width=this.width
video.autoplay="autoplay"
document.body.appendChild(video)
this.video = video
const mediaStream = await navigator.mediaDevices.getUserMedia({video:true}) // webrtc
this.video.srcObject = mediaStream
this.video.addEventListener('timeupdate',()=>{
this.videoToImageByFilter()
},false)
фильтр
Если вы используете это для прямой трансляции, хотя это немного меньше, вы также можете рассмотреть возможность добавления фильтра.Принцип также очень прост.Холст получает значение цвета пикселя изображения.Для требуемого фильтра найдите формулу и установите его, например, фильтр серого. Вычислите RBG единичного элемента, а затем возьмите среднее значение и скопируйте его себе, чтобы получить серое изображение.
const context = this.canvas.getContext('2d')
context.clearRect(0, 0, this.SIDE, this.SIDE)
context.drawImage(this.video, 0, 0, this.SIDE, this.SIDE)
//获取ImageData的属性:width,height,data(包含 R G B A 四个值);
var imgdata = context.getImageData(0,0,this.SIDE,this.SIDE)
for(var i=0;i<imgdata.data.length;i += 4){
// 灰色滤镜
// 计算获取单位元素的RBG然后取平均值 然后复制给自身得到灰色的图像
var avg = (imgdata.data[i]+ imgdata.data[i+1]+ imgdata.data[i+2])/3
imgdata.data[i] = imgdata.data[i+1] =imgdata.data[i+2] =avg
}
this.canvasFilter.getContext('2d').putImageData(imgdata,0,0);
setFavico(this.canvasFilter)
Формула фильтра ностальгии
Код вот-вот выйдет, не спрашивайте логику, спрашивайте, чтобы скопировать формулы, многие формулы фильтров можно найти на baidu, например, мультфильмы, печи, черно-белые и т. д.
// 怀旧滤镜
const context = this.canvas.getContext('2d')
context.clearRect(0, 0, this.SIDE, this.SIDE)
context.drawImage(this.video, 0, 0, this.SIDE, this.SIDE)
//获取ImageData的属性:width,height,data(包含 R G B A 四个值);
var imgdata = context.getImageData(0,0,this.SIDE,this.SIDE)
for(var i = 0; i < imgdata.height * imgdata.width; i++) {
var r = imgdata.data[i*4],
g = imgdata.data[i*4+1],
b = imgdata.data[i*4+2];
var newR = (0.393 * r + 0.769 * g + 0.189 * b);
var newG = (0.349 * r + 0.686 * g + 0.168 * b);
var newB = (0.272 * r + 0.534 * g + 0.131 * b);
var rgbArr = [newR, newG, newB].map((e) => {
return e < 0 ? 0 : e > 255 ? 255 : e;
});
[imgdata.data[i*4], imgdata.data[i*4+1], imgdata.data[i*4+2]] = rgbArr;
}
this.canvasFilter.getContext('2d').putImageData(imgdata,0,0);
setFavico(this.canvasFilter)
Увидев себя немного меланхоличным в фавиконе, я чувствую, что вернулась в юношеские времена убийства Мэтта, но, к сожалению, объема моих волос сейчас недостаточно.
Змея
На самом деле, 32 * 32 пикселя все еще могут выполнять много интересных функций.После переменной 1px остается еще 30px для воспроизведения.Базовая длина стороны составляет 2 и 3 пикселя.Мы можем иметь максимальную длину стороны 15 для воспроизведения, например обжорство Змейка, тетрис, желающие могут бросить вызов танковому бою, сокобан
Нечего сказать, сначала напишите код, принцип прожорливой змеи заключается в том, чтобы сесть на холст, затем отрисовать фавикон и создать новый класс.
class Snake {
constructor(){
// 15*15
this.SIDE = 32 // favcion边长32px
this.LINE_WIDTH = 1 // 1px
this.SIZE = 3 // 一个数据点的像素值
this.WIDTH =10 // 游戏空间是10个 (32-2)/3
this.initCanvas()
}
initCanvas(){
this.canvas = document.createElement('canvas')
this.canvas.width = this.canvas.height = this.SIDE
}
initGrid(){
this.grid = []
while(this.grid.length<this.WIDTH){
this.grid.push(new Array(this.WIDTH).fill(0))
}
}
}
инициализация
После создания новой сетки указываем, что 0 — начальное значение, позиция, которую занимает змейка — 1, а еда — 2
Начальная длина змеи 3, центр слева,
// 初始化小蛇蛇
initSnake(){
this.snake = []
// 初始值长度是3 处置位置在左侧中间
let y = 4
let x = 0
let snakeLength = 3
while(snakeLength>0){
this.snake.push({x:x,y:y})
this.grid[y][x] = '1'
snakeLength--
x++
}
// 小蛇的初始方向是右边
this.current = this.directions.right
}
Давайте запустим console.table this.grid
bingo
визуализировать сетку
Нам нужно отобразить сетку на холсте, сначала поместив холст в тело, чтобы облегчить отладку. Способ очень грубый, просто игрушка, без учета оптимизации рендера, обход сетки напрямую, и каждый раз перерендерить
initCanvas(){
this.canvas = document.createElement('canvas')
this.canvas.width = this.canvas.height = this.SIDE
document.body.appendChild(this.canvas)
}
drawCanvas(){
// 32*32 四周变量1px,所以中间是30*30, 用15*15的格子,每个格子2px
var context = this.canvas.getContext('2d') //getContext() 方法可返回一个对象
context.clearRect(0,0,this.SIDE,this.SIDE)
context.strokeStyle = 'green'
context.lineWidth = this.LINE_WIDTH
context.fillStyle = "red" // 设置或返回用于填充绘画的颜色、渐变或模式
context.strokeRect(0, 0, this.SIDE, this.SIDE)
this.grid.forEach((row,y)=>{
row.forEach((g,x)=>{
if(g!==0){
// 食物或者是蛇
context.fillRect(this.LINE_WIDTH+x*this.SIZE,this.LINE_WIDTH+y*this.SIZE,this.SIZE,this.SIZE) // x轴 y轴 宽 和 高 ,绘制“被填充”的矩形
}
})
})
setFavico(this.canvas)
}
увидеть эффект
Маленькая змея вышла да
положить еду
Это ничего не сказать, рандом координата, а потом позиция падает на змейку, потом перерандомить, иначе ставь 2 и рисуй красным Затем сделайте скриншот холста и поместите его на фавикон.
// 放吃的
setFood(){
while(true){
const x = Math.floor(Math.random()* this.WIDTH)
const y = Math.floor(Math.random()* this.WIDTH)
if(this.grid[y][x]=='1'){
continue
}else{
//食物是2
this.grid[y][x]='2'
break
}
}
}
переехать
Есть четыре направления движения: вверх, вниз, влево и вправо. Здесь немного лениво. Просто оцените точку, в которой находится следующая голова змеи, исходя из направления и положения головы змеи, а затем решите, следует ли ущипнуть. от кончика хвоста в зависимости от того, ест он пищу или нет.Это относительно просто.
- Положение следующей головы змеи, если она выходит за пределы сетки, или самой змеи, игра окончена, а статистический счет помещается в локальное хранилище.
- setInterval можно регулярно перемещать в соответствии с направлением
this.directions = {
// 左
'left':{x:-1,y:0},
// 上
'up':{x:0,y:-1},
// 右
'right':{x:1,y:0},
// 下
'down':{x:0,y:1},
}
move(){
// 1. 根据方向,计算出下一个蛇头所在位置
// 蛇头设为
const head = this.snake[this.snake.length-1]
const tail = this.snake[0]
const nextX = head.x+this.current.x
const nextY = head.y+this.current.y
// 2. 判断蛇头是不是出界 是不是碰见自己个了 如果是屁股尖就碰不到
const isOut = nextX<0||nextX>=this.WIDTH||nextY<0||nextY>=this.WIDTH
if(isOut){
this.initGame()
return
}
const isSelf = (this.grid[nextY][nextX]) =='1' && !(nextX === tail.x && nextY === tail.y)
if(isSelf){
this.initGame()
return
}
const isFood = this.grid[nextY][nextX]=='2' // 食物是2
if(!isFood){
// 所谓蛇向前走,就是把尾巴去掉, 新增nextX和Y
// 去尾巴 有食物的时候不用去尾
this.snake.shift()
this.grid[tail.y][tail.x] = 0
}else{
// 食物吃掉了,在放一个
this.setFood()
// 加一份
this.score++
this.setTitle()
}
// 新增头部
this.snake.push({x:nextX,y:nextY})
this.grid[nextY][nextX] = '1'
this.drawCanvas()
}
следовать за
Включение этих кодов также написано Moyu, что сделало эту функцию бесполезной для птиц, 囧, добро пожаловать, обратите внимание и вместе разработайте больше проектов Moyu. Это все по основным функциям, достаточно самому порыбачить, так можно открыть 3 вкладки
- Вкладка 1 для просмотра небольших видеороликов
- Включите камеру на вкладке №2, чтобы не дать классному руководителю сзади
- Играть в «Змейку» на вкладке 3
На самом деле 30*30 пикселей можно много чего сделать, например тетрис, волшебную башню, танковый бой, все можно проставить, если интересно, можете попробовать
Кодовый адрес:GitHub.com/Worry Gold…Через два дня тоже запишу видео кода 0.2 и выложу на станцию Б.Видео версии 0.1Добро пожаловать три компании
Создайте группу, ловите рыбу вместе, добавьте меня в WeChat, если вы не можете войтиwoniu_ppp