Love2d Isometric Grid Framework Starting Point

Series: dev April 20, 2018

Interactive Isometric Grids

The following is an outline of a Love2D Isometric Framework. It is a complete love2d example that gives you an 8 by 8 isometric grid. You can use the functions to generate grids of tiles.

Here are some ways you can extend this starting point:

  • Upgrade it to love 11.
  • You could extend this by drawing sprites, animations, or graphics by writing additional functions like draw_tile_border, draw_tile_fill to implement things like drawing sprites, animations, or specific shapes.
  • You could create additional tools to draw a different border just around the edge of the border.
  • Turn it into its own library.
  • Add a way of storing our constants in said library so we don’t just pass them all over the place.
  • If you’re using big maps, you’ll want to switch from brute-forcing figuring out which tile you’re on.
    • It’s something like:
      • x = ((screen_x - x_off) / TH + screen_y / (TH / 2)) /2
      • y = ((screen_y - y_off) / (TH/2) - (screen_x / TH)) /2
  • Adding actual gameplay.

Please feel free to reach out via Twitter or Email if you do anything with this!

function love.load()
	-- love.mouse.setVisible( false )
	TW = 6
	TH = 6
	X_OFF = 100
	Y_OFF = 50
	TILE_H = 20
end

-- Overview
-- All of the functions have a few arguments that are pretty much the same for a project.
-- They should be refactored out, but they allow you to change the offset, number of tiles, and the tile height.
 
function love.draw()
	W = {255,255,255,255} 	--WHITE
	U = {0,0,255,255} 		--BLUE
	B = {0,0,0,255} 		--BLACK
	R = {255,0,0,255} 		--RED
	G = {0,255,0,255} 		--GREEN
	MG = {0,255,0,100}		-- Mouse (Translucent) Green
	C = {0,0,0,0}			--CLEAR

	map = {
			{W,R,C,C},
			{W,W,C,W},
			{C,W,R,W},
			{W,C,C,W}
		}

	draw_map_fill(map,X_OFF,Y_OFF,TW,TH,TILE_H)
	if mouse_map_x ~= nil and mouse_map_y ~= nil then 
		draw_map_tile_fill(mouse_map_x,mouse_map_y,TW,TH,TILE_H,X_OFF,Y_OFF,MG)
	end
	draw_map_border(X_OFF,Y_OFF,TW,TH,TILE_H,G)

	love.graphics.setColor(MG[1],MG[2],MG[3],MG[4])
	love.graphics.points(mouse_x, mouse_y)
end

function love.update(dt)
	mouse_x, mouse_y = love.mouse.getPosition( )

	mouse_map_x, mouse_map_y = get_map_coords(mouse_x, mouse_y,X_OFF,Y_OFF,TW,TH,TILE_H)
end


-- Draws an isometric line with its bottom point at x,y, with a height from the bottom to top points.
-- The height acts as a scale for the tiles.
function draw_tile_border(x,y,height)
	love.graphics.line(x, y, x+(2*height), y+height, x, y+(2*height), x-(2*height), y+height, x, y)
end

-- Fills a tile as above.
function draw_tile_fill(x,y,height,col)
	love.graphics.setColor(col[1],col[2],col[3],col[4])
	love.graphics.polygon('fill', x, y, x+(2*height), y+height, x, y+(2*height), x-(2*height), y+height, x, y)
end

-- This function takes a map coordinate, turns it into a tile coordinate, and draws a tile
function draw_map_tile_border(x,y,w,h,tile_height,x_off,y_off)
	mx = ((4*tile_height)*(w/2))+((2*tile_height)*(x-y))
	my = ((tile_height)*(y+x-2))
	draw_tile_border(mx+x_off,my+y_off,tile_height)
end

-- Fills a map tile as above
function draw_map_tile_fill(x,y,w,h,tile_height,x_off,y_off,col)
	mx = ((4*tile_height)*(w/2))+((2*tile_height)*(x-y))
	my = ((tile_height)*(y+x-2))
	draw_tile_fill(mx+x_off,my+y_off,tile_height,col)
end

-- Our map has the following coordinates:

--         0,0
--     0,1     1,0
-- 0,2     1,1     2,0
--     1,2     2,1
--         2,2

-- Draws the edges of a map in a given color.
function draw_map_border(x_off,y_off,width, height, tile_height,col)
	love.graphics.setColor(col[1],col[2],col[3],col[4])
	for ix=1,width,1 do 
		for iy=1,height,1 do 
			draw_map_tile_border(ix,iy,width,height,tile_height,x_off,y_off)
		end
	end
end

-- Fills in tiles of a map based on a 2d table, each cell of which contains a table of color values
function draw_map_fill(arr,x_off,y_off,w,h,th)
	for x=1,#arr,1 do
		for y=1,#arr[x],1 do
			draw_map_tile_fill(x,y,w,h,th,x_off,y_off,arr[x][y])
		end
	end
end

-- Finds the x,y map coordinates based on screen coordinates
function get_map_coords(x,y,x_off,y_off,width,height,tile_height)
	for ix=1,width,1 do
		for iy=1,height,1 do
			if tile_contains_point(ix,iy,x-x_off,y-y_off,width, height, tile_height) then
				return ix, iy 
			end
		end
	end
	return nil, nil
	-- return 6,6
end

-- Checks if a tile on a map contains a point.
function tile_contains_point(tx,ty,px,py,w,h,th)
	-- Get the center of the tile
	cx = ((4*th)*(w/2))+((2*th)*(tx-ty))
	cy = ((th)*(ty+tx-2))+th
	if (math.abs(px-cx)/(2*th))+(math.abs(py-cy)/th) <= 1 then
		return true
	end
	return false
end

function div(a,b)
	return (a - a % b) / b
end

built with , Jekyll, and GitHub Pages — read the fine print