Плавная прокрутка изометрической карты с помощью перетаскивания — Html5

Я реализовал базовый изометрический тайловый движок, который можно исследовать, перетаскивая карту мышью. Пожалуйста, посмотрите на скрипку ниже и перетащите ее:

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/


person Jamie Fearon    schedule 30.08.2012    source источник


Ответы (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/

Разве это не намного короче и слаще?

P.S. Изометрические браузерные игры в реальном времени — отличная идея. Обязательно попробую сделать, когда будет время.

person Andrew Mao    schedule 28.09.2012