Как правильно перевести карту после масштабирования?

Я создаю камеру на холсте, как в Super Smash Bros, где центр камеры следует за центральной точкой всех игроков и масштабируется, чтобы охватить всех игроков.

Я настроил его для определения расстояния между двумя игроками, и если оно больше размера холста, масштаб камеры уменьшается, чтобы уменьшить размер блоков, спрайтов игроков и т. д.

ctx.scale(cameraS,cameraS);
ctx.translate(-(cameraX*cameraS)+(CANVAS_WIDTH/2),-(cameraY*cameraS)+(CANVAS_HEIGHT/2));

Это то, что масштабирует и перемещает нарисованные изображения в положение относительно экрана.

Это настоящая игра, использующая код, и, как вы можете заметить, масштабирование и перемещение изображений немного некорректны, но я не знаю, почему! https://dl.dropboxusercontent.com/u/51784213/Conjugate/index.html

Для справки, красная точка — это позиция по центру между обоими игроками. Линии показывают мертвую точку фактического холста. Когда масштабирование равно 1 (масштабирование вообще отсутствует), красная точка полностью центрирована, как и должно быть. Когда масштабирование начинает уменьшаться, красная точка начинает двигаться от центра в странных направлениях.

Чтобы код работал правильно, точка всегда должна находиться в центре, даже в процессе масштабирования!


person NinthWorld    schedule 09.05.2013    source источник


Ответы (1)


Преобразования применяются в обратном порядке; поэтому вы сначала переводите, а затем масштабируете. Это означает, что для точки (x, y) после текущего преобразования вы получите

( 
    (x + CANVAS_WIDTH/2 - cameraX*cameraS) * cameraS, 
    (y + CANVAS_HEIGHT/2 - cameraY*cameraS) * cameraS 
)

На самом деле здесь необходимо, чтобы холст был переведен в масштабе (cameraX, cameraY), а затем смещен на фактическое (CANVAS_WIDTH/2, CANVAS_HEIGHT/2), так что (cameraX, cameraY) находится в центре видимого холста.

Вернее, преобразование, необходимое здесь для точки (x, y), есть

( 
    (x - cameraX) * cameraS + CANVAS_WIDTH/2, 
    (y - cameraY) * cameraS + CANVAS_HEIGHT/2 
)

Таким образом, код становится, если вы решите сначала применить перевод,

ctx.scale(cameraS,cameraS);
ctx.translate(-cameraX+CANVAS_WIDTH/(2*cameraS),-cameraY+CANVAS_HEIGHT/(2*cameraS));

Или, если вы решите сначала применить масштабирование

ctx.translate(-cameraX*cameraS + CANVAS_WIDTH/2, -cameraY*cameraS + CANVAS_HEIGHT/2);
ctx.scale(cameraS, cameraS);

Рабочий JSFiddle.

person Rikonator    schedule 09.05.2013