Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > HardCoder

Оценить эту запись

Еще один способ создания изометрического мира

Запись от HardCoder размещена 20.01.2012 в 21:04
Обновил(-а) HardCoder 21.01.2012 в 11:48 (Переделал классы и их названия)

Здравствуйте, уважаемые коллеги! Хочу представить вам мой способ создания изометрического игрового мира. Прежде чем начать, хочу попросить Вас воздержаться от фраз типа: "Зачем изобретать велосипед?". Думаю, те - кому интересно создавать что-то свое собственное - меня поймут. Весь алгоритм преобразования координат и сортировки созданы мной лично, поэтому цель этой статьи - услышать об ошибках для дальнейшего их устранения.
И так, начать хочу с примера. В этом примере нужно с помощью мыши перетаскивать серые кубики по полю. Они представляют собой персонажей будущей игры. А вот и сам swf: http://megaswf.com/serve/1955305

1. Обзор
Чем отличается мой подход от остальных я и сам толком не знаю, так как никогда не пользовался и даже не интересовался другими изометрическими библиотеками.

1.1 Недостатки
Если Вы, заметили - все поле состоит из клеток. В данном способе клетки могут быть лишь квадратной формы (если смотреть сверху), но не прямоугольной. Отсюда главный недостаток - невозможность создания обьектов прямоугольной формы - одни лишь "квадратики". Но, как Вы, заметили - это не мешает создавать прямоугольные здания из набора мелких обьектов квадратной формы.
Второй недостаток - обьекты не могут летать в воздухе. Вернее - могут, но сортироваться они будут в этом случае неправильно. Короче говоря: это не 3D - все вычисления происходят лишь двухмерной системе координат.

1.2 Преимущество
Очень удобный и простой, для понимания инструмент для создания игр, основанных на лабиринтах.

2. Основные понятия

2.1 Клетка
Клетка - это экранный обьект, представляющий собой отдельную квадратную область плоскости, на которой стоят или перемещаются разные обьекты. Клетка не может быть обьемной, она всегда плоская. Клетка может быть изображением травы, песка, асфальта и пр. Но она не может иметь изображение дерева, кустов, гор, так как эти обьекты имеют определенную высоту.
2.1.1 Требования:
а) клетки должны добавляться в самый нижний спрайт, который представляет собой фон изометрического мира;
б) клетки не сортируются;
в) все 4 стороны клетки должны быть равны (ромб, но не параллелограмм);
г) все клетки должны быть одинакового размера;
д) угол между сторонами клетки и осью Х должен быть равен 26.6° (см. дальше);
е) точка регистрации клетки должна быть в самой верхней точке по середине (см. рисунок 1).

2.2 Сортируемый обьект
Сортируемый обьект - это экранный обьект, представляющий собой трехмерную фигуру. Это может быть здание, солдат, дерево, гора и др.
2.2.1 Требования:
а) сортируемые обьекты должны быть добавлены и удалены только с помощью методов addItem() и removeItem соответственно, класса IsoSorter (см. ниже);
б) контейнер сортируемых обьектов должен всегда находится над спрайтом клеток (то есть - выше фона изометрического мира);
в) в контейнере с обьектами не должно находится сторонних обьектов, которые не должны сортироваться, или по ошибке были добавлены стандартными методами addChild(), addChildAt();
г) желательно, чтобы точка регистрации сортируемых обьектов соответствовала примеру на рисунке1.

2.3 Контейнер сортируемых обьектов
Контейнер сортируемых обьектов - это экранный обьект, в котором находятся герои, домики, деревья и т.д. Таких контейнеров может быть несколько в игре. Они могут содержать в себе другие контейнеры. Тогда эти дочерние контейнеры будут сортироваться как отдельные "сортируемые обьекты.".
Класс IsoSorter хранит в себе список всех контейнеров (см. п.5).

3. Изометрия

