Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 1.0/2.0 (http://www.flasher.ru/forum/forumdisplay.php?f=93)
-   -   Некорректное перемещение плит игровой карты (http://www.flasher.ru/forum/showthread.php?t=117966)

Offi 11.11.2008 21:00

Некорректное перемещение плит игровой карты
 
Доброе время суток!
Пишу игру с плиточной картой в изометрии. При перемещении по карте двигается сама карта, а не персонаж. Все плиты находятся в массиве и перемещаются перебором массива в цикле. Есть функция, которая преобразует смещение карты на скорость в изометрическое представление(ИП). Логически все прекрасно работает, но при смещении плит со временем происходит наезд задних плит на передние, несмотря на то, что вроде как всем без исключения плитам добавляется одинаковое число к координатам и двигаться с разной скоростью они не должны! Единственное, что мне удалось обнаружить в коде возможное вызывать какие-то некорректности в перемещении это то, что результат перевода смещения координат в ИП округляется до десятых целого числа при добавлении результата к координатам плит.

Например, плита1._x=200;плита1._y=150; скорость=1; mapToScreen(скорость,0,-скорость) вернет смещение по x:1.11022302462516e-16 и y:0.707106781186547, но при смещении объекта _x+=x; _y+=y; в итоге плита1._x:200(!) плита1._y:150.7 ).

Я не силен в тригонометрии, но по-моему функция преобразования в ИП тут не при чем...Функцию позаимствовал из книги "Секреты разработки игр в МакромедиаФлешМХ" Джоба Макара, она там служила для перемещения персонажа по статической изометрической карте.

Смещение плит еле заметное в начале, но получается даже при смещении на 1 пиксель. Я трейсил _width и _height карты как до смещения так и после и результат изменялся. В моем представлении при передвижении всех плит на одинаковое расстояние: ни ширина, ни высота меняться не должны!

Буду рад любой помощи! И извините, если непонятно выразился где-то, спрашивайте!


Код AS1/AS2:

isometricAS = function ()
{
        this.theta = 30;
        this.alpha = 45;
        this.theta *= Math.PI/180;
        this.alpha *= Math.PI/180;
        this.sinTheta = Math.sin(this.theta);
        this.cosTheta = Math.cos(this.theta);
        this.sinAlpha = Math.sin(this.alpha);
        this.cosAlpha = Math.cos(this.alpha);       
}
isometricAS.prototype.mapToScreen = function (xpp, ypp, zpp)
{
        var yp = ypp;
        var xp = xpp*this.cosAlpha+zpp*this.sinAlpha;
        var zp = zpp*this.cosAlpha-xpp*this.sinAlpha;
        var x = xp;
        var y = yp*this.cosTheta-zp*this.sinTheta;
        //var z = zp*this.cosTheta+yp*this.sinTheta;
        return [x, y];
}
 
var iso = new isometricAS();
var spd:Number = 1; // Скорость движения
switch(direction) // Определение скорости по Х и У в зависимости от направления движения
{
        case UP:
        Xspd=0;
        Yspd=spd;
        break;
        case DOWN:
        Xspd=0;
        Yspd=-spd;
        break;
        case LEFT:
        Xspd=spd;
        Yspd=0;
        break;
        case RIGHT:
        Xspd=-spd;
        Yspd=0;
        break;
        default:
        break;
}
 
for(var i=0;i<mapList.length;i++)
        {
                var isoXY = iso.mapToScreen(Xspd, 0, -Yspd); // Перевод данных в изометрическое представление
                var iX=isoXY[0];
                var iY=isoXY[1];
                mapList[i]._x+=iX;
                mapList[i]._y+=iY;
        }


scarbo 11.11.2008 21:39

Ну так округлите

Offi 11.11.2008 22:09

при округлении результат еще плачевней:( некорректное смещение ещё заметней и движение карты происходит явно в не изометрических направлениях!

Wolsh 11.11.2008 23:45

Ну вообще при движении всегда происходит округление координат, и этого Вы никак не избежите. Выход смещать на целый пиксель Вас вряд ли устроит, изображение будет "дергаться". Для начала я бы посоветовал попробовать вычислять новую координату плиты не из ее собственной, уже округленной и неправильной, а вычислить например _у только нижнего ряда, а всех верхних - вычитая из нижнего высоту плиты. Улавливаете?))) Она константна, и наезда не будет.

