1
\$\begingroup\$

I have been working on a 2d html5 canvas map editor. It is tile based, and originally it was just a top-down view on a grid of tiles (or empty spaces). I decided I wanted to convert it to render the tiles from an isometric view.

My main question right now is what is the best way to do that? All of my map data is stored in standard cartesian coordinates in a 2d array. Looking at my map files is essentially like looking at a text based version of the map, it renders exactly like the 2d array is formatted. Also all of my logic is done with cartesian coordinates, including all the collision detection and resolution.

I did some research, and a lot of people were saying the best way to do this is to store the data in cartesian coordinates, do all the collision detection with cartesian coordinates, etc, and then simply render the tiles isometrically. I tried to do this, however everything is messed up now. This is how I currently am trying to render it:

Game.ctx.save()
Game.ctx.translate(relativeX, 0);
Game.ctx.scale(1, 0.5);
Game.ctx.rotate(45 * Math.PI /180);

// draw the map as you normally would here

Game.ctx.restore()

This makes it look like an isometric map, however several things are screwed up when I do it this way. The first thing, is that collisions between my mouse and the tiles are broken. I figured this was because my mouse is clicking on the isometric tiles, so I can't simply divide the x and y of the mouse event by the tile width/height, to determine which row/column I clicked on, and therefore which tile I clicked on. I wrote a few functions for converting between cartesian and isometric coordinates, to address this issue, below:

let cartToIso = (point) => {
  let isoX = point.x - point.y
  let isoY = (point.x + point.y) / 2
  return { x: isoX, y: isoY }
}

let isoToCart = (point) => {
  let cartX = point.y + (point.x / 2)
  let cartY = point.y - (point.x / 2)
  return { x: cartX, y: cartY }
}

And here is the code I use to place tiles on the grid from my mouse:

let realMousePos = {
  x: Game.events.mouse.x - this.pos.x,
  y: Game.events.mouse.y - this.pos.y
}

let mouseCartPos = Iso.isoToCart(realMousePos)
let columnIntersected = Math.trunc(mouseCartPos.x / this.size)
let rowIntersected = Math.trunc(mouseCartPos.y / this.size)

let x = this.pos.x + (columnIntersected * this.size)
let y = this.pos.y + (rowIntersected * this.size)

if(this.textureMenu.selectedTexture != 'eraser') {
  if(this.texturePreview) {
    this.texturePreview.pos = {x, y}
  }
  else {
    this.texturePreview = new Texture(x, y, this.textureMenu.selectedTexture.key, this.textureMenu.selectedTexture.img)
  }
}

The tile ends up being placed anywhere from 10 to 100 or so pixels away from my mouse.

This is such a complicated issue I'm having that I'm not sure how to best summarize the questions. Essentially, given what you all now know about my project, what is the best way to convert it to an isometric engine?

Should everything be stored in cartesian terms, and only at the last minute translated into isometric terms? Or should everything be isometric, from the map data to the collision math to the tiles themselves.

Should my tiles be isometric? Or should they be squares, that I then rotate and scale to be twice as wide as they are high (like I'm doing now)?

This is a big question I have. Since my map is rectangular, and when I render things isometrically, how do I fit a diamond shaped map into my viewport? The viewport is a rectange, and the map is a diamond, I don't understand how I can set the horizontal and vertical boundaries. Do I add padding to the map somehow? Do I make my maps diamond shaped? This part is so confusing to me, it seems either parts of my map will be cut off or I'm going to have big chunks of blank space at the 4 corners of my map. I would really appreciate help with this part.

Here is the full project, on the current branch I'm working on: https://github.com/robins35/map_editor/tree/convert-to-iso

Please let me know if I need to add additional info, there is definitely a lot of things I've missed, but it's such a big project that it's hard to mention every part of the codebase this would effect.

EDIT: Here is an image of the map editor. You can see the tile placement indicator, my screenshot tool (scrot) didn't show my mouse, but it's about 100 pixels below the tile placement indicator (translucent). Also the grid is all messed up, missing from the top right side of the view port.

map_editor

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.