недавняя параhtml5
Небольшие игры немного интересны, потому что я чувствую, что эта вещь может стать важным сценарием внешнего интерфейса в будущем, например, каждый праздник сейчас, например, Alipay, Taobao или другие.APP
Это может дать вам push-уведомление, а затем нажать на него, это будет небольшая игра.По сути, люди, которые нажимают на него, будут играть в игру, пока они не слишком конфликтуют.get
к пользователюG
Это может еще больше улучшить бизнес, будь то пользовательский опыт или развитие бизнеса, это очень хороший способ улучшить.
Кроме того, я сказал этоhtml5
мини-игры включеныWebGL
,WebVR
и т. д., не ограничиваясь только играми, но и другими сценариями, в которых используются связанные технологии, например изображения продуктов.360°
Если смотреть это онлайн, то причина, по которой мы начинаем с мини-игр, заключается в том, что мини-игры требуют всеобъемлющих технологий.Если вы можете сделать игру хорошо, а затем использовать ту же технологию для других вещей, это более удобно.
Поискав информацию, я обнаружил, что дорвеев еще довольно много.Посмотрев вокруг, я решил начать с азов, начиная с более простых.canvas
Глядя на игру, прочитав некоторые статьи и книги по теме, я обнаружил, что, хотя эта вещь очень проста в использовании, все же немного сложно ее использовать хорошо, и все еще немного сложно ею пользоваться. начать с реального боя.
Итак, я собираюсь написатьcanvas
Малая игровая практика, связаннаяUI
Материал собран, но как говоритсяЕсли вы хотите делать хорошую работу, вы должны сначала заточить свои инструменты,Поскольку у меня нет опыта в этой области, чтобы избежать всяких ям в процессе, я специально читал некоторые связанные статьи по наступлению на ямы.Я чувствую, что производительность - это то, на что нужно обратить внимание, и есть много дверных проемов, поэтому я разобрался.
использоватьrequestNextAnimationFrame
Сделать анимационный цикл
setTimeout
а такжеsetInterval
Не предназначен для непрерывного циклаAPI
, поэтому может не получиться добиться плавной анимации, поэтому используйтеrequestNextAnimationFrame
,может понадобитьсяpolyfill
:
const raf = window.requestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.oRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function(callback) {
window.setTimeout(callback, 1000 / 60)
}
Воспользуйтесь преимуществами областей отсечения для анимированных фонов или других неизменяемых изображений.
Для простых анимаций стирание и перерисовка всего на холсте в каждом кадре — хорошая идея, но для сложных фонов вы можете использоватьобласть отсечениятехника для повышения производительности за счет меньшего отрисовки на кадр
Этапы выполнения использования технологии отсечения области для восстановления фонового изображения, занятого предыдущим кадром анимации:
- передача
context.save()
, сохранить экранcanvas
положение дел - позвонив
beginPath
начать новый путь - существует
context
вызов на объектarc()
,rect()
и т. д., чтобы установить путь - передача
context.clip()
метод, установите текущий путь к экрануcanvas
область отсечения - протрите экран
canvas
(фактически стирается только область, где находится область отсечения) - вывести фоновое изображение на экран
canvas
включено (операции рисования на самом деле влияют только на размер области отсечения, поэтому изображение рисуется с меньшим количеством пикселей на кадр) - восстановить экран
canvas
параметр состояния, сбрасывает область отсечения
Закадровый буфер (закадровый холст)
Первый рисунок за кадромcanvas
, а затем черезdrawImage
вне экранаcanvas
подтянуться к главномуcanvas
, это поставить за кадромcanvas
как буфер. Кэшируйте данные экрана, которые необходимо многократно отрисовывать, чтобы уменьшить число вызовов.canvas
изAPI
потребление
const cacheCanvas = document.createElement('canvas')
const cacheCtx = cacheCanvas.getContext('2d')
cacheCtx.width = 200
cacheCtx.height = 200
// 绘制到主canvas上
ctx.drawImage(0, 0)
Хотя за кадромcanvas
Его нельзя увидеть в поле зрения перед отрисовкой, но его ширину и высоту лучше установить равными размеру элемента кэша, чтобы не тратить ресурсы и не рисовать ненужные ненужные изображения.drawImage
масштабирование изображения также будет потреблять ресурсы
При необходимости можно использовать несколько экрановcanvas
Кроме того, за кадромcanvas
Когда эта ссылка больше не используется, лучше вручную сбросить ссылку наnull
, избегайте, потому чтоjs
а такжеdom
Взаимосвязь между ними приводит к тому, что механизм сборки мусора не работает должным образом и занимает ресурсы.
сделать большую частьCSS
фоновая картинка
Если есть большое статичное фоновое изображение, рисуйте прямо наcanvas
Это может быть не очень хорошей практикой, если вы можете использовать это большое фоновое изображение какbackground-image
положить вDOM
элемент (например,div
), затем поместите этот элемент вcanvas
После этого одним меньшеcanvas
рисовать визуализацию
трансформировать изменения
CSS
изtransform
превосходитcanvas
изtransfomr API
, потому что первый может быть хорошо использован на основеGPU
, так что, если вы можете,transform
Измените, пожалуйста, используйтеCSS
контролировать
Отключить прозрачность
Создайтеcanvas
контекстуальныйAPI
Есть второй параметр:
canvas.getContext(contextType, contextAttributes)
contextType
является типом контекста, а общие значения2d
,Кроме тогоwebgl
,webgl2
,bitmaprenderer
Три значения, но последние три браузера поддерживают слишком низкие, обычно не используются
contextAttributes
атрибут контекста, используемый для инициализации некоторых атрибутов контекста для различныхcontextType
,contextAttributes
Возможные значения также различны, для часто используемых2d
,contextAttributes
Возможные значения:
- alpha
boolean
введите значение, указывающееcanvas
содержитalpha
канал.По умолчаниюtrue
, если установленоfalse
, браузер рассмотритcanvas
Фон всегда непрозрачный, что ускоряет отрисовку прозрачного содержимого и изображений.
- willReadFrequently
boolean
Введите значение, указывающее, существует ли план повторного чтения. часто используемыйgetImageData()
, что заставит программное обеспечение использовать2D canvas
И экономия памяти (вместо аппаратного ускорения). Эта схема работает для экзистенциальных свойствgfx.canvas.willReadFrequently
среда г. и установить наtrue
(По умолчанию толькоB2G / Firefox OS
)
Низкая поддержка, пока толькоGecko
Поддержка браузера ядра, обычно не используется
- storage
string
Указывает способ хранения (по умолчанию: постоянный (persistent
))
Низкая поддержка, пока толькоBlink
Поддержка браузера ядра, обычно не используется
Вышеупомянутые три атрибута см. часто используемыеalpha
Просто отлично, если ваша игра использует холст и не нуждается в прозрачности, при использованииHTMLCanvasElement.getContext()
При создании контекста рисования поместитеalpha
параметры установлены наfalse
, эта опция может помочь браузеру выполнить внутреннюю оптимизацию
const ctx = canvas.getContext('2d', { alpha: false })
Старайтесь не часто вызывать трудоемкие API.
Например
shadow
СвязанныйAPI
, такойAPI
включатьshadowOffsetX
,shadowOffsetY
,shadowBlur
,shadowColor
связанные с рисованиемAPI
,НапримерdrawImage
,putImageData
, масштабирование во время рисования также увеличивает время
Конечно, всего вышеперечисленного следует по возможности избегать.частоВызов или использование других средств для контроля производительности должны использоваться там, где это необходимо.
Избегайте координат с плавающей запятой
использоватьcanvas
При анимации, если вычисляемые координаты являются числами с плавающей запятой, может появитьсяCSS Sub-pixel
Проблема в том, что значение с плавающей запятой будет автоматически округляться до целого числа, то в процессе анимации, так как реальная траектория движения элемента получается не строго по расчетной формуле, может возникнуть дрожание, и элемент может тоже дергаться.сглаживание по краям
Это также аспект, который может повлиять на производительность, поскольку все время выполняются ненужные криминалистические расчеты.
Операции рендеринга и рисования не следует вызывать часто
Визуализированоapi
,Напримерstroke()
,fill
,drawImage
, будетctx
Состояние конечного автомата на самом деле рисуется на холсте, что также требует большей производительности.
Например, если вы хотите нарисовать десять отрезков, тоctx
Нарисуйте конечный автомат из десяти сегментов антенны в конечном автомате, а затем нарисуйте его один раз, что будет намного эффективнее, чем рисовать каждый линейный сегмент один раз.
for (let i = 0; i < 10; i++) {
context.beginPath()
context.moveTo(x1[i], y1[i])
context.lineTo(x2[i], y2[i])
// 每条线段都单独调用绘制操作,比较耗费性能
context.stroke()
}
for (let i = 0; i < 10; i++) {
context.beginPath()
context.moveTo(x1[i], y1[i])
context.lineTo(x2[i], y2[i])
}
// 先绘制一条包含多条线条的路径,最后再一次性绘制,可以得到更好的性能
context.stroke()
Измените состояние конечного автомата ctx как можно меньше
ctx
Его можно рассматривать как конечный автомат, напримерfillStyle
,globalAlpha
,beginPath
,Этиapi
изменитсяctx
Что касается состояния внутри, то частое изменение состояния конечного автомата влияет на производительность.
Вы можете повысить производительность, лучше планируя операции и уменьшая количество изменений конечного автомата, таких как рисование нескольких строк текста на холсте, а шрифты верхнего и нижнего текста одинаковы.30px
, цветаyellowgreen
, средний текст20px pink
, то вы можете сначала нарисовать верхний и нижний текст, а затем нарисовать средний текст вместо того, чтобы рисовать сверху вниз, потому что первый уменьшает изменение состояния конечного автомата один раз
const c = document.getElementById("myCanvas")
const ctx = c.getContext("2d")
ctx.font = '30 sans-serif'
ctx.fillStyle = 'yellowgreen'
ctx.fillText("大家好,我是最上面一行", 0, 40)
ctx.font = '20 sans-serif'
ctx.fillStyle = 'red'
ctx.fillText("大家好,我是中间一行", 0, 80)
ctx.font = '30 sans-serif'
ctx.fillStyle = 'yellowgreen'
ctx.fillText("大家好,我是最下面一行", 0, 130)
Эффект следующего кода такой же, как и выше, но количество кода меньше, и конечный автомат изменяется меньше, чем приведенный выше код, и производительность будет лучше.
ctx.font = '30 sans-serif'
ctx.fillStyle = 'yellowgreen'
ctx.fillText("大家好,我是最上面一行", 0, 40)
ctx.fillText("大家好,我是最下面一行", 0, 130)
ctx.font = '20 sans-serif'
ctx.fillStyle = 'red'
ctx.fillText("大家好,我是中间一行", 0, 80)
звонить как можно режеcanvas API
Эм,canvas
также манипулируяjs
рисовать, но по сравнению с обычнымjs
работай, звониcanvas API
Будет потреблять больше ресурсов, поэтому планируйте, прежде чем рисовать, поУмеренный js
Сокращение собственных вычисленийcanvas API
Звонок - более рентабельная вещь
Конечно, обратите вниманиеУмеренныйДва слова, если одну строку сократитьcanvas API
Стоимость звонка десять дополнительных линийjs
Посчитай, тогда этого может и не надо делать
избежать блокировки
При выполнении некоторых трудоемких операций, таких как вычисление большого объема данных, один кадр содержит слишком много состояний рисования, крупномасштабныхDOM
Операции и т. д. могут привести к зависанию страницы и повлиять на работу пользователей. Можно использовать следующие два метода:
web worker
web worker
Наиболее часто используемый сценарий — большое количество частых вычислений для снижения нагрузки на основной поток.Если вы столкнулись с крупномасштабными вычислениями, вы можете использовать этотAPI
Разделите основное давление нити, этоAPI
Совместимость уже очень хорошая, т.к.canvas
можно использовать, т.web worker
Также можно рассмотреть возможность использования
Разбивайте задачи
Разделите большой процесс задачи на несколько небольших задач и используйте опрос таймера для выполнения операций.Для декомпозиции задачи задача должна соответствовать следующим условиям:
- Операции циклической обработки, не требующие синхронизации
- Данные не требуется обрабатывать для
Задачи декомпозиции включают две ситуации:
- Распределить по общему количеству задач
Например, для выполнения общей операционной задачи из десятков миллионов уровней ее можно разложить на10
вычислительные задачи уровня миллионов
// 封装 定时器分解任务 函数
function processArray(items, process, callback) {
// 复制一份数组副本
var todo=items.concat();
setTimeout(function(){
process(todo.shift());
if(todo.length>0) {
// 将当前正在执行的函数本身再次使用定时器
setTimeout(arguments.callee, 25);
} else {
callback(items);
}
}, 25);
}
// 使用
var items=[12,34,65,2,4,76,235,24,9,90];
function outputValue(value) {
console.log(value);
}
processArray(items, outputValue, function(){
console.log('Done!');
});
Преимущество в том, что режим распределения задач более простой и управляемый, но недостаток в том, что трудно определить размер небольших задач.
Некоторые небольшие задачи могут по некоторым причинам занимать больше времени, чем другие небольшие задачи, что приведет к блокировке потока; в то время как некоторые небольшие задачи могут требовать гораздо меньше времени, чем другие задачи, что приводит к пустой трате ресурсов.
- Распределить на основе времени выполнения
Например, при выполнении общей вычислительной задачи из десятков миллионов уровней напрямую не определяется, сколько подзадач выделено, или степень детализации распределения относительно мала.После завершения каждого или нескольких вычислений проверьте время, затраченное на этой операции.Если время меньше определенного критического значения, такого как10ms
, затем продолжите операцию, иначе сделайте паузу, дождитесь следующего опроса, прежде чем продолжить
function timedProcessArray(items, process, callback) {
var todo=items.concat();
setTimeout(function(){
// 开始计时
var start = +new Date();
// 如果单个数据处理时间小于 50ms ,则无需分解任务
do {
process(todo.shift());
} while (todo.length && (+new Date()-start < 50));
if(todo.length > 0) {
setTimeout(arguments.callee, 25);
} else {
callback(items);
}
});
}
Преимущество в том, что проблема в первом случае избегается, а недостаток в том, что есть дополнительная операция сравнения времени, и процесс дополнительной операции также может повлиять на производительность.
Суммировать
что я собираюсь делатьcanvas
Игра кажется долго делается.Кроме того,чтобы каждый день ходить на работу,осталось не так много времени.Я не знаю,когда она будет закончена.Если все пойдет хорошо,я бы хотел поиграть еще в какую-нибудь игру двигатели, такие какEgret
,LayaAir
,Cocos Creator
Переделайте его, чтобы ознакомиться с использованием этих игровых движков, а затем напишите серию руководств...
Эй, похоже, война будет затяжной.