Offi 12.11.2008 00:16

Wolsh
дело говорите! я не могу понять почему плиты наезжают друг на друга если к каждой плите применяется одинаковое(!) смещение...такое ощущение, что смещение для плиты №1 не такое как для плиты №-n...если ряд за 1 кадр сдвигается на 5 шагов, то длинна его должна остаться той же, шаги то у элементов ряда одинаковые...а в моем варианте получается что у кого-то не такой шаг как у другого...

при том правый ряд(сверху-вниз) непоколебим и не поддается на провокацию глюка, а остальные ведут себя неподобающе. Больше всего смещение наблюдается начиная с левой верхней плиты, не зависимо от направления движения(стабильный ряд тоже стоит вне зависимости от направления). Подумал, может в цикле каждый раз(неизвестным образом) генерируется разное число: вынес расчет смещения из цикла:

Код AS1/AS2:

var isoXY = iso.mapToScreen(Xspd, 0, -Yspd); 
var iX=isoXY[0];
var iY=isoXY[1];
for(var i=0;i<mapList.length;i++)
        {
                mapList[i]._x+=iX;
                mapList[i]._y+=iY;
        }

но не помогло:(

scarbo 12.11.2008 00:35

Цитата:

правый ряд(сверху-вниз) непоколебим
Ну так от него и считайте.

Offi 12.11.2008 00:40

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

scarbo 12.11.2008 00:43

Потому что Флеш так дроби считает

Offi 12.11.2008 00:49

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

scarbo 12.11.2008 01:30

Смотря,как считать...

Wolsh 12.11.2008 11:54

Чёто Вы меня совсем запутали. Может, выложите свфку хотя бы посмотреть, как у Вас плиты двигаются

Hidest 12.11.2008 13:27

А нельзя плиты просто загонять в отдельный клип и двигать один раз только его.... тогда все плиты сдвинутся на одно и то же расстояние...

Offi 12.11.2008 20:29

Wolsh
swf-ку посмотреть тут, повозите карту туда-сюда кнопками клавиатуры. чем дольше потягаете - тем больше деформация будут заметна.

Hidest
Можно конечно, я сначала так и думал сделать, но карта будет динамическая, т.е. подгружать новые плиты когда крайние плиты сдвинутся на свой же размер...хотя, так можно и общий сдвиг отлавливать, даже наверное правильней...:)

Wolsh 12.11.2008 21:25

Ага, посмотрел. Ну и чем Вам мой метод не понравился - не верите что всё будет ОК?
Вычисляйте координату нижней плиты, а все остальные - относительно нее. Поймите что сбой происходит при считывании координаты плиты, которая всегда округляется до сотых. И этот сбой будет всегда накапливаться, потому что новое значение Вы берете опять от неправильного. А так сбой будет, но только неизбежный и для первой плиты, а все остальные плиты будут вставать ровно с нижней.

Offi 12.11.2008 22:14

