Недавно на Хабре была статья про пятнашки на Canvas.
Отличная статья, уверен, новички найдут в ней много полезного. К сожалению, в комментариях высказались о немного завышеном потреблении процессора.
Это не от недостатка технологии, а от недостаточного опыта и удобных инструментов.
В этом топике я расскажу, как, при помощи LibCanvas, сделать эту игру совершенно нетребовательной к процессору и отлично выглядящей.
В игре по ссылке достаточно было исправить всего один нюанс — убрать ненужную перерисовку каждого кадра и вызывать её только при изменении холста.
Но мы пойдём дальше — введем анимацию передвижения фишек. Во время анимации при перерисовке всего холста мы будем иметь ту же проблему — неоправданно загруженный процессор, потому подумаем, что мы можем сделать.
Несложно заметить, что изображение меняется нечасто. Необходимо воспользоваться этим и, вместо того, чтобы перерисовывать весь холст — стираем при помощи clearRect старое месторасположение пятнашки и рисуем новое.
Нам достаточно зарисовать старую клетку и очистить новую (по сути, можно было бы постоянно сохранять предыдущее место отрисовки фишки, но это не так критично).
Итак, теперь у нас есть код перерисовки фишки. Допустим, раньше наше приложение перерисовывало каждый кадр. Код передвижения фишки выглядел приблизительно так:
Мы отключаем автоматическую перерисовку каждого кадра и добавляем код, который заставляет каждую фишку перерисовывать себя при движении:
Теперь каждый шаг будет вызываться перерисовка холста. Впринципе, этого вполне достаточно для вполне плавной анимации и практически свободного проца, но пойдём дальше.
Если проинспектировать приложение в консоли Javascript можно заметить, что самая значительная часть — это перерисовка холста, в которой вызываются такие тяжелые функции, как отрисовка градиента.
Для своего приложения можно грубо считать, что (program) == 'Бездействие системы'
Исправим это досадное недоразумение предварительной отрисовкой фишки в буфер. Создадим новый скрытый холст, отрисуем фишку в него и далее будем отрисовывать сам холст вместо вызова кучи тяжелых функций. Я для этого использую плагин atom.Class.Mutators.Generators — простой способ единожды сгенерировать объект и далее брать из кеша.
Допустим, раньше у нас был следующий код, который отрисовывал фишку:
Сменим его на следующий код:
Да, оно стало немного менее изящно, но, зато¸ мы достигли цели, отрисовка наших пятнашек очень быстра и совершенно нетребовательна к ресурсам:
До введения буфера
После введения буфера
Программируйте и наслаждайтесь результатом)
Отличная статья, уверен, новички найдут в ней много полезного. К сожалению, в комментариях высказались о немного завышеном потреблении процессора.
Это не от недостатка технологии, а от недостаточного опыта и удобных инструментов.
В этом топике я расскажу, как, при помощи LibCanvas, сделать эту игру совершенно нетребовательной к процессору и отлично выглядящей.
В игре по ссылке достаточно было исправить всего один нюанс — убрать ненужную перерисовку каждого кадра и вызывать её только при изменении холста.
Но мы пойдём дальше — введем анимацию передвижения фишек. Во время анимации при перерисовке всего холста мы будем иметь ту же проблему — неоправданно загруженный процессор, потому подумаем, что мы можем сделать.
Dirty Rectangles
Несложно заметить, что изображение меняется нечасто. Необходимо воспользоваться этим и, вместо того, чтобы перерисовывать весь холст — стираем при помощи clearRect старое месторасположение пятнашки и рисуем новое.
Нам достаточно зарисовать старую клетку и очистить новую (по сути, можно было бы постоянно сохранять предыдущее место отрисовки фишки, но это не так критично).
var Tile = atom.Class({
[...]
redraw: function () {
this.libcanvas.ctx
.clearRect( this.lastPositionRectangle )
.clearRect( this.field.emptyRectangle );
this.draw()
},
[...]
})
Итак, теперь у нас есть код перерисовки фишки. Допустим, раньше наше приложение перерисовывало каждый кадр. Код передвижения фишки выглядел приблизительно так:
var Tile = atom.Class({
[...]
move: function (point) {
// Блокируем поле, чтобы, пока не закончится передвижение, никто не двигал фишки
this.field.blocked = true;
this.animate({
time: 150,
props: { x: point.x, y: point.y },
onFinish: function () {
// Разблокируем поле
this.field.blocked = false;
},
fn: 'sine-out'
});
},
[...]
})
Мы отключаем автоматическую перерисовку каждого кадра и добавляем код, который заставляет каждую фишку перерисовывать себя при движении:
var Tile = atom.Class({
[...]
move: function (point) {
// Блокируем поле, чтобы, пока не закончится передвижение, никто не двигал фишки
this.field.blocked = true;
this.animate({
time: 150,
props: { x: point.x, y: point.y },
onProccess: this.redraw.bind(this),
onFinish: function () {
// Разблокируем поле
this.field.blocked = false;
this.redraw();
},
fn: 'sine-out'
});
},
[...]
})
Теперь каждый шаг будет вызываться перерисовка холста. Впринципе, этого вполне достаточно для вполне плавной анимации и практически свободного проца, но пойдём дальше.
Буферизация
Если проинспектировать приложение в консоли Javascript можно заметить, что самая значительная часть — это перерисовка холста, в которой вызываются такие тяжелые функции, как отрисовка градиента.
Для своего приложения можно грубо считать, что (program) == 'Бездействие системы'
Исправим это досадное недоразумение предварительной отрисовкой фишки в буфер. Создадим новый скрытый холст, отрисуем фишку в него и далее будем отрисовывать сам холст вместо вызова кучи тяжелых функций. Я для этого использую плагин atom.Class.Mutators.Generators — простой способ единожды сгенерировать объект и далее брать из кеша.
Допустим, раньше у нас был следующий код, который отрисовывал фишку:
var Tile = atom.Class({
[...]
draw: function () {
this.callHardDrawFunctions( this.libcanvas.ctx );
}
[...]
})
Сменим его на следующий код:
var Tile = atom.Class({
[...]
Generators: {
buffer: function () {
var buffer = LibCanvas.buffer( this.shape, true );
this.callHardDrawFunctions( buffer.ctx );
return buffer;
}
},
draw: function () {
this.libcanvas.ctx.drawImage({
image: this.buffer,
draw : this.shape
});
}
[...]
})
Да, оно стало немного менее изящно, но, зато¸ мы достигли цели, отрисовка наших пятнашек очень быстра и совершенно нетребовательна к ресурсам:
До введения буфера
После введения буфера
Заключение
Программируйте и наслаждайтесь результатом)