3.1 Система координат
Как я заметил выше, все клетки добавляются в самый нижний спрайт - фон. Согласно приведенному в п.4 алгоритму, все клетки добавляются на сцену так что одна половина находится в положительной области спрайта - фона по оси Х, а другая - в отрицательной. Для кого-то это может быть неудобно, но меня совсем не смущает. Самая первая клетка (самая дальняя от зрителя) всегда находится в 0 точке спрайта - фона. Изометрическая карта имеет две оси: x и z. Пример системы координат данного подхода приведен на рисунке 2.

3.2 Создание клетки
Выше я упоминал что угол между сторонами клетки и осью Х должен быть равен 26.6°. Обычно, говоря "изометрия" - имеют в виду 30°. В моем случае по другому. Откуда такая цифра 26.6°? Все дело в том, что очень удобно создавать клетки под таким углом. Мне этот способ создания клеток понравился и я решил написать алгоритм преобразования координат именно под этим углом.
Для создания клетки необходимо нарисовать квадрат, повернуть его на 45° и высоту того что получилось уменьшить вдвое (см. рисунок 3).

3.3 Spacing
Spacing - это пространство между точками регистрации двух клеток, которые граничат между собой. Грубо говоря - это расстояние между соседними клетками (рисунок 4).

4. Класс IsoTransformer

4.1 Метод setSpacing()
Ниже приведен класс, преобразующий координаты. У него есть статическое свойство Spacing. Перед началом использования этого класса сначала нужно определить это свойство с помощью статического метода setSpacing(). Если расстояние между клетками (spacing) заранее известно, можно передать это значение в метод setSpacing() в иде числа (Number). Если же расстояние неизвестно, то есть мы его не измеряли, необходимо передать в метод тестовый экземпляр клетки. В этом случае программа сама высчитает свойство Spacing, исходя из геометрических размеров переданной клетки.
Код AS3:
//Временная клетка. Вместо мувиклипа - класс клетки (зависит от фантазии)
var tempCell:MovieClip = new MovieClip();
//устанавливаем пространство между клетками
IsoTransformer.setSpacing(tempCell);
4.2 Метод screenToIso()
Статический метод screenToIso() вычисляет изометрические координаты. Он принимает в себя два параметра: x и y. Это координаты точки НА КОНТЕЙНЕРЕ. Иногда очень легко запутаться, если передавать глобальные координаты в этот метод. Тогда он возвратит совсем не те значения которые нужно. Поэтому - в метод screenToIso() нужно передавать только координаты точки, которая относится к контейнеру, для которого нужно найти изометрические координаты. Если необходимо вычислить isoX и isoZ по точке, например, из главной сцены - то нужно воспользоваться стандартным методом globalToLocal() и преобразовать эту точку в точку нужного нам контейнера. Возвращает этот метод обьект Point со свойствами: x - координаты точки по оси isoX; y - координаты точки по оси isoZ.

4.3 Метод isoToScreen()
Статический метод isoToScreen() преобразовывает изометрические координаты контейнера в экранные координаты того же контейнера (не родительского, или какого-нибудь другого). Принимает в себя 2 параметра: isoX и isoZ. Возвращает обьект Point с экранными координатами.

4.4 Построение карты
Как я упоминал выше: спрайт клеток должен быть ниже контейнера сортируемых обьектов. Для этого нужно создать два спрайта, определить свойство Spacing класса IsoTransformer и добавить клетки, приблизительно по следующему примеру:
Код AS3:
//спрайт клеток (фон)
var background:Sprite = new Sprite();
this.addChild(background);
 
//Временная клетка. Вместо мувиклипа - класс клетки (зависит от фантазии)
var tempCell:MovieClip = new MovieClip();
//устанавливаем пространство между клетками с помощью временной клетки
IsoTransformer.setSpacing(tempCell);
 
//количество клеток по оси isoX
var rows:uint = 10;
//количество клеток по оси isoZ
var columns:uint = 10;
 