метод хороший и я понимаю, что всё будет ок, но ведь это сколько операций будет выполнено, чтоб сместить все плиты:( если так 2 операции(присвоение х, у), то там еще и расчет х,у... сейчас попробую:напишу расчёт, увеличу карту и посмотрю на производительность метода.

Добавлено через 35 минут
если бы карта была не изометрической, то метод выглядел бы так?
Код AS1/AS2:

 mapList[0]._x+=dx;
        mapList[0]._y+=dy;
 
        for(var i=1;i<mapList.length;i++)
        {
                ddx=mapList[0]._x+mapList[i].x*cellWidth; // mapList[i].x - порядковый номер в горизонтальном ряду
                ddy=mapList[0]._y+mapList[i].y*cellHeight; // mapList[i].у - порядковый номер в вертикальном ряду
                mapList[i]._x=ddx;
                mapList[i]._y=ddy;
        }


NoCD 13.11.2008 10:43

Я подобными вещами давно занимаюсь и вам бы рекомендовал, так же как рекомендовалось в посте №12. Загоните все плитки в один клип и двигайте клип. Так у вас будет только пять точек вычисления, это верхний-левый, верхний-правый, нижний-левый, нижний-правый и сам пресонаж, а если есть npc на карте, то они сами по себе относительно карты будут двигаться.
Если подумать, то можно еще дальше пойти.Например, что бы карта не вся была загружена, то можно невидимую часть держать в tile._visible и только тогда, когда за одну клетку до попадения ввидимую зону тайл ставим в положение tile._visible=true. и вычисляем всё это общей формулой TempX=Math.floor(this._x/размеры тайла).Так же и по Y. Это не сложно сделать и карта не нагружена. А что бы сделать карту громадных размеров, то просто стоит разделить её на сегменты, на сектора, на зоны(как вам удочней это называть).Например если у вас видимое поле скажим 20х20, то сектор можно сделать размером 40х40 или 60х60, как удобней. И соответственно вычислять например, если длина сектора в 60 клеток,то при достижении видимой области 58-ой клетки подгружаем другой сектор либо другой клип.
Вот так.

Wolsh 13.11.2008 11:01

Да, что-то вроде того, только я бы оптимизировал это дело, чтоб не дергать каждый раз массив.
И, если не секрет, какая разница - изометрическая, не изометрическая... Я даже какие-то косинусы у Вас там видел... Зачем это? Я было подумал, что у Вас угол меняется, ну типа высоту камеры менять можно))) А если не меняется, то изометрия == 2D и не мучайте себя тригонометрией, она тут не нужна. И конечно, в таком случае проще было бы все засунуть в один мувик (если не учитывать будущее взаимодействие героя с плитами)
Вы меня заразили, сижу рисую ячейки)))))))

Hidest 13.11.2008 13:36

Если все кинуть в один клип не будет проблем с взаимодействием героя с плитами - с программной точки зрения какая разница, орудуем мы clip1...clipN, или world.clip1...world.clipN. Конкретно тайловыми играми не занимался, но в тех проектах, которые доводилось делать - вполне нормальный путь, который упрощает многие задачи (для примера - возможность одним действием изменить масшатаб карты, типа обзора с бОльшей высоты).

Offi 13.11.2008 22:01

NoCD
у меня карта всего уровня лежит в массиве, пока это только информация о типе ячейки(кадр). есть видимая область, к примеру 20х20, при сдвиге карты на размер ячейки - ненужный ряд удаляется, а нужный подгружается в нужное место. не вижу смысла, пока, разбивать карту на сегменты. в массиве может быть карта хоть 1000х1000, при необходимости строить новый ряд,заносить его в массив видимой области и наделять ячейки свойствами из глобального массива. по-моему это достаточно оптимальней чем работать с секторами. а для того чтоб невидно было скачков удаления и подгрузки рядов я рисую маску по контуру карты минус размеры ячейки и подгрузка вообще не заметна. но все же, возможно, придеться делать разбивку на секторы, когда будет работа с объектами на карте, посмотрим.

Wolsh
а как бы Вы это оптимизировали, если не секрет?
изометрическая, ибо движения вверх, вниз, влево, вправо надо ведь проводить в соответствии с положением карты(наклон на 30градусов и поворот на 45) "Косинусы" как раз вычисляют как объекты должны двигаться по основным направлениям с учётом положения карты. возможно я реализую, также пол разной высоты(ступеньки, горки и прочее), для этого и нужны эти расчёты. я удовлетворил Ваш интерес? или неправильно вопрос по поводу изометрии понял...?

Wolsh 14.11.2008 01:03

Цитата:

а как бы Вы это оптимизировали, если не секрет?
Посмотрите на свой код в 15-ом посте.
Сколько раз там повторяется выражение mapList[i] и mapList[0]?
На протяжении витка цикла mapList[i] это один и тот же объект, как и mapList[0] - какой резон каждый раз плееру обращаться к массиву, отыскивать там свойство с индексом i и возвращать его, если этот объект известен? Сохраните ссылку на него в переменной и используйте в функции. И достаточно просто сохранить в переменных сами значения _x и _у для mapList[0], а не лазить каждый раз в массив, чтобы найти объект и узнать его параметры - когда такое делается несколько раз за виток цикла, это очень не оптимально. В конечном итоге Вы совершите несколько сотен совершенно лишних операций.
Что касается изометрии - повторюсь, тригонометрия не имеет к ней никакого отношения, по крайней мере здесь уж точно. Для того, чтобы, сдвинув объект на 10 пикселей вправо, сдвинуть его на 10/2 = 5 пикселей вверх, косинусы не нужны. Здесь отношение X к Y постоянное, все углы зафиксированы. Нет НИКАКОЙ необходимости их пересчитывать. Если бы динамически менялся хоть один угол - обзора камеры, или угол движения объекта, был бы смысл. А так это просто константы.

