I've been working on porting an old closed source game to Javascript with Canvas and I've come to a slight problem.
Right now, to display the land, I just have a pretty basic loop that just draws the 44px by 44px diamond-shaped tiles using ctx.drawImage()
.
It essentially looks like the left side of the image, while I need them to "stretch" to fill the entire tile (like on the right). The tiles have a Z axis which is just in the +j direction on the screen and it's supposed to look like a hill or incline.
Anyway, this leads to my question: Is there a way to correctly do this without using webgl? If not: would it be better to use webgl directly to do this, or use a library to handle it for me?
EDIT 2: Well, after thinking for a while, I remembered that affine transformations are only linear (duh), so I won't be able to use certain transformations like transforming corner tiles... so I guess I can use the transformation matrices for the "light green" tiles, but not the pink tile in this example.
EDIT: With Phillips answer, I was able to create a few matrices to apply an affine transformation to the tile. However, I pretty much did "guess and check" to calculate the values for only one Z-value, but I can't seem to create a general form of it.
I'm guessing for different angles (like when there is an incline going from east->west, west->east, north->south, south->north), I will have to use a ton of if-statements for each scenario, but that's not much of a big deal.
I have the JSFiddle here: http://jsfiddle.net/awwPP/1/
<script>
window.onload = function(e) {
multiply = function(a, b) {
return [a[0]*b[0] + a[1]*b[2],
a[0]*b[1] + a[1]*b[3],
a[2]*b[0]+a[3]*b[2],
a[2]*b[1]+a[3]*b[3]];
};
multiplyAll = function() {
var result = arguments[0];
for(var i = 1; i < arguments.length; i++) {
result = multiply(result, arguments[i]);
}
return result;
};
drawDiamond = function(ctx, x, y) {
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x+22, y+22);
ctx.lineTo(x, y+44);
ctx.lineTo(x-22, y+22);
ctx.lineTo(x, y);
ctx.stroke();
ctx.fill();
};
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var z = 2 * 3; // each z is like 2px up
ctx.mozImageSmoothingEnabled = false;
ctx.fillStyle = 'rgba(50, 50, 50, 0.5)';
ctx.strokeStyle = 'rgba(255, 50, 50, 0.5)';
//left:
drawDiamond(ctx, 44, 22);
drawDiamond(ctx, 66, 44);
drawDiamond(ctx, 88, 66);
var cos = Math.cos(Math.PI/4);
var sin = Math.sin(Math.PI/4);
// just negate
var nCos = Math.cos(-Math.PI/4);
var nSin = Math.sin(-Math.PI/4);
var result = multiplyAll(
//rotate it so the tile is a square:
[cos, sin,
-sin, cos],
// scale the x axis (although it's actually the Y)
// to make it look longer
[50/44, 0,
0, 1],
// scew the opposite axis by factor K
[1, -0.12,
0, 1],
//negate the rotation
[nCos, nSin,
-nSin, nCos]);
ctx.setTransform(result[0], result[1],
result[2], result[3],
//dunno why there is an x/y offset
0, 10);
//middle:
drawDiamond(ctx, 66, 0 - z);
drawDiamond(ctx, 88, 22 - z);
drawDiamond(ctx, 110, 44 - z);
//right:
ctx.setTransform(1, 0,
0, 1,
0, 0);
drawDiamond(ctx, 88, -22 - z);
drawDiamond(ctx, 110, 0 - z);
drawDiamond(ctx, 132, 22 - z);
}
</script>
<canvas id="c" width="200" height="200"></canvas>