for (var x:uint = 0; x < rows; x++){
	for (var z:uint = 0; z < columns; z++){
		//создается клетка и добавляется в спрайт клеток
		var cell:MovieClip = new MovieClip();
		background.addChild(cell);
 
		//вычисляются экранные координаты клетки в спрайте клеток
		var tempPoint:Point = IsoTransformer.isoToScreen(x * IsoTransform.Spacing, z * IsoTransform.Spacing);
		сell.x = tempPoint.x;
		сell.y = tempPoint.y;
	}
}
Код класса IsoTransformer

Код AS3:
package {
	import flash.display.DisplayObject;
	import flash.geom.Point;
 
	/**
	 * Преобразует экранные координаты контейнера в изометрические и наоботрот
	 * @author HardCoder
	 */
	public class IsoTransformer {
		private static const ALPHA:Number = 0.4636476090008062;
		private static var _spacing:Number;
 
		/**
		 * Преобразует экранные координаты контейнера в изометрические
		 * @param	x - экранная x
		 * @param	y - экранная y
		 * @return	Point(isox, isoZ)
		 */
		public static function screenToIso(x:Number, y:Number):Point {
			var isoX:Number = (x * Math.tan(ALPHA) + ((y - x * Math.tan(ALPHA)) / 2)) / Math.sin(ALPHA);
			var isoZ:Number = ((y - x * Math.tan(ALPHA)) / 2) / Math.sin(ALPHA);
			return new Point(isoX, isoZ);
		}
 
		/**
		 * Преобразует изометрические координаты в экранные координаты контейнера
		 * @param	isoX - изометрическая x
		 * @param	isoZ - изометрическая z
		 * @return	Point(x, y)
		 */
		public static function isoToScreen(isoX:Number, isoZ:Number):Point {
			var x:Number = isoX * (Math.cos(ALPHA)) - isoZ * (Math.cos(ALPHA));
			var y:Number = isoX * (Math.sin(ALPHA)) + isoZ * (Math.sin(ALPHA));
			return new Point(x, y);
		}
		/**
		 * Вычисляет и возвращает пространство между точками регистрации плиток
		 * @param	obj - значение (Number) или клетка (DisplayObject)
		 * @return	Number
		 */
		public static function setSpacing(obj:*):Number {
			if (!_spacing){
				if (obj is DisplayObject){
					_spacing = Math.floor(Math.sqrt(5 * Math.pow(obj.width, 2) / 16));
				} else {
					_spacing = obj;
				}
				return _spacing;
			}
			return _spacing;
		}
 
		/**
		 * Возвращает пространство между точками регистрации плиток
		 */
		public static function get Spacing():Number {
			return _spacing;
		}
	}
}
5. Класс IsoSorter

Класс имеет лишь статические методы. Он хранит в себе список контейнеров (их в приложении может быть несколько) и методы работы с сортируемыми обьектами.

5.1 Список контейнеров сортируемых обьектов
Список контейнеров сортируемых обьектов - статический. Поэтому когда какой нибудь контейнер удален со сцены - необходимо его также удалить из этого списка, иначе он будет висеть в памяти до закрытия приложения.
В каждом контейнере из списка хранятся сортируемые обьекты (деревья, человечки, домики, или другие контейнеры с человечками, деревьями и домиками). Дальше каждый сортируемый обьект буду называть "человечек".

5.2 Метод addContainerToList()
Этот метод добавляет новый контейнер в список, но не добавляет его в дисплейлист (это надо делать "вручную"). Принимает в себя параметр DisplayObjectContainer - спрайт в котором находятся наши человечки.

5.3 Метод removeContainerFromList()
Удаляет контейнер из списка, но не удаляет его из дисплейлиста (это надо делать "вручную"). Принимает в себя параметр DisplayObjectContainer - спрайт в котором находятся наши человечки, который нужно убрать из списка, чтобы он не висел в памяти.

5.4 Добавление и удаление сортируемых обьектов в контейнер
Для того чтобы добавить сортируемый обьект (человечка) в контейнер - нельзя использовать стандартный метод addChild(). Для этого нужно вызвать метод addItem() класса IsoSorter и передать в него: контейнер (спрайт, в котором находится человечек); второй параметр - сам человечек. Метод сам добавит человечка в его контейнер и поместит на нужную глубину в контейнере.