Пример бага подсветки для админов. К сообщению НЕ ИМЕЕТ НИКАКОГО ОТНОШЕНИЯ!!!!)))

Код AS1/AS2:
Код AS1/AS2:

 <font color="#6699cc">thisfont>.megadeth.<font color="#6699cc">gotoAndPlayfont><font color="#66cc66">(font><font color="#cc66cc">16font><font color="#66cc66">)font>;
<font color="#6699cc">tracefont><font color="#66cc66">(font>"БАГИ<font color="#66cc66">!!!font>"<font color="#66cc66">)font>;


Offi 14.11.2008 18:59

Wolsh
если Вам не трудно, объясните на примере...моё восприятие, к сожалению, не достаточно полно позволяет понять как это реализуется :( сохранять ссылку на каждый элемент(плиту) в отдельной переменной? но ведь массив и есть подборка ссылок на плиты...и через массив удобнее, как мне кажется, навигация по этим ссылкам...на счёт mapList[0], вроде, понятно. на счёт изометрии, наконец-то, понял! спасибо за разжевывание :) действительно, тригонометрия никчему...

Добавлено через 2 часа 15 минут
по сути, отмена тригонометрии решила проблему с некорректным перемещением плит! Всем спасибо за участие и советы! :)
Wolsh, Вам отдельное спасибо! Буду так же признателен, если приведете пример с оптимизацией процесса!

Wolsh 15.11.2008 00:48

OK, поехали.
Ваш код:
Код AS1/AS2:

mapList[0]._x+=dx;
mapList[0]._y+=dy;
for(var i=1; i<mapList.length; i++)
{
        ddx=mapList[0]._x+mapList[i].x*cellWidth;
        ddy=mapList[0]._y+mapList[i].y*cellHeight;
        mapList[i]._x=ddx;
        mapList[i]._y=ddy;
}

Оптимальный код:
Код AS1/AS2:

// сохраняем х и у нулевого клипа в переменных
var mc0x:Number = (mapList[0]._x+=dx);
var mc0y:Number = (mapList[0]._y+=dy);
for(var i=1; i<mapList.length; i++)
{
        // сохраняем ссылку на mapList[i] в переменной
        var mc:MovieClip = mapList[i];
        // все, массив больше не дергаем
        mc._x = mc0x + mc.x*cellWidth;
        mc._y = mc0y + mc.y*cellHeight;
}

В этом кусочке из трех строк Вы можете избежать как минимум 10 лишних операций. Если учесть, что этот кусочек выполняется 30 раз в секунду - ну считайте сами))))
Всегда, когда можно и имеет смысл, храните во внутренних для функции переменных (а если можно и нужно, то во внешних "общих") прямые ссылки на объекты, не заставляйте плеер их разыскивать по всей губернии каждый раз. Для игры важна любая возможность оптимизации.
А в идеале, для такого большого проекта, надо уже учиться писать классы.
У Вас получится. Чем раньше начнете, тем лучше. Тем более что уже вышли прекрасные книги как по АС2, так и по АС3, на русском. Удачи!

Добавлено через 9 минут
А, блин, забыл - не просто 10 операций 30 раз в секунду, а еще и для каждого из (50?) клипов. 1500 операций в секунду. Как минимум.

Offi 17.11.2008 20:04

Спасибо огромное)) Все чисто и ясно!:)

NoCD 23.11.2008 10:59

Вложений: 1
Вобщем вот такой вариант у меня полчился.
Если делать по моему примеру
управление картой курсором

AlexStukoff 03.12.2008 19:07

Не забывайте о том, что все координаты объектов задаются в твипсах = это 1/20 пиксела.
Изменять координату меньше чем на 0.05 бессмысленно, т.к. эта величина будет округлятся до 0.
Это на тот случай, если смещения плит гуляют примерно около такой величины за одну итерацию. :)


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

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