Комментарии 61
А демо?
+2
дак скачать можно
-1
Ссылка в конце статьи, там архив. Распаковываем и пробуем.
0
Карту каждый кадр перерисовываете или только объекты?
0
Каждый кадр.
0
Карту имело смысл отрисовать один раз в отдельном слое или в буфер. Скорость была бы вполне приемлимая.
0
Я специально этого не сделал. Придется иметь дело с системами частиц, а с ними такие трюки не сработают.
Тест он и есть тест.
Тест он и есть тест.
0
ЭЭ. С какими системами частиц? Вы могли карту кешировать в буфере и отрисовывать её однажны как картинку. Было бы вполне производительно.
0
Интересно, как тогда реализовать, например, реакцию на наведение курсора на объект. Мельница имеет сложный контур и простая прямоугольная область не очень подходит. Рисовать для каждого объекта его приблизительный контур и смотреть внутри него через isPointInPath?
0
Почему интервал 1000/16? Перерисовка происходит постоянно? Тормозить не будет на слабеньких машинах?
0
В нете находил, что критическая отметка ниже 15 (1000/60). После нее начинается разброд в браузерах по выполнению Интервала. В статьях, как заметил, чаще используется 60. В принципе значение можно варьировать и подгонять скорость анимации через speed параметр.
0
Просто 16 fps — вообще нестандартно как-то. Можно было воспользоваться requestAnimationFrame — это было бы идеальное решение.
0
Меня смутило, что requestAnimationFrame еще находится в доработке.
0
Для мультипликации и аниме стандарт вроде бы вообще 14 кадров в секунду…
0
А можно пруф? Не вижу смысла особого, просто.
0
Наверное, все слышали про 25 кадров в секунду (этого достаточно для кинематографа). Но аниме раньше рисовали вручную, например, карандашами. Чем меньше кадров в секунду — тем меньше рисунков, очевидно.
Кусок текста с одного из случайных сайтов:
Возможно, я и ошибаюсь.
Кусок текста с одного из случайных сайтов:
С технической точки зрения "Акира" для конца 1980-х был настоящим аниме-совершенством. Это было первое аниме с частотой 24 кадра в секунду (промышленный аниме-стандарт - 12-15 кадров в секунду).
Возможно, я и ошибаюсь.
0
Конечно слышал. В кинематографе применяется приблизительно 24(PAL) или 30(NTSC) fps. Также есть 25 fps, 29,970 и т.д. (в кинематографе на самом деле со стандартами даже хуже, чем в браузерах). Раньше использовалось 18 или 12 кадров в секунду.
Я просто не понимаю смысла в 14/16 fps)
Они даже непропорциональны ни одному из существующих стандартов)
Я просто не понимаю смысла в 14/16 fps)
Они даже непропорциональны ни одному из существующих стандартов)
0
Уже давно мультипликацию делают в 3D пакетах, например южный парк делаю в Maya, и вот зачем им 14 кадров?
0
Те, кто делает анимацию в Maya, могут позволить себе делать и 60, и 120 кадров в секунду. А те, кто по-старинке рисует карандашом или кистями, не могут себе такую роскошь позволить.
15 кадров в секунду — это половина от 30 кадров для NTSC, 12 — половина от PAL.
И верно, я погорячился. 14 fps незачем.
15 кадров в секунду — это половина от 30 кадров для NTSC, 12 — половина от PAL.
И верно, я погорячился. 14 fps незачем.
0
Имхо на глаз у них 10 FPS + keyframe анимация. Южный парк не пример гладкости отображения :)
0
Если судить по играм, то 13-15 кадров вполне хватает для ощущения плавности.
0
У меня подобные анимации есть в LibCanvas. Они используются в Asteroids для анимации взрыва, огня и корабля.
Корабль анимируется вообще просто. Так инициируется анимация:
А так отрисовывается корабль:
Анимация корабля создаётся приблизительно так:
Потом она используется как-то так:
Аналогично сделана анимация взрыва, при этом, при окончании анимации — элемент удаляется, чтобы мог быть убран сборщиком мусора
Корабль анимируется вообще просто. Так инициируется анимация:
this.animation = new Animation()
.addSprites(this.libcanvas.getImage('ship'), 60)
.run({
line : Array.range(0,8),
delay: 40,
loop : true
});
А так отрисовывается корабль:
draw: function () {
if (this.hidden) return;
this.drawEngines();
this.libcanvas.ctx.drawImage({
image : this.animation.getSprite(),
center: this.position,
angle : this.angle + (90).degree()
});
},
Анимация корабля создаётся приблизительно так:
var image = this.libcanvas.getImage('fire');
return new LibCanvas.Animation()
.addSprites({
small : image.sprite( 0, 0, 20, 140),
med1 : image.sprite( 20, 0, 20, 140),
med2 : image.sprite( 40, 0, 20, 140),
med3 : image.sprite( 60, 0, 20, 140),
big1 : image.sprite( 80, 0, 20, 140),
big2 : image.sprite(100, 0, 20, 140),
big3 : image.sprite(120, 0, 20, 140)
})
.add({
name : 'start',
line: ['small', 'small', 'med1', 'med2'],
delay: 40
})
.add({
name : 'moving',
loop : true, // Анимация зацикливается и меняется до ручной остановки
line : ['big1', 'big2', 'big3'],
delay : 40
})
.add({
name : 'end',
line: ['med2', 'med1', 'small', 'small'],
delay: 40
});
Потом она используется как-то так:
onMoveStart: function () {
this.fireAnimation
.stop(true)
.run('start')
.run('moving');
},
onMoveStop: function () {
this.fireAnimation
.stop(true)
.run('end');
}
Аналогично сделана анимация взрыва, при этом, при окончании анимации — элемент удаляется, чтобы мог быть убран сборщиком мусора
this.animation = new Animation()
.addSprites(this.libcanvas.getImage('explosion'), 162)
.run({
delay: 40,
line : Array.range(0, 9)
})
.addEvent('stop', function () {
this
.stopDrawing()
.fireEvent('stop');
}.bind(this))
+3
Вместо «Анимация корабля создаётся приблизительно так» необходимо читать «Анимация огня создаётся приблизительно так:»
0
если в drawImage передать Animation — оно само перерисовываться будет, или оно мне только текущий активный спрайт выдаст? А вызывать с нужным( и не известным мне) интервалом — моя забота?
0
При чём тут интервал? Вы вообще про интервалы не думаете. Если ваш объект необходимо перерисовать — у него вызывается мeтод
Подключаем такой файл и у нас есть анимация взрыва:
draw
. drawImage
— это тот же метод .getContext('2d').drawImage
, но с возможностью задавать именованные параметры, а также вращать изображение. Минимальный код выглядит как-то так:var Explosion = atom.Class({
Extends : Drawable,
position : null,
animation: null,
initialize : function (position, image) {
this.position = position;
this.animation = new Animation()
.addSprites(image, 162)
.run({
delay: 40,
line : Array.range(0, 9)
});
},
draw : function () {
this.libcanvas.ctx.drawImage({
image : this.animation.getSprite(),
center: this.position
});
}
});
Подключаем такой файл и у нас есть анимация взрыва:
0
Ну прости меня конечно, но как я узнаю что обьект надо перерисовать, если он даже сам явно не знает когда у него спрайт обновляется.
Или ты противоречишь своим же подколкам и перерисовываешь всю сцену?
Или ты противоречишь своим же подколкам и перерисовываешь всю сцену?
0
По ссылке на подколки, а простое любопытство.
Иногда — перерисовываю всю сцену, иногда раскладываю на слои и перерисовываю только нужный слой, иногда — стираю старый объект и рисую новый.
В частности в Asteroids нету смысла что-то оптимизировать в этом плане — абсолютно все объекты игры — динамические, изменяются каждый кадр и просчитывать изменившиеся участки — бесполезно, изменилось всё, что есть на экране.
Если у нас только есть какая-либо анимация и есть возможность изменять только один объект, то можно прицепится к событию смены кадра (например, у нас есть пятнашки, где каждая пятнашка — драгоценный камень, который сверкает раз в 3 секунды):
Класс Animation вообще не должен знать ни про обновление холста, ни про того, кто его вызывает. Он должен получать список кадров, выводить нужные анимации и дергать привязанные события.
Иногда — перерисовываю всю сцену, иногда раскладываю на слои и перерисовываю только нужный слой, иногда — стираю старый объект и рисую новый.
В частности в Asteroids нету смысла что-то оптимизировать в этом плане — абсолютно все объекты игры — динамические, изменяются каждый кадр и просчитывать изменившиеся участки — бесполезно, изменилось всё, что есть на экране.
Если у нас только есть какая-либо анимация и есть возможность изменять только один объект, то можно прицепится к событию смены кадра (например, у нас есть пятнашки, где каждая пятнашка — драгоценный камень, который сверкает раз в 3 секунды):
var MyObject = atom.Class({
[...],
initialize : function () {
this.animation = new Animation()
[...]
.addEvent( 'changed', this.redraw.bind(this) );
},
redraw: function () {
this.clear().draw();
},
draw : function () {
this.libcanvas.ctx.drawImage(
this.animation.getSprite(),
this.shape
);
}
});
Класс Animation вообще не должен знать ни про обновление холста, ни про того, кто его вызывает. Он должен получать список кадров, выводить нужные анимации и дергать привязанные события.
0
Умная чтука у тебя, осталось прикрутить на это нормальный SceneGraph и клипинг
0
Можете помочь, если есть желание)
0
А тебе лучше помогу создав конкуренцию :)
0
А есть наработки уже, посмотреть чо?
0
Пока нет, иначально была немного другая ниша, только недели две назад начал собирать по сусекам нужные куски, скажем так, «из твоей области»
Подвигли на это дело, как не странно, твои танки
Но автомагия SceneGraph это было первое что начал портировать их запасов бытности геймдевелопером.
Подвигли на это дело, как не странно, твои танки
Но автомагия SceneGraph это было первое что начал портировать их запасов бытности геймдевелопером.
0
Именно танки — не мои, а форк)
В чём суть SceneGraph? Нету ли смысла объединиться, тем более, я так понял, у нас наработки из разных областей. ОпенСорс сообществу лучше держаться вместе, а не врозь.
В чём суть SceneGraph? Нету ли смысла объединиться, тем более, я так понял, у нас наработки из разных областей. ОпенСорс сообществу лучше держаться вместе, а не врозь.
+1
SceneGraph это в общем случае обычное дерево, хотя может иметь и циклы.
Его задача правильно отрисовать сцену.
Тут подразумевается и порядок объектов и отработка скрытых поверхностей(pbuffer в смысле), в случае WebGL еще и выбор оптимального порядка наложение шейдеров\данных чтобы DIP не словить.
В случае с 2д канвасом это по сути — эмулятор Z индекса и проверка пересечения.
В частности если у тебя GUI на канвасе — один из узлов задает клип рест чтобы дети за его пределы не вылазили( или нинзя трик — предоставляет детям другой канвас, а на фронт кидает только нужную область, скролинг говорит спасибо)
Одновременно по этой структуре можно определяет что нужно обновить когда что-то другое обновилось.
Тоесть если твои астероиды запустились на 60FPS, а скорость движения астероида — 10 пикселей в секунду — его можно перерисовывать не каждый раз, а только 1\6 кадр( ну ладно 1\12, алиасинг ).
Ну или если два астероида перекрываются, и только у одного меняется спрайт — перерисовать оба.
В общем та хреновина через которую ты читаешь данный текст так и работает. Особо хорошо видно в MozAfterPaint :)
Остаются проблемы вроде что «академическому» графу на клиенте делать нечего, и те моменты что 90% различных «чтук» делаются через различные фейки.
В том плане что быстрее нарисовать, чем понять что рисовать не надо.
А с объединением пока не смогу — двое детей, работа с 8ми до 20 и тройка собственных проектов которые надо закончить.
Его задача правильно отрисовать сцену.
Тут подразумевается и порядок объектов и отработка скрытых поверхностей(pbuffer в смысле), в случае WebGL еще и выбор оптимального порядка наложение шейдеров\данных чтобы DIP не словить.
В случае с 2д канвасом это по сути — эмулятор Z индекса и проверка пересечения.
В частности если у тебя GUI на канвасе — один из узлов задает клип рест чтобы дети за его пределы не вылазили( или нинзя трик — предоставляет детям другой канвас, а на фронт кидает только нужную область, скролинг говорит спасибо)
Одновременно по этой структуре можно определяет что нужно обновить когда что-то другое обновилось.
Тоесть если твои астероиды запустились на 60FPS, а скорость движения астероида — 10 пикселей в секунду — его можно перерисовывать не каждый раз, а только 1\6 кадр( ну ладно 1\12, алиасинг ).
Ну или если два астероида перекрываются, и только у одного меняется спрайт — перерисовать оба.
В общем та хреновина через которую ты читаешь данный текст так и работает. Особо хорошо видно в MozAfterPaint :)
Остаются проблемы вроде что «академическому» графу на клиенте делать нечего, и те моменты что 90% различных «чтук» делаются через различные фейки.
В том плане что быстрее нарисовать, чем понять что рисовать не надо.
А с объединением пока не смогу — двое детей, работа с 8ми до 20 и тройка собственных проектов которые надо закончить.
0
Понятно.
А разве не будет дёрганно? А как определить, когда можно его запустить медленнее, а когда — нет?
Тут есть проблема. Например, у нас ректангл с толстой границей. Или, даже, не ректангл, а путь, состоящий из arc, curve и т.п.. Плюс ещё с толстой границей, скажем strokeWidth = 30px. Как определить Rectangle, внутри которого этот путь находится, чтобы не обрезать ничего лишнего? Я думал делать подобное, но так и не придумал вменяемого решения вышеназванных проблем. Решил, что будет лучше оставить это на совести приложения (как в случае с пятнашками).
Ну а остальное у меня есть, да.
Тоесть если твои астероиды запустились на 60FPS, а скорость движения астероида — 10 пикселей в секунду — его можно перерисовывать не каждый раз, а только 1\6 кадр( ну ладно 1\12, алиасинг ).
А разве не будет дёрганно? А как определить, когда можно его запустить медленнее, а когда — нет?
дин из узлов задает клип рест чтобы дети за его пределы не вылазили
Тут есть проблема. Например, у нас ректангл с толстой границей. Или, даже, не ректангл, а путь, состоящий из arc, curve и т.п.. Плюс ещё с толстой границей, скажем strokeWidth = 30px. Как определить Rectangle, внутри которого этот путь находится, чтобы не обрезать ничего лишнего? Я думал делать подобное, но так и не придумал вменяемого решения вышеназванных проблем. Решил, что будет лучше оставить это на совести приложения (как в случае с пятнашками).
Ну а остальное у меня есть, да.
+1
сори, забыл ответить
Для начала вычисляешь активный bound зоны, создаешь канвас нужных размеров и рисует там внутренности.
Потом в отдельном канвасе рисуешь внешнюю фигуру, например чисто белым цветом.
Потом на нее накладываешь данные из первого канваса с композитом and.
Потом конечную «обрезанную» перекидываешь куда надо.
Таким макаром можно управлять не только обрезкой по внешнему контуру, но и «выжигать» дырки или накладывать градиенты прозрачности.
Для начала вычисляешь активный bound зоны, создаешь канвас нужных размеров и рисует там внутренности.
Потом в отдельном канвасе рисуешь внешнюю фигуру, например чисто белым цветом.
Потом на нее накладываешь данные из первого канваса с композитом and.
Потом конечную «обрезанную» перекидываешь куда надо.
Таким макаром можно управлять не только обрезкой по внешнему контуру, но и «выжигать» дырки или накладывать градиенты прозрачности.
0
А можно подробнее про танчики?
0
Меня пригласил ognevsky, показал такой скрин и предложил присоединиться к ним:
Я посмотрел, счёл проект интересным и предложил переписать клиентскую часть на LibCanvas, на что получил согласие.
За несколько часов я полностью перевёл клиент на LibCanvas с временной графикой из Asteroids:
Основной идеолог был недоволен и отказался использовать смерджить мой форк.
В итоге я решил делать свою игру на node.js+LibCanvas, другого жанра, экшн.
А BattleField, как это обычно бывает с такими проектами — скоропостижно загнулся
Первая публичная альфа-версия моей игры (она open-source) планируется где-то летом. Если есть желание присоединиться — welcome.
Я посмотрел, счёл проект интересным и предложил переписать клиентскую часть на LibCanvas, на что получил согласие.
За несколько часов я полностью перевёл клиент на LibCanvas с временной графикой из Asteroids:
Основной идеолог был недоволен и отказался использовать смерджить мой форк.
В итоге я решил делать свою игру на node.js+LibCanvas, другого жанра, экшн.
А BattleField, как это обычно бывает с такими проектами — скоропостижно загнулся
Первая публичная альфа-версия моей игры (она open-source) планируется где-то летом. Если есть желание присоединиться — welcome.
+4
404 :(
0
Canvas не такой медленный, как кажется на первый взгляд ;)
0
Немного потестил ваши шарики.
Chrome 11, Core 2Duo 2.66Ггц, 4Гб RAM, GeForce 9400 256:
Что 100, что 500, что 1000 — разницы нет, тормозов тоже. Дальше тысячи ждать уже не хотелось (:
[889, 9063, 20: 217, 1004]
Скриншот
HTC Hero, CM7, 2.3.3, родной браузер:
По-моему, одинаково тормозит и с двумя шариками и с сотней. C сотней чууть медленнее цифры меняются.
[223, 5116, 2: 103, 100]
В общем, canvas с анимацией одной тысячи простых объектов справляется прекрасно
Chrome 11, Core 2Duo 2.66Ггц, 4Гб RAM, GeForce 9400 256:
Что 100, что 500, что 1000 — разницы нет, тормозов тоже. Дальше тысячи ждать уже не хотелось (:
[889, 9063, 20: 217, 1004]
Скриншот
HTC Hero, CM7, 2.3.3, родной браузер:
По-моему, одинаково тормозит и с двумя шариками и с сотней. C сотней чууть медленнее цифры меняются.
[223, 5116, 2: 103, 100]
В общем, canvas с анимацией одной тысячи простых объектов справляется прекрасно
0
Очень интересные вещи вы творите, давно слежу за вашим фреймворком, сейчас потихоньку вчитываюсь в документацию.
Но, серьезно заняться чем-либо времени нету. Итак 2 больших проекта веду, семья уже забыла как я выгляжу.
Но, серьезно заняться чем-либо времени нету. Итак 2 больших проекта веду, семья уже забыла как я выгляжу.
+1
Интересно как реализован алгоритм слоев, ведь перерисовываем сцену каждый раз заново? Или слои это части сцены, а не лежащие друг на друге объекты?
0
Несколько элементов Canvas, ничего особого) Как выше уже сказал — зависит от приложения. Могу и перерисовывать сцену, а могу перерисовывать только изменившиеся части, как в пятнашках. Из всех примеров на libcanvas.github.com/ ни один не использует слои на полную. У меня есть два проекта в разработке, где слоёв много и активно используются.
0
Несколько Canvas заинтересовало, когда смотрел принцип работы этой игрушки. В ихсоднике две канвы и они постоянно меняются. Т.е. отрисовка происходит в скрытой и по окончании происходит смена. Прям как doom с его 4 видео страницами.
0
НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Анимация и Canvas