Для удаления человечка нужно вызывать метод removeItem() класса IsoSorter и передать в него: контейнер (спрайт, в котором находится человечек); второй параметр - сам человечек. И человечек будет удален из своего контейнера.

Для того, чтобы полностью очистить контейнер от человечков - можно вызвать метод removeAllItems(). В этот метод передать контейнер (спрайт с человечками). Если после удаления всех человечков нужно удалить и сам контейнер из памяти, надо передать второй параметр - deleteContainerFromList:Boolean как true.

И так, можно немного дополнить код, приведенный выше:
Код AS3:
//спрайт клеток (фон)
var background:Sprite = new Sprite();
this.addChild(background);
 
//контейнер человечков
var objectsContainer:Sprite = new Sprite();
this.addChild(objectsContainer);
 
//Добавим контейнер человечков в список контейнеров класса IsoSorter
IsoSorter.addContainerToList(objectsContainer);
 
//Временная клетка. Вместо мувиклипа - класс клетки (зависит от фантазии)
var tempCell:MovieClip = new MovieClip();
//устанавливаем пространство между клетками с помощью временной клетки
IsoTransformer.setSpacing(tempCell);
 
//количество клеток по оси isoX
var rows:uint = 10;
//количество клеток по оси isoZ
var columns:uint = 10;
 
for (var x:uint = 0; x < rows; x++){
	for (var z:uint = 0; z < columns; z++){
		//создается клетка и добавляется в спрайт клеток
		var cell:MovieClip = new MovieClip();
		background.addChild(cell);
 
		//вычисляются экранные координаты клетки в спрайте клеток
		var tempPoint:Point = IsoTransformer.isoToScreen(x * IsoTransform.Spacing, z * IsoTransform.Spacing);
		сell.x = tempPoint.x;
		сell.y = tempPoint.y;
 
		//код, приведенный ниже - используется, когда над клеткой должен быть человечек
		//Вместо мувиклипа - класс человечкп (зависит от фантазии)
		var obj:MovieClip = new MovieClip();		
		//помещаем обьект в контейнер человечков, созданный ранее и позиционируем его по середине клетки
		IsoSorter.addItem(objectsContainer, obj, cell.x, cell.y + cell.height / 2);
	}
}
5.4 Сортировка
Сортировка обьектов осуществляется с помощью метода sortItems() класса IsoSorter. Этот метод принимает в себя контейнер, в котором будет происходить сортировка и массив человечко, которые были перемещены (короче - те которые нужно отсортировать).
В примере, который я привел в самом начале - метод sortItems() вызывается каждый раз, когда двигается мышь. Поскольку все обьекты стоят на месте - нет надобности всех их сортировать. Поэтому на сортировку отправляется лишь перетаскиваемый обьект, что экономит производительность:
Код AS3:
IsoSorters.sortItems(objectsContainer, [this._dragObject]);
Вот несколько примеров:
1) В контейнере перемещается лишь один обьект и он нам известен:
Код AS3:
IsoSorters.sortItems(objectsContainer, [someObject]);
2) Например, в контейнере 200 обьектов, но из них перемещаются только 5 и они нам известны:
Код AS3:
IsoSorters.sortItems(objectsContainer, [object1, object2, object3, object4, object5]);
3) а) в контейнере перемещаются все обьекты, и всех их нужно сортировать; б) мы понятия не имеем какие обьекты в контейнере перемещаются, поэтому нужно отсортировать их всех. Для этих случаев (а и б) - в метод sortItems() не нужно передать лишь контейнер, в котором надо произвести сортировку. Это будет означать, что сортировать нужно все подряд в этом контейнере.

Код класса IsoSorter

