2

我已经实现了一个基本的等距平铺引擎,可以通过用鼠标拖动地图来进行探索。请看下面的小提琴并拖走:

http://jsfiddle.net/kHydg/14/

分解的代码是(CoffeeScript):

绘图功能

draw = ->
  requestAnimFrame draw
  canvas.width = canvas.width

  for row in [0..width]
    for col in [0..height]
      xpos = (row - col) * tileHeight + width
      xpos += (canvas.width / 2) - (tileWidth / 2) + scrollPosition.x
      ypos = (row + col) * (tileHeight / 2) + height + scrollPosition.y
      context.drawImage(defaultTile, Math.round(xpos), Math.round(ypos), tileWidth, tileHeight)

鼠标拖动滚动控制

scrollPosition =
  x: 0
  y: 0

dragHelper = 
  active: false
  x: 0
  y: 0


window.addEventListener 'mousedown', (e) =>
  handleMouseDown(e)
, false

window.addEventListener 'mousemove', (e) =>
  handleDrag(e)
, false

window.addEventListener 'mouseup', (e) =>
  handleMouseUp(e)
, false

handleDrag = (e) =>
  e.preventDefault()
  if dragHelper.active
    x = e.clientX
    y = e.clientY
    scrollPosition.x -= Math.round((dragHelper.x - x) / 28)
    scrollPosition.y -= Math.round((dragHelper.y - y) / 28)

handleMouseUp = (e) =>
  e.preventDefault()
  dragHelper.active = false

handleMouseDown = (e) =>
  e.preventDefault()
  x = e.clientX
  y = e.clientY
  dragHelper.active = true
  dragHelper.x = x
  dragHelper.y = y

问题

正如您从小提琴中看到的那样,拖动动作还可以,但并不完美。我将如何更改代码以使拖动动作更流畅?我想要的是您单击的地图点,以便在拖动时保持在鼠标点下方;和他们在这里做的一样:http: //craftyjs.com/demos/isometric/

4

1 回答 1

1

很多图书馆都可以帮助解决这样的事情。出于几个原因,我建议使用 d3 的数据操作能力来提供帮助。

首先,在 d3 中,有一个拖动行为,其中存储了对象的原点,并在拖动开始时计算相对于原点的鼠标位置。然后,您可以使用鼠标的绝对位置来确定对象应该在哪里,并避免在使用相对更改时发生的增量错误 - 当您开始四舍五入时会变得更糟,如上所述。

dragMap = (d) ->  
  d.x = d3.event.x # d3.event.x, y are computed relative to the origin for you!
  d.y = d3.event.y 

dragBehavior = d3.behavior.drag()
  .origin(Object) # equivalent to (d) -> d 
  .on("drag", dragMap)

d3.select(canvas)
  .datum(x: 0, y: 0)  # Load your canvas with an arbitary origin
  .call(dragBehavior) # And now you can drag it!

其次,通过使用 d3 的线性或其他数字比例,您可以避免自己进行典型的绘图数学,这很容易出错,尤其是当您必须在所有地方都这样做时。在将拖动缩放 28 之前。在我当前的方法中,这是不必要的,但是如果您将绘图算法更改为使用平铺而不是像素,您可以更改此比例,它会自动将鼠标像素转换为平铺大小。

pixelToTile = d3.scale.linear()
  .domain([0, 1])
  .range([0, 1])  

这是您在 d3 帮助下重新完成的小提琴。没有 dragHelper 和所有必要的无关代码。除了用于防止抗锯齿的画布绘制之外,所有 Math.round 调用也是不必要的。

http://jsfiddle.net/kHydg/23/

这不是更短更甜吗?

PS Isometric 实时浏览器游戏是一个很棒的主意。当我有时间的时候,我一定会尝试做一个。

于 2012-09-28T19:48:18.460 回答