ctx.clearRect спрайт холста

Мне интересно, как я могу изменить свой Javascript, чтобы очистить только падающие спрайты, а не весь холст (как сейчас).

Я надеюсь разместить на холсте несколько других (анимированных) спрайтов, которые не будут отображаться в соответствии со структурой моего function animate.

Есть ли способ, чтобы, если бы на холсте было другое изображение/спрайт, на него не повлиял бы function animate.

Я думаю, что эту строку нужно изменить:

ctx.clearRect(0, 0, canvas.width, canvas.height);

Хотя я понятия не имею, какие параметры мне нужно было бы разместить внутри. Падающие спрайты рисуются с размером 60x60, но когда они падают вниз, я немного застрял с очисткой единственного пути спрайта.

Любая помощь будет оценена по достоинству :)

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d");
canvas.width = 1408;
canvas.height = 640; 
canvasWidth = canvas.width;
canvasHeight = canvas.height;

var orangeEnemy = new Image();
orangeEnemy.src = "http://www.catholicsun.org/wp-content/uploads/2016/09/cropped-sun-favicon-512x512-270x270.png";
var yellowEnemy = new Image();
yellowEnemy.src = "http://www.clker.com/cliparts/o/S/R/S/h/9/transparent-red-circle-hi.png";

var srcX;
var srcY;
var enemySpeed = 2.75;
var images = [orangeEnemy, yellowEnemy];
var spawnLineY=-50;
var spawnRate=2500;
var spawnRateOfDescent=1.50;
var lastSpawn=-1;
var objects=[];
var startTime=Date.now();
animate();


    function spawnRandomObject() {
        var object = {
                x: Math.random() * (canvas.width - 15),
                y: spawnLineY,
                image: images[Math.floor(Math.random() * images.length)]
            }
        objects.push(object);
    }

    function animate(){
        var time=Date.now();
        if(time>(lastSpawn+spawnRate)){
            lastSpawn=time;
            spawnRandomObject();
        }

        requestAnimationFrame(animate);
        ctx.clearRect(0, 0, canvas.width, canvas.height);


        // move each object down the canvas
        for(var i=0;i<objects.length;i++){
            var object=objects[i];
            object.y += enemySpeed;
            ctx.drawImage(object.image, object.x, object.y, 60, 60);

        }

    }
<html>
<canvas id="canvas" style="border:3px solid"></canvas>
</html>


person LFJ__    schedule 03.07.2017    source источник


Ответы (2)


Самый простой и быстрый способ — наложить другой холст, специально для ваших спрайтов, поверх текущего холста (требуется немного CSS). Поместите все свои спрайты в один, все остальное в другой. Затем функция clearRect() в вашей функции animate() будет применяться только к холсту вашего спрайта, а не к другому.

В противном случае вам придется отслеживать позиции спрайтов и очищать каждый программно с помощью прямоугольников 60x60, используя clearRect(offsetX, offsetY, 60, 60).

P.S. извините за неформатированный ответ ... все еще выясняя ТАК

person duncan smith    schedule 03.07.2017
comment
Эй, спасибо за ваше предложение. Я думал о втором холсте, но не был полностью уверен, как он будет работать в контексте игры на холсте, которую мне нужно сделать. Я следил за тем, как нарисовать второй холст в стеке, который показал образец CSS (выравнивания и т. д.), и мой тестовый холст работает хорошо. Мне даже удалось заставить работать столкновение, чего я не был уверен с двумя холстами (вы можете сказать, что я не очень хорошо знаю JS!) В любом случае, спасибо за вашу помощь! - person LFJ__; 04.07.2017

Очистите один раз для производительности.

Гораздо лучше очистить весь холст и перерисовать спрайты. Используя предыдущую позицию, проверяя наложение, а затем очищая каждый спрайт по очереди, чтобы убедиться, что вы не очищаете существующий спрайт, потребуется гораздо больше циклов ЦП, чем однократная очистка экрана.

Функция очистки экрана работает очень быстро и выполняется на аппаратном уровне. Ниже приведены результаты теста производительности в Firefox (в настоящее время самый быстрый рендерер) очистки 65 000 пикселей с использованием всего одного вызова для всей области, затем 4 вызовов каждый квартал, затем 16 называет каждую поляну 16-м. (мкс составляет 1/1 000 000 секунды)

Each test clears 256*256 pixels Each sample is 100 tests
'Clear 1/1' Mean time: 213µs ±4µs 1396 samples
'Clear 4/4' Mean time: 1235µs ±14µs 1390 samples     
'Clear 16/16' Mean time: 4507µs ±42µs 1405 samples

Как видите, очистку 65 000 пикселей лучше всего выполнять за один вызов, при этом фактический вызов javascript добавляет около 100 мкс.

В Firefox количество очищаемых пикселей не влияет на время выполнения вызова clearRect, при этом вызовы clearRect(0,0,256,256) и clearRect(0,0,16,16) занимают ~2 мкс.

Помимо скорости, попытка очистки перекрывающихся анимированных спрайтов на спрайт становится чрезвычайно сложной и может привести к сотням вызовов очистки всего с дюжиной спрайтов. Это происходит из-за перекрытия.

person Blindman67    schedule 03.07.2017
comment
Некоторые интересные расчеты там; спасибо за их объяснение. Вы подтверждаете, насколько сложно было бы четко выпрямлять и перерисовывать движущиеся элементы! Я просто создал второй холст, чтобы можно было анимировать отдельный спрайт. - person LFJ__; 04.07.2017