Как стать автором
Обновить

Комментарии 32

Если что, есть уже библиотеки, например axono.me/
Огромное спасибо.
Было бы более интересно почитать про изометрию со сложным рельефом )
А по точнее?
Отрендерить в webGL?
В старых DOS играх это решалось значительно более простыми методами
'К сожалению', на текущий момент, при разработке для планшетов, смартфонов или html5, webgl/opengl будут быстрее и эффективнее.
ИМХО, я игр не писал.

У сетки есть компонента высоты, которая учитывается при отрисовке и в логике, тайлов от этого больше не станет, так что принципы те же.
Я вот сделал простой класс. В двух словах — принимает 3d-точку координат в мире, возвращает 2d-точку координаты на холсте и наоборот. Теперь, когда у нас есть карта высот (высота углов тайла, а не самого тайла) — мы проходим эти тайлы, создаём соответствующием им четырёхугольные полигоны и отрисовываем на холст. карту не делал, но объёмный летающий куб — делал

Исходник класса
/** class IsometricProjection */
LibCanvas.declare( 'LibCanvas.Engines.IsometricProjection', 'IsometricProjection', {

/**
* factor (and default factor in proto)
* @property {Point3D}
*/
factor: [0.866, 0.5, 0.866],

/**
* size (and default size in proto)
* @property int
*/
size: 1,

/**
* start (and default start in proto)
* @property {Point}
*/
start: [0, 0],

/**
* @constructs
* @param {Point3D} factor
*/

/**
* @constructs
* @param {object} settings
* @param {Point3D} settings.factor
* @param {Point3D} settings.size
* @param {Point} settings.start — position of [0,0] coordinate
*/
initialize: function (settings) {
this.bindMethods([ 'toIsometric', 'to3D' ]);
this.settings = new Settings(settings);

this.factor = Point3D( this.settings.get('factor') || this.factor );
this.size = Number ( this.settings.get('size') || this.size );
this.start = Point ( this.settings.get('start') || this.start );
},

/**
* @param {Point3D} point3d
* @returns {Point}
*/
toIsometric: function (point3d) {
point3d = Point3D( point3d );
return new Point(
(point3d.y + point3d.x) * this.factor.x,
(point3d.y — point3d.x) * this.factor.y — point3d.z * this.factor.z
)
.mul(this.size)
.move(this.start);
},

/**
* @param {Point} point
* @param {int} [z=0]
* @returns {Point3D}
*/
to3D: function (point, z) {
point = Point(point);
z = Number(z) || 0;

var
size = this.size,
start = this.start,
dXY = ((point.y — start.y) / size + z * this.factor.z) / this.factor.y,
pX = ((point.x — start.x) / size / this.factor.x — dXY) / 2;

return new Point3D( pX, pX + dXY, z );
}
});
Раскрашенный исходник класса
LibCanvas.declare( 'LibCanvas.Engines.IsometricProjection', 'IsometricProjection', {

	factor: [0.866, 0.5, 0.866],
	size: 1,

	start: [0, 0],

	initialize: function (settings) {
		this.bindMethods([ 'toIsometric', 'to3D' ]);
		this.settings = new Settings(settings);

		this.factor = Point3D( this.settings.get('factor') || this.factor );
		this.size   = Number ( this.settings.get('size')   || this.size   );
		this.start  = Point  ( this.settings.get('start')  || this.start  );
	},

	toIsometric: function (point3d) {
		point3d = Point3D( point3d );
		return new Point(
			(point3d.y + point3d.x) * this.factor.x,
			(point3d.y - point3d.x) * this.factor.y - point3d.z * this.factor.z
		)
		.mul(this.size)
		.move(this.start);
	},

	to3D: function (point, z) {
		point = Point(point);
		z = Number(z) || 0;

		var
			size  = this.size,
			start = this.start,
			dXY = ((point.y - start.y) / size + z * this.factor.z) / this.factor.y,
			pX  = ((point.x - start.x) / size / this.factor.x - dXY) / 2;

		return new Point3D( pX, pX + dXY, z );
	}
});
А почему надо по-диагонали рисовать?
Потому что если вы начнете рисовать по горизонту, вы наткнетесь на пару веселых проблем.
1) Проблема со сдвигами.
2) Неопределенность координат. К примеру координаты Y идут влево, а координаты X вправо. А теперь подумайте, как придется выворачиваться, чтоб составить матрицу. Рисование по горизонтали, не позволит это сделать без геморроя.
Чем флеш то отличается?
Математика она везде математика вне зависимости от языка.
А в статье хоть и есть ЖС код но не сказал бы что механизмы уж совсем исключительно яваскриптовые. К тому же рисовать от центра не смотря на все сложности — далеко не самый оптимальный вариант.
Проще добавить парочку математических формул для вычисления правильных координат, зато заполнить массив картинок на которые повесить слушатели кликов. Чем «удобненько» отрисовать, но потом еще два дня потратить на изобретение олова нужного клика.
Опять же массив массив картинок не самый оптимальный по производительности вариант. Но рассуждать можно долго:)