Код AS3:
package {
	import flash.display.DisplayObjectContainer;
	import flash.display.DisplayObject;
	import flash.geom.Point;
 
	/**
	 * Добавляет, удаляет и сортирует экранные обьекты
	 * @author HardCoder
	 */
	public final class IsoSorter {
		//Список всех контейнеров
		//Этот список статический, поэтому, если контейнер удален со сцены
		//- его нужно удалить также из списка с помощью removeContainerFromList(),
		//иначе ссылка на него будет храниться все время		
		private static var _containers:Array = new Array();
 
		/**
		 * Добавляет сортируемый обьект в список отображения контейнера
		 * @param	container - контейнер, в который добавляем обьект
		 * @param	obj - сортируемый обьект
		 * @param	x - х-координата обьекта в контейнере
		 * @param	y - у-координата обьекта в контейнере
		 */
		public static function addItem(container:DisplayObjectContainer, obj:DisplayObject, x:Number = 0, y:Number = 0):void {
			var sortedContainer:SortedContainer = checkForContainer(container);
			if (!sortedContainer){
				throw new Error("Переданный контейнер не существует в списке!");
				return;
			}
			var item:SortedItem = new SortedItem();
			item.object = obj;
			item.object.x = x;
			item.object.y = y;
			sortedContainer.items.push(item);
			sortAndReplace(sortedContainer, item);
		}
 
		/**
		 * Удаляет сортируемый обьект из списка отображения контейнера
		 * @param	container - контейнер, из которого удаляется обьект
		 * @param	obj - сортируемый обьект, подлежащий удалению
		 */
		public static function removeItem(container:DisplayObjectContainer, obj:DisplayObject):void {
			var sortedContainer:SortedContainer = checkForContainer(container);
			if (!sortedContainer){
				throw new Error("Переданный контейнер не существует в списке!");
				return;
			}
			var index:uint = container.getChildIndex(obj);
			sortedContainer.items.splice(index, 1);
			container.removeChild(obj);
		}
 
		/**
		 * Удаляет все сортируемые обьекты из списка отображения контейнера
		 * @param	container - контейнер, из которого удаляются все обьекты
		 * @param	deleteContainerFromList - указывает, удалять ли контейнер из списка (не
		 *          удаляет контейнер со сцены)
		 */
		public static function removeAllItems(container:DisplayObjectContainer, deleteContainerFromList:Boolean = false):void {
			var sortedContainer:SortedContainer = checkForContainer(container);
			if (!sortedContainer){
				throw new Error("Переданный контейнер не существует в списке!");
				return;
			}
			for (var i:uint = 0; i < sortedContainer.items.length; i++){
				sortedContainer.object.removeChild(sortedContainer.items[i].object);
			}
			if (deleteContainerFromList){
				_containers.splice(_containers.indexOf(sortedContainer), 1);
				return;
			}
			sortedContainer.items.splice(0);
		}
 
		/**
		 * Добавляет новый контейнер в список, но добавляет его на сцену.
		 * @param	container - контейнер, который нужно добавить в список
		 */
		public static function addContainerToList(container:DisplayObjectContainer):void {
			var sortedContainer:SortedContainer = checkForContainer(container);
			if (sortedContainer){
				return;
			}
			sortedContainer = new SortedContainer();
			sortedContainer.object = container;
			sortedContainer.items = new Array();
			_containers.push(sortedContainer);
		}
 
		/**
		 * Удаляет контейнер из списка, но не удаляет его со сцены.
		 * @param	container - контейнер, который нужно удалить из списка
		 */
		public static function removeContainerFromList(container:DisplayObjectContainer):void {
			var sortedContainer:SortedContainer = checkForContainer(container);
			if (!sortedContainer){
				return;
			}
			_containers.splice(_containers.indexOf(sortedContainer), 1);
		}
 
		/**
		 * Сортирует обьекты. Необходимо вызывать каждый раз когда положение
		 * какого-либо обьекта изменилось
		 * @param	container - контейнер, в котором нужно сортировать обьекты
		 * @param	objectsToSort - массив обьектов контейнера, которые необходимо отсортировать.
		 * Если null - сортируем все обьекты в контейнере
		 */
		public static function sortItems(container:DisplayObjectContainer, objectsToSort:Array = null):void {
			var sortedContainer:SortedContainer = checkForContainer(container);
			if (!sortedContainer){
				throw new Error("Переданный контейнер не существует в списке!");
				return;
			}
			var length:uint;
			objectsToSort ? length = objectsToSort.length : length = sortedContainer.items.length;
			for (var i:uint = 0; i < length; i++){
				var item:SortedItem;
				if (objectsToSort){
					item = sortedContainer.items[container.getChildIndex(objectsToSort[i])];
				} else {
					item = sortedContainer.items[i];
				}
				sortAndReplace(sortedContainer, item);
			}
		}
 
		//непосредственно занимается сортировкой
		private static function sortAndReplace(container:SortedContainer, item:SortedItem):void {
			//сохраняем старую глубину обьекта
			item.prevDepth = item.depth;
			//вычисляем позицию обьекта в изометрических координатах и новую глубину
			var point:Point = IsoTransformer.screenToIso(item.object.x, item.object.y);
			item.depth = point.x + point.y;
			//если старая и новая глубины отличаются - обьект переместился, значит сортируем
			if (item.prevDepth != item.depth){
				container.items.sortOn("depth", Array.NUMERIC);
				container.object.addChildAt(item.object, container.items.indexOf(item));
			}
		}
 
		//Ищет контейнер в списке и возвращает его
		private static function checkForContainer(container:DisplayObjectContainer):SortedContainer {
			for (var i:uint = 0; i < _containers.length; i++){
				if (_containers[i].object == container){
					return _containers[i];
				}
			}
			return null;
		}
	}
}
 
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
 
