Reputation: 3613
I'm trying to do an isometric projection in HTML5 and the closest I can get is by scaling and rotating the viewport
window.addEventListener('DOMContentLoaded', (event) => {
class Point {
constructor() {
this.x = 0;
this.y = 0;
}
}
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function tick(time) {
ctx.save();
ctx.translate(250,0);
ctx.scale(1, 0.5);
ctx.rotate(45 * Math.PI /180);
let p = new Point();
p.x = 4*32;
p.y = 2*32;
ctx.fillStyle = 'green';
ctx.fillRect(p.x,p.y,32,32);
for (var x = 0; x < 10; ++x) {
for (var y = 0; y < 10; ++y) {
ctx.strokeStyle = 'black';
ctx.strokeRect(x*32, y*32, 32, 32);
}
}
ctx.restore();
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
});
And it does work..but this isn't a practical solution because then when I try to draw isometric sprites within that scaled and rotated view, it looks really distorted. So I'd rather not go that route unless I can get it to work without distorting my sprites.
I also tried this website https://gamedevelopment.tutsplus.com/tutorials/creating-isometric-worlds-primer-for-game-developers-updated--cms-28392
Which provided an equation for generating isometric grids. I used their cartesianToIsometric function to try and make an iso grid
window.addEventListener('DOMContentLoaded', (event) => {
class Point {
constructor() {
this.x = 0;
this.y = 0;
}
}
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function cartesianToIsometric(cartPt) {
var tempPt = new Point();
tempPt.x = cartPt.x - cartPt.y;
tempPt.y = (cartPt.x + cartPt.y) / 2;
return (tempPt);
}
function tick(time) {
for (var x = 0; x < 50; ++x) {
for (var y = 0; y < 50; ++y) {
let p = new Point();
p.x = x * 32;
p.y = y * 32;
let iso = cartesianToIsometric(p);
ctx.strokeStyle = 'black';
ctx.strokeRect(iso.x, iso.y, 32, 32);
}
}
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
});
but it still looked wrong Unless I rotate or scale the viewport to correct it.
So my question is..how can I draw an isometric grid without scaling and rotating my viewport(if possible)
If I have to scale my viewport like the first example, how can I do it without distorting my sprites.... Sorry if this question is confusing to read my knowledge on this is iffy..
Here's my html file
index.html
<html>
<head>
<script src="index.js"></script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>
Upvotes: 2
Views: 1880
Reputation: 354
Looks like you are so close to the solution but a little bit confused. Let me explain:
Normally, you don't have to rotate and scale your canvas viewport. This is something you do when you create your isometric sprites. You should already have some isometric sprites and all you have to do just to put them in correct isometric coordinates.
Your second approach will do exactly what I mean, calculating the isometric points by using cartesian coordinates. It should work, no need to draw rectangles just place the images on the isometric coordinates.
The only trick here you should place your isometric sprites from their bottom center points:
for (var x = 0; x < 50; ++x) {
for (var y = 0; y < 50; ++y) {
let p = new Point();
p.x = x * 32;
p.y = y * 32;
let iso = cartesianToIsometric(p);
// Apply offset to place each isometric image from its bottom center.
// The default pivot point (top left) won't do good
// because we need to stack them up according to their heights.
let offset = {x: floorImageWidth/2, y: floorImageHeight}
ctx.drawImage(floor, iso.x - offset.x, iso.y - offset.y);
}
}
I also suggest using a separate function to draw iso points (not the rectangles) so that you can debug your positions:
let debug = true;
function debugDraw(time) {
for (var x = 0; x < 50; ++x) {
for (var y = 0; y < 50; ++y) {
let p = new Point();
p.x = x * tileWidth;
p.y = y * tileWidth;
let iso = cartesianToIsometric(p);
// draw pivot point for each tile
ctx.fillStyle = 'yellow';
ctx.fillRect(iso.x - 5, iso.y - 5, 10, 10);
}
}
}
if(debug){
requestAnimationFrame(debugDraw)
}
Plus, here is a working demo for you to experiment further: https://codepen.io/justintc/pen/eYpMabx
Hope it helps, cheers!
Upvotes: 1