0
votes

I'm creating a camera in canvas like the one in Super Smash Bros, where the center of the camera follows the center point of all players and scales to encompass all the players.

I have it set up to find the distance between the 2 players, and if it's larger than the canvas size, the camera scale lowers to decrease the size of the blocks, player sprites, etc.

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

These are what scale and move the drawn images to a position relative to the screen.

This is the actual game using the code and as you can tell, the scaling and moving of the images is slightly incorrect, but I'm not sure why! https://dl.dropboxusercontent.com/u/51784213/Conjugate/index.html

For reference, the red dot is the position centered between both players. The lines show the dead center of the actual canvas. When scaling is 1(no scaling at all), the red dot is completely centered as it should be. When the scaling starts to decrease, the red dot begins to move off center in weird directions.

For the code to be working correctly, the dot should be centered at all times, even during the scaling process!

1

1 Answers

0
votes

Transformations are applied in the reverse order; so you are first translating and then scaling. This means that for a point (x, y), after the current transformation, you get

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

What's actually needed here is the canvas be translated by scaled (cameraX, cameraY) and then be offset by actual (CANVAS_WIDTH/2, CANVAS_HEIGHT/2), so that (cameraX, cameraY) is at center of the visible canvas.

Or rather, the transformation needed here for a point (x, y) is

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

Hence, the code becomes, if you choose to apply translate first,

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

Or, if you choose to apply scaling first

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

Working JSFiddle.