//Вспомогательный класс, представляющий контейнер с набором свойств
internal class SortedContainer {
	internal var items:Array;
	internal var object:DisplayObjectContainer;
}
 
//Вспомогательный класс, представляющий сортируемый обьект с набором свойств
internal class SortedItem {
	internal var prevDepth:Number;
	public var depth:Number;
	internal var object:DisplayObject;
}
На этом, думаю, можно закончить. Спасибо за терпение. Жду обьективной критики.

Рисунки:
Изображения
Тип файла: jpg 2.jpg (45.9 Кб, 1094 просмотров)
Тип файла: jpg 4 copy.jpg (23.3 Кб, 983 просмотров)
Тип файла: jpg 1.jpg (9.8 Кб, 989 просмотров)
Тип файла: jpg 3.jpg (8.1 Кб, 1127 просмотров)
Всего комментариев 13

Комментарии

Старый 21.01.2012 03:22 Котяра вне форума
Котяра
 
Аватар для Котяра
Код AS1/AS2:
this._sortUtils
Сломало мне мозг.
замени всё на статики и передвай в параметры контейнер, если будет SortUtils
либо назови класс и его экземпляры Sorter, DiplayObjectSorter,IsoSorter,ISorter...итп
Имя должно отображать.
Обновил(-а) Котяра 21.01.2012 в 03:40
Старый 21.01.2012 11:13 Astraport вне форума
Astraport
 
Аватар для Astraport
Картинки не отображаются.
Старый 21.01.2012 16:26 GBee вне форума
GBee
 
Аватар для GBee
Не буду критиковать, мне понравилось, хотя такой подход где-то видел. В 2.5Д я не разбираюсь (но очень интересно, правда вермени нет), но как помню самый камень преткновения - это именно сортировка. Как ваш движок работает с арками?
Старый 21.01.2012 18:40 HardCoder вне форума
HardCoder
 