Короче автору могу посоветовать меньше яваскрипта и больше математики с логикой в его труды.

А теперь представьте, если навешивать слушателей. 320 вариантов. В добавок, при клике будут вызываться от 2 до 4 ячеек (прямоугольники как ни как), нужно будет каждую из них проверять на вхождение в ромб. Хоть математически это и не сложная операция, но сам факт, сначала перебрать 320 вхождений, а после уже вызов нужной функции.

Не проще ли выйти на эту координату используя пару математических операций?

Я не про слушатели как бы говорил, к тому же уточнил что это всего лишь один из вариантов, и далеко не самый производительный.
Сам вариант отрисовки «от центра» хреновый, так как с таким вариантом мы только рисуем удобно, но кроме рисования ничего из таким образом отрисованных ячеек получить не сможем. А если рисовать нормально, столбиками и линиями то как минимум останется выбор что делать с этими ромбами. И математика будет где-то сложнее где-то проще, но глобально — там где действительно считать придется — в разы проще таки.

А отрисовка сетки это как бы далеко не единственная и не основная задачи изометрии.
т.е. вы предлагаете рисовать матрицу таким образом?
* * * * *
* * * *
* * * * *
Пробелы были скушаны.
Еще один бонус такой рисовки — удобно работать с гексами, а не только ромбами.
Как один из вариантов — да.
Под каждую задачу свое решение будет.
К примеру с таким вариантом расчет координат(и отрисовка же) будет сводиться к сдвигу четных рядов на 0.5 клетки.
Я такой вариант уже пробовал. Т.к. я пишу стратегию, наткнулся на неприятную особенность, когда идет сдвиг карты, на который еще есть объекты.

При сдвигах по вертикали, юниты и строения начинали прыгать. Сейчас покажу в примере.

Допустим, слэш — это положение юнита.


Сдвигая карту по вертикали, юнит должен быть отрисован на уровень выше. Был на матрице в координате Y:25, а стал Y:24.

При сдвиге происходит так, что юнит сдвигается вот так.


Получается что двигая карту строго по вертикали, юнит начинает прыгать то влево, то вправо.

Я нашел выход из этой ситуации, но он меня не удовлетворял, т.к. перерисовку матрицы нужно было бы делать при сдвиге 2 клеток. Если юзать мышь, для передвижения то можно выкрутиться используя перемещение холста, но если есть стрелки навигации, то мы попадаем не в очень удобное положение, удобность использования матрицы или гладкое использование для пользователей.

Вот такая дилемма.
Странная дилема. Надо сдвигать матрицу и юнитов не на тайлы, а на пиксели. А потом отрисовывать их транслейтнутыми. Т.е., если юзер нажал «влево», то холст и юнитов надо рисовать на 20 пикселей левее.
Но юниты двигаются с позиции X1 и Y1 в позицию X2 и Y2. И находятся они в точно заданных местах.
А если сдвигаемся на пиксели, то появятся проблемы точности, в этом я уверен на 100%.
Юниты да, а карта это вся плоскость. Вот всю плоскость надо сдвигать как-то точнее нежели по тайлам.

И я бы порекомендовал попробовать реализовать это на флеше, чтобы понять к чему стремиться, там это проще и быстрее получится. А потом если так хочется — перенести на жабаскрипт.
Движение юнитов по карте — это одно и оно не привязано к сдвигу слоя. Т.е. когда юнит ходит — у него меняется позиция относительно карты и относительно экрана (т.к. карта остаётся на месте), а когда карта двигается, то позиция относительно карты остаётся стабильной, а вот позиция относительно экрана — смещается (на одинаковое растояние у карты и у юнита).

Если бы карта двигалась так, чтобы юнит всегда был посередине, то позиция юнита оставалась бы стабильной, а позиция карты — перемещалась бы.

Посмотрите этот пример: libcanvas.github.com/scenes/dune/
Я теперь понял о чем ты именно.
В общем плавный сдвиг перевести и на стрелки навигации.

Вариант решения.
Ага)
Именно.
Очень неплохая статья была в блоге project zomboid. Одна проблема: картинки там исчезли, а понять смысл без них весьма не просто. Может у кого-нибудь есть сохраненная?

Примеры не доступны

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории