The wonders of Isometric creations

I have always been very intrigued about the great looks and illusions of dept that Isometric illiustrations and isometric games can give. So much that I finally decided to give it a shot and try it out.
It kind of reminded me of the time I took the apprenticeship of carpentry – I had to learn some constructional drawing skills. Dots and lines, drawn across a paper could suddently make a figure pop out in 3D. The complex simplicity is similar when making Isometric art.

isometric grid

I started out creating a grid like the one above, adding dioginal lines in 30° and -30°, and a vertical line in the intersection between the two. Then I simply mulitipled them to fill the sheet. (I used illustrator). There is a lot of ways to do this, you could also use one of the examples here.

A couple of hours later playing in illustrator, I managed to create the following piece (remake of some inspiration I found on Pinterest):

isometric drawing on grid

I thought it was a great experience, but I really wanted to make isometric art faster – and found this awesome tool: Marmorset Hexels 2. I downloaded the trial and jumped straight in and created the following three pieces:

isometric experiments 01 isometric experiments 01 isometric experiments 03

I did these 3 in a little over 1 hour a piece, and I was so amazed that I bought Hexels2 straight away. Just by using simple shades, the illusion of dept was emminent, and anyone I showed this could easily see the depth.

I still felt like there was more to isometric creation that needed to be explored. Details are missing from this way of making isometric art in Hexels2, so I decided to bring it to a pixel-level.

I went into Photoshop and created the following tiles ( inspired roughly from this illustration ) and saved them all to transparent pngs.

forest swamp tiles

Now with some javascript I was able to build a map (javascript array) and placed the tiles accordingly to the array in a html5 canvas element:

simple tilemap with a small island in the middle

My map array for this image looks like this