Аватар для HardCoder
Цитата:
Как ваш движок работает с арками?
Да, вроде нормально, вот пример: http://megaswf.com/serve/1957534 Вообще-то он не знает что такое арка или дерево. Тут надо разбивать обьекты на несколько частей. У меня арка состоит из двух частей. Одна дальше, другая - ближе.
Котяра, спасибо за замечание. Я постарался сделать как вы советовали (см. переделанную статью выше). Но, теперь, прочитав - понял что прикрутил еще больше костылей. Полностью абстрагировать класс IsoSorter не получится. Обьясню, почему. Сортировка происходит следующим образом. Каждый обьект в любом контейнере имеет свои координаты, неважно где этот контейнер находится. Исходя из этих координат - высчитывается некое число. Значит для каждого обьекта в контейнере это число будет уникальным. Чем больше число - тем на высшем уровне глубины находится обьект в контейнере. У каждого обьекта это число должно где-то хранится, а у каждого контейнера должен быть массив с этими числами. Если эти данные нигде не хранить, то каждый раз при вызове метода sortItems() нужно это число высчитывать наново для каждого обьекта в контейнере, что не есть хорошо. Например, в примере выше - метод sortItems() вызывается каждый раз, когда двигается мышка. К сожалению, у нас динамический только класс MovieClip, но не DisplayObject и DisplayObjectContainer. Поэтому это число мы не можем прикрутить к обьекту динамически как свойство. А массив мы не можем прикрутить к контейнеру. Поэтому есть два варианта:
1. Создавать экземпляры класса IsoSorter каждый экземпляр, которого будет хранить данные лишь об одном контейнере. Так было в первой редакции статьи.
2. Создать все методы класса IsoSorter статическими. Но тогда в этом классе нужно хранить список контейнеров с данными об обьектах. Так как сейчас описано в статье.
Даже не знаю какой способ лучше..?
Старый 21.01.2012 18:48 etc вне форума
etc
 
Аватар для etc
Код:
ReferenceError: Error #1069: Property currentFrame not found on Container and there is no default value.
	at Container/onDown()[D:\IsoSortUtils\IsoSortProject\src\Container.as:72]
Старый 21.01.2012 19:02 HardCoder вне форума
HardCoder
 
Аватар для HardCoder
Спасибо, etc. Это я загнался. Уже исправил. Ссылки обновил.
Старый 21.01.2012 21:11 Dukobpa3 вне форума
Dukobpa3
 
Аватар для Dukobpa3
Ну норм, красивенько.
С парочкой моментов не согласен.
Цитата:
Полностью абстрагировать класс IsoSorter не получится. Обьясню, почему.
Цитата:
1. Создавать экземпляры класса IsoSorter каждый экземпляр, которого будет хранить данные лишь об одном контейнере. Так было в первой редакции статьи.
Ну данные о контейнере может хранить допустим сам контейнер. В чем тут проблема.

Цитата:
Второй недостаток - обьекты не могут летать в воздухе.
Чтобы понять как сортировать воздушные объекты достаточно запустить старкрафт2 с включенными метками воздушных юнитов.
Ну типа:
Изометрические координаты у юнита 2-2, но визуально мы его рисуем так как будто он находится в координатах 1-1, т.е. на клетку выше. Сортировка та же как и для наземных. А чтобы визуально отображалось верно можно как миниум двумя методами решить. Банально графику нарисовать с учетом смещения)) Или же добавить в каждый элемент такой параметр как смещение.
Старый 21.01.2012 21:28 HardCoder вне форума
HardCoder
 
Аватар для HardCoder
Код AS3:
Ну данные о контейнере может хранить допустим сам контейнер. В чем тут проблема.
Проблема в том что класс IsoSorter не может создать сам свойство для контейнера. Для этого это свойство для контейнера нужно определять заранее (сам программист должен его создать). Значит здесь уже теряется универсальность, так как можно будет запутаться. Мне то по барабану, так как все эти алгоритмы я знаю наизусть и могу их впихнуть куда угодно. Но другому программисту надо помнить что каждый раз создавая контейнер - нужно для него определять некоторое свойство, которым будет оперировать класс IsoSorter.
Идея была - сделать класс с тремя статическими методами: добавить, удалить, отсортировать, которому было бы по-барабану откуда контейнеры взялись, и что в них находится. Как не морочил голову - не могу такой универсальности достичь. Может есть у кого какие идеи?
PS: Если не заметили, в приведенном примере арку тоже можно двигать. Сделал это чтобы было понятно как ее создавать.
Старый 21.01.2012 21:35 Dukobpa3 вне форума
Dukobpa3
 
