Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Тригонометрия. Ошибка в условии изменения дельты угла в радиальной системе координат. (http://www.flasher.ru/forum/showthread.php?t=206096)

InSelecto 12.01.2014 22:02

Тригонометрия. Ошибка в условии изменения дельты угла в радиальной системе координат.
 
Вложений: 2
Добрый день!

Проблема в следующем:

В прикрепленном ролике подвижный корабль (ship) летит к синему указателю цели (pointer), который перемещается вокруг неподвижного корабля (target).
Мне нужно, чтобы при значении угла α < 90 градусов (т.е. Math.PI/2) синий указатель менял направление перемещения на противоположное.
Угол α на картинке обозначен.

Вот код функции ответственной за перемещение указателя:

Код AS3:

function MovePointer(ship:Object, targ:Object, point:Object, R:Number, DAngle:Number):Number
{
        var angle = Math.atan2(point.y - targ.y, point.x - targ.x);
 
        if ( Math.abs( Math.PI-( angle - (Math.PI+Math.atan2(ship.y - targ.y, ship.x - targ.x)) ) ) < Math.PI/2 )
        {
                DAngle=-DAngle;
        }
 
        angle += DAngle;
 
 
        point.x = targ.x + R * Math.cos(angle);
        point.y = targ.y + R * Math.sin(angle);
 
        return DAngle;
}

Вложение 30363

Вложение 30364

InSelecto 12.01.2014 23:24

Вложений: 1
Изменил алгоритм на:

Код AS3:

function MovePointer(ship:Object, targ:Object, point:Object, R:Number, DAngle:Number):Number
{
        var angle = Math.atan2(point.y - targ.y, point.x - targ.x);
        trace (Math.atan2(ship.y - targ.y, ship.x - targ.x) - angle);
 
        if (
                (
                Math.abs( Math.atan2(ship.y - targ.y, ship.x - targ.x) - angle ) < (Math.PI/2 + 2*Math.abs(DAngle))
                        )
                                ||
                (
                Math.abs( Math.atan2(ship.y - targ.y, ship.x - targ.x) - angle ) > (Math.PI*3/2 - 2*Math.abs(DAngle))
                        )
                )
        {
                DAngle=-DAngle;               
        }
 
        angle += DAngle;
 
 
        point.x = targ.x + R * Math.cos(angle);
        point.y = targ.y + R * Math.sin(angle);
 
        return DAngle;
}

-стал скакать как надо но все равно после определенного момента глючит (см. новое приложение):
Вложение 30365

maxkar 13.01.2014 00:33

Примерно так должно быть:
Код AS3:

const product : Number = (point.y - targ.y) * (ship.y - targ.y) + (point.x - targ.x) * (ship.x - targ.x);
if (product > 0) {
  DAngle = -DAngle;
}

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

InSelecto 13.01.2014 00:45

Цитата:

Сообщение от maxkar (Сообщение 1157084)
Примерно так должно быть:
Код AS3:

const product : Number = (point.y - targ.y) * (ship.y - targ.y) + (point.x - targ.x) * (ship.x - targ.x);
if (product > 0) {
  DAngle = -DAngle;
}

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

Красота, но все равно после 2го отскока глючит: см. мой пост выше с новым приложением - там именно эта ситуация и с вашим алгоритмом.

Как вы к этому выражению пришли? "(point.y - targ.y) * (ship.y - targ.y) + (point.x - targ.x) * (ship.x - targ.x)"
Если не сложно - можно фото вычислений на бумаге? Или ссыль какую)

maxkar 13.01.2014 01:15

Цитата:

Сообщение от InSelecto (Сообщение 1157085)
Красота, но все равно после 2го отскока глючит: см. мой пост выше с новым приложением - там именно эта ситуация и с вашим алгоритмом.

А зачем ваш метод возвращает DAngle? Вы его там потом ничему заново не присваиваете и в новую итерацию не передаете? У меня подозрения, что угол потом резко (за счет движения корабля) попадает в область "< 90 градусов" и выйти из нее уже не может (так и меняется на противоположный).

Мне кажется, нужно менять алгоритм. Пока угол тупой - target движется в предыдущем направлении. Если же угол острый (или прямой) - затупляем его вне зависимости от предыдущего движения. Для этого смотрим на знак

Код AS3:

if (product < 0) {
  const crossProduct : Number = (point.y - targ.y) * (ship.x - targ.x) - (point.x - targ.x) * (ship.y - targ.y);
  DAngle = (crossProduct <= 0 ? -1 : 1) * Math.abs(DAngle);
}

Может быть, там условие ">=0" вместо "<=0".

Цитата:

Сообщение от InSelecto (Сообщение 1157085)
Как вы к этому выражению пришли? Или ссыль какую)

Не люблю считать в углах, если все можно посчитать в векторах. В углах очень много граничных случаев. Ваша задача проверки угла на тупизну эквивалентна проверке знака косинуса угла. А проверка знака косинуса угла эквивалентна проверке знака скалярного произведения векторов (скалярное произведение равно произведению длин на косинус угла между ними). Формула product - формула скалярного произведения векторов по их коордиантам в ортонормированном базисе. Формула crossProduct - "длина" векторного произведения векторов, ее знак определяет направление поворота между векторами (в каком случае положительно - не помню). Т.е. при изменении порядка веткоров "векторное произведение" поменяет знак. Пока точные углы не нужны, векторного произведения вполне достаточно для качественной оценки (поворот по/против часовой стрелки).

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

InSelecto 13.01.2014 01:17

Цитата:

Сообщение от maxkar (Сообщение 1157086)
Не люблю считать в углах, если все можно посчитать в векторах. В углах очень много граничных случаев. Ваша задача проверки угла на тупизну эквивалентна проверке знака косинуса угла. А проверка знака косинуса угла эквивалентна проверке знака скалярного произведения векторов (скалярное произведение равно произведению длин на косинус угла между ними). Формула product - формула скалярного произведения векторов по их коордиантам в ортонормированном базисе. Формула crossProduct - "длина" векторного произведения векторов, ее знак определяет направление поворота между векторами (в каком случае положительно - не помню). Т.е. при изменении порядка веткоров "векторное произведение" поменяет знак. Пока точные углы не нужны, векторного произведения вполне достаточно для качественной оценки (поворот по/против часовой стрелки).

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

Уже нашел) Читаю.

Добавлено через 11 минут
Цитата:

Сообщение от maxkar (Сообщение 1157086)
А зачем ваш метод возвращает DAngle? Вы его там потом ничему заново не присваиваете и в новую итерацию не передаете? У меня подозрения, что угол потом резко (за счет движения корабля) попадает в область "< 90 градусов" и выйти из нее уже не может (так и меняется на противоположный).

Передаю:
Код AS3:

DeltaAngle=MovePointer (Player1, Target1, Pointer1, PointerRadius, DeltaAngle);


dimarik 14.01.2014 22:52

Прошу прощения за занудство, но по решению комиссии IEEE от 30.02.1901 года, термин "радиальная" (Система Координат) заменен на полярная (СК).


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

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