[[2,2,2,2,2,2,2,1,1,1,1,1,1,1,9,1,1,1,1,1,1,1,1,1,1],
[2,2,2,2,2,2,1,1,1,6,6,1,1,1,1,1,0,1,5,8,1,1,1,1,1],
[2,2,2,2,2,1,1,1,1,1,5,1,1,1,0,1,1,1,1,1,6,1,1,1,1],
[2,2,2,2,1,1,1,7,1,1,1,1,1,2,2,2,2,2,1,1,1,9,7,1,1],
[2,2,2,1,1,5,1,1,0,1,1,1,4,2,2,3,2,2,2,1,1,1,1,1,1],
[2,2,2,1,1,1,1,1,1,1,2,4,2,2,2,2,2,2,2,2,1,1,1,1,1],
[2,2,1,1,1,1,1,1,2,2,4,4,2,2,2,2,2,2,2,2,2,1,1,1,1],
[2,1,1,1,1,1,1,1,2,2,3,2,2,1,1,1,0,2,2,2,2,2,1,7,1],
[2,1,9,8,1,1,1,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,1,0,1],
[1,1,1,1,1,1,1,2,3,2,2,1,6,1,1,1,1,1,2,2,2,3,1,1,1],
[1,1,1,1,1,1,2,2,2,2,1,1,1,10,8,1,12,1,2,2,2,2,1,5,1],
[1,1,1,1,1,1,2,2,2,2,1,1,5,1,1,9,1,2,2,2,2,2,1,1,1],
[1,7,1,1,0,1,2,2,2,2,2,1,1,1,1,1,2,2,2,4,2,1,1,1,1],
[1,1,1,1,1,1,2,2,4,2,2,4,1,2,2,2,2,3,2,2,2,1,1,1,1],
[1,1,1,1,1,1,1,4,2,2,2,2,2,2,2,2,2,2,2,2,1,1,12,1,1],
[1,0,1,1,1,1,1,2,2,3,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,1,1,1,1,6,1,1,1],
[1,1,1,1,1,1,1,1,1,9,2,2,2,2,1,1,1,1,1,6,1,1,1,1,1],
[1,1,8,1,1,1,1,1,9,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,7,6,1,1,1,1,1,1,1,1,1,1,1,9,1,1,1,7,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,5,1,1,1,11,1,1,1,1,1,6,1,1,1,1,5,1,7,1],
[1,1,7,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,5,1,1,6,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]

A live example can be seen here

Great – now I had the possiblity to “paint” a map with an array – but how about automating it – making the art randomized?

random tilemap edge to edge

See live example here – to generate a new ranomized map, click the background.

Another win.. But then my constantly challenging brain thought – how about making it change itself in a smooth animation – like scrolling sideways and always generating new map. The difficulty about this is memory in the browser – I had to build something that didnt just keept adding to the memory. So I came up with the idea of modifying the array – removing tiles from one end, and adding new ones to the other end.

an animated sidescrolling tilemap

See a live example here (if you scroll down you can also see how the array is modified).

The isometric script for the last example is here, for free use.

If you make something nice with this – please post it in the comments below 🙂

		window.requestAnimFrame = (function(){
			return  window.requestAnimationFrame   ||
					window.webkitRequestAnimationFrame ||
					window.mozRequestAnimationFrame    ||
					window.oRequestAnimationFrame      ||
					window.msRequestAnimationFrame     ||
					function(/* function */ callback, /* DOMElement */ element){
						window.setTimeout(callback, 1000 / 60);
					};
		})();
		
		// Adding the same images multiple times to the tile array, to increase the chance of image appearence on the map. Could make this better by making some factor for each image; how much it should be used.
		var tiles = [
				{ src: "/swamp/000.png"	},
				{ src: "/swamp/000.png"	},
				{ src: "/swamp/000.png"	},
				{ src: "/swamp/000.png"	},
				{ src: "/swamp/000.png"	},
				{ src: "/swamp/000.png"	},
				{ src: "/swamp/000.png"	},
				{ src: "/swamp/000.png"	},
				{ src: "/swamp/000.png"	},
				{ src: "/swamp/000.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/001.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/002.png"	},
				{ src: "/swamp/003.png"	},
				{ src: "/swamp/004.png"	},
				{ src: "/swamp/005.png"	},
				{ src: "/swamp/006.png"	},
				{ src: "/swamp/007.png"	},
				{ src: "/swamp/008.png"	},
				{ src: "/swamp/009.png"	},
				{ src: "/swamp/010.png"	},
				{ src: "/swamp/011.png"	},
				{ src: "/swamp/012.png"	}
			];
		var images = [];
		
		$(document).ready(function(){
			
			  
			
		// preload all tile images
			
			var imagesLoaded = 1;
			for(var i = 0; i < tiles.length; i++){
				var img = new Image();
				img.src = 'tiles/' + tiles[i].src;
				img.onload = function(){
					if(imagesLoaded < tiles.length){
						console.log('images loaded: ' + imagesLoaded + '/' + tiles.length)
						imagesLoaded++;
					} else if(imagesLoaded == tiles.length) {
						console.log('all images loaded');
						setTimeout(function(){loop();},100);
					}
					
				}
				images.push(img);
			}

		
		

		

		});
		
		function randomMap(x,y,types){
			var map = [];
			for(var a = 0; a < x; a++){
				var row = [];
				for(var b = 0; b < y; b++){
					row.push(Math.floor(Math.random() * types));
				}
				map.push(row);
			}
			return map;
		}
		
		
		var offset = 1;
		
		var map = randomMap(20,20,tiles.length);

			
		var tilecount = 0;
		function loop(){
			
			
			var canvas = document.getElementById('main')
			var ctx = canvas.getContext('2d');	
			ctx.clearRect(0,0, canvas.width, canvas.height);
			//console.log(offset);
			for (var i = 0; i < map.length; i++) { for (var j = map[i].length - 1; j >= 0 ; j--) {
					
					var tileWidth = 76,
						tileHeight = 43;

					var tileHeightDif = tileHeight - images[map[i][j]].height;
					ctx.drawImage(
						images[map[i][j]],
						((j * tileWidth) / 2) + ((i * tileWidth) / 2) +200, //X
						(i * tileHeight / 2) - (j * tileHeight / 2) + ((map[i].length/2)*tileHeight) + tileHeightDif +70, //Y
						tileWidth+2, 
						images[map[i][j]].height+2
					)
				}
			}
			
			
			
			ctx.translate(-offset,0);
			tilecount++;
			
			if(tilecount == 75){
				for(var a = 0; a < map.length; a++){
					map[a].shift();
					map[a].push(Math.floor(Math.random() * tiles.length));

				}
				var row = [];
				for(var b = 0; b < map[0].length; b++){
					row.push(Math.floor(Math.random() * tiles.length));
					
				}
				map.shift();
				map.push(row);
				tilecount = 0;
				ctx.translate(75,0);

			}

			$('#map').val(JSON.stringify(map));
			requestAnimFrame(loop);
			
			
			
		}
		

The used tiles can be found here:

So.. what is next you might think? I am speculating on ways to recreate this in Unity in 2.5D – so I can be able to add dynamic lightning and make the trees cast shadows. But before I do this, I guess I have to brush off on my unity skills – since I havent worked with unity since v.4 was brand new.

Stay tuned, and check back later 🙂

Ah – one last thing. Monument Valley – If you havent tried it yet – do so ASAP, it is an amazing Isometric game for both android and iphone.

screenshot from monnument valley