Аватар для Dukobpa3
И еще смущает метод просчета глубины.
С таким подходом у нас будет пачка клеток с одинаковой глубиной. и между собой они сортируются случайным образом. Вот как например дерево, которое в изометрии занимает одну клетку, но визуально торчит в стороны. И вот эти ветки которые торчат они могут быть один раз перед соседним объектом а в другой раз за ним.
Старый 21.01.2012 21:40 Dukobpa3 вне форума
Dukobpa3
 
Аватар для Dukobpa3
Цитата:
Идея была - сделать класс с тремя статическими методами: добавить, удалить, отсортировать, которому было бы по-барабану откуда контейнеры взялись, и что в них находится.
Я логику не совсем понимаю. Вот я пользуюсь твоим фреймворком. Раз я им пользуюсь я знаю что им пользуюсь для изометрической сортировки, и собственно нахожу вполне нормальным юзать твои классы в своих целях.

Я бы наверное сделал некий класс IsoMap() - который был бы таким вот контейнером.
В него бы всунул методы добавить, удалить, передвинуть. И всё.

И класс IsoItem() - Который был таким вот объектом.

Тот кто пользуется не задумывается бы как это реализовано, для него наружу торчит пачка публичных методов в кол-ве трех штук, что согласись вообще не много. И типа как всё отлично.
Старый 21.01.2012 21:59 HardCoder вне форума
HardCoder
 
Аватар для HardCoder
Ну, такой вариант был бы очень прост в реализации, но немного запутаннее в понимании. Как я говорил - я могу спокойно оперировать приведенными алгоритмами в любой точке кода. Но если другой разработчик захотел бы использоваться им, то я хотел подать материал как можно понятнее - без IsoMap() и без IsoItem(), так чтобы: увидел - и сразу написал свое, без расшифровки разных классов.
Кстати, на счет псевдо 3D - ты меня вдохновил . Сейчас думаю, как прикрутить к сортируемому обьекту третью координату. Здесь планирую уже использовать 2-3 класса для сортировки. Если что-то получится, может накатаю еще одну статейку (ну, и если полностью не закритикуют еще в этом блоге )
Цитата:
И еще смущает метод просчета глубины.
С таким подходом у нас будет пачка клеток с одинаковой глубиной. и между собой они сортируются случайным образом. Вот как например дерево, которое в изометрии занимает одну клетку, но визуально торчит в стороны. И вот эти ветки которые торчат они могут быть один раз перед соседним объектом а в другой раз за ним.
Не совсем понял. Стоит себе дерево - ну и пусть растет себе в ширину или в высоту. Попробуй перемещать арку возле дерева (она как раз по высоте подходит). Если ветки дерева находятся ближе к зрителю, чем арка - они будут над ней, если дальше - соответственно под ней.
Обновил(-а) HardCoder 22.01.2012 в 01:58
Старый 21.01.2012 22:05 Dukobpa3 вне форума
Dukobpa3
 
Аватар для Dukobpa3
Цитата:
без IsoMap() и без IsoItem(), так чтобы: увидел - и сразу написал свое, без расшифровки разных классов.
Их расшифровывать и не нужно. Основная задача в том чтобы программист мог рассчитывать свою математику на плоскости (изометрические координаты) и не задумываться об экранных координатах и сортировке, чтоб этим занимался движок.

Так что как минимум изометрические координаты у каждого итема наружу нужно вытягивать. Иначе это получается изометрия ради изометрии. Другими словами попросту бесполезная штука.
Обновил(-а) Dukobpa3 21.01.2012 в 22:12
Старый 21.01.2012 22:22 GBee вне форума
GBee
 
Аватар для GBee
Такие блоги повышают мое желание работать. Спасибо за арку.
 

 


Часовой пояс GMT +4, время: 21:10.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.