Страницы

Поиск по вопросам

четверг, 9 января 2020 г.

Граница видимости и граница холста

#javascript #html #canvas


Такой вопрос: допустим у нас есть некоторая локация, в которой сможет передвигаться
игрок, она большая, но заранее известно, какие объекты в каких местах на ней находятся. 
Есть игрок, мы видим вокруг игрока в определенном радиусе, а то что за радиусом видимости
мы не видим.
Вопрос в том, как это реализовать на canvas.
До этого, как я раньше делал, все видимые объекты сразу же рисовались на видимом поле.
    


Ответы

Ответ 1



Простейший способ - считать bounding box объекта и перед отрисовкой проверять попал ли он на экран, попробуйте поиграть с количеством точек в этом примере, чтобы найти предел производительности Вашего компьютера, тогда можно будет понять как эта оптимизация влияет на производительность var width, height; var canvas = d3.select("canvas").call(d3.zoom().on("zoom", zoom)); resize(); var context = canvas.node().getContext("2d"); var randomX = d3.randomNormal(width / 2, 80); var randomY = d3.randomNormal(height / 2, 80); var data = d3.range(1e4).map(function() { return [randomX(), randomY()]; }); let r1 = 1; var transform = {x:0, y:0, k:1}; draw(); function zoom() { transform = d3.event.transform; context.save(); context.clearRect(0, 0, width, height); context.translate(transform.x, transform.y); context.scale(transform.k, transform.k); draw(); context.restore(); } function draw() { var i = -1, n = data.length, d, c=0; context.beginPath(); let rect = visibleRect(); context.beginPath() context.fillStyle = 'red'; while (++i < n) { d = data[i]; if (inScreen(d, rect)) { c++; context.moveTo(d[0], d[1]); context.arc(d[0], d[1], r1, 0, 2 * Math.PI); } } context.fill(); log.textContent = 'кругов нарисовано: ' + c + ', используйте drag и wheel' } function resize() { width = canvas.node().width = window.innerWidth; height = canvas.node().height = window.innerHeight-22; } function visibleRect() { let pad = 50; let x = transform.x-pad, y = transform.y-pad, k = transform.k, w = width-pad*2, h = height-pad*2; context.beginPath() context.fillStyle = 'rgba(0,0,0,0.1)'; context.rect(-x/k, -y/k, w/k, h/k); context.fill(); return [-x/k, -y/k, w/k-x/k, h/k-y/k] } function inScreen(d, r) { return d[0] > r[0]-r1 && d[1] > r[1]-r1 && d[0]
Недостаток такого подхода - перебор всех элементов, чтобы этого избежать придется использовать структуры данных - например квадродерево

Комментариев нет:

Отправить комментарий