Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Повернуть объект Nое число раз (http://www.flasher.ru/forum/showthread.php?t=132191)

me2 06.11.2009 03:17

Повернуть объект Nое число раз
 
Возникла небольшая проблемка, а именно: при повороте объекта на угол формируемый некторым вектором, объект поворачивается до 2П, далее угол скидывается на -2П, и плавно уходит в ноль. Цикл повторяется, объект крутиться.
Только это ая-яй как плохо, ибо нужно чтоб крутилось от -nП до nП
(требуется знать сколько витков намоталось или наоборот размоталось).
На сегодняшний день, решение достаточно простое, есть некая переменная к которой прибавляется либо отнимается шаг угла.
Сей алгоритм в некторых случаях уходит в погрешность и со временем вырастает в серьёзную проблему...
Может быть кто-нибудь с таким сталкивался и красиво решил всё это дело?...

SamFR 06.11.2009 04:24

ммм... ну ведь rotation это тоже некоторая переменная типа Number, и точность её не выше точности любой другой переменной типа Number. Ну ладно, геттер это, но суть от этого не меняется.

Проблема тут не в другой переменной, а в том, что шаг угла прибавляется итеративно, и погрешность накапливается. Так будет не только во флэше, но и в любой другой системе с ограниченной памятью. Поэтому подходить нужно с другой стороны: пусть угол поворота в момент времент t вычисляется как a*t + b. Теперь запоминаем время начала вращения, и в каждом кадре вычисляем прошедшее с этого момента время. Для всего этого есть глобальная функция getTimer(). Ну а далее, думаю, понятно :)

proxiServer 06.11.2009 10:37

Если значение с 2Пи скидывается на минус 2Пи, это, как мне кажется, ошибка алгоритма уже. По поводу накопления ошибки, это конечно возможно. Если вы крутите объект туда сюда раз эдак 10^8. Тогда может и накопиться. А в вашем случае, опять же, думаю что навран алгоритм.

А что конкретно и как крутится?

Как вариант
Код AS3:

 
// проблема с переходом -180...180
                    if (angle>180){
                            angle-=360;
                    } else if (angle<-180){
                            angle+=360;
                    }

Решение взял из статьи мерлина про игру с астеройдами. Она прилеплена.

SamFR 06.11.2009 16:25

proxiServer, вы забыли учесть, что прибавление угла происходит в каждом кадре, а их 30 в секунду. Так что ошибка очень даже накапливается, можете проверить.

Поэтому, если важно, чтобы объект не просто крутился (перемещался), а оказывался в определённый момент в определённом положении, то про последовательное прибавление угла (координаты) нужно забыть.

dsQuadro 06.11.2009 16:31

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

SamFR 06.11.2009 16:41

Да зачем же все эти ухищрения? Всё ж просто:

Код AS3:

//перед началом вращения
 
var t0:uint = getTimer(); //момент начала вращения
var T:uint = 10000; //полное время вращения (в мс.)
 
//каджый кадр
 
var t:Number = 2*(getTimer() - t0)/T - 1; //от -1 (в начале вращения) до 1 (в конце)
object.rotation = N*t*Math.PI; //от -N*PI в начале вращения до N*PI в конце

Таким же макаром можно, при желании, заставить угол изменяться по синусоиде, например. И про накопление погрешности можно забыть.

proxiServer 06.11.2009 16:45

SamFR, могу поверить) но не буду. там ей накапливаться негде. либо ее порядок настолько мал, что 30 лет будете крутить и может на пол-градуса ошибетесь. Врет алгоритм. Ну или пример покажите пожалуйста. Может какие особенности самого флеша.

SamFR 06.11.2009 17:01

Код AS3:

var t:Number = 0;
 
for(var i:int = 0; i < 600; i++){
        t += 0.01;
}
 
trace(t);

Да, ошибка маленькая, но основная проблема не в этом.

Скажите, что вы будете делать, если нужно, чтобы за 3, например, секунды, объект повернулся на N*PI радиан? Ведь частота кадров ролика не всегда равна заданному числу (а точнее, почти всегда не равна). Мало того, она непостоянна по времени, и зависит от того, сколько заняла отрисовка и выполнение скрипта.

me2 06.11.2009 19:36

Цитата:

Сообщение от SamFR (Сообщение 863800)
Да зачем же все эти ухищрения? Всё ж просто:

Код AS3:

//перед началом вращения
 
var t0:uint = getTimer(); //момент начала вращения
var T:uint = 10000; //полное время вращения (в мс.)
 
//каджый кадр
 
var t:Number = 2*(getTimer() - t0)/T - 1; //от -1 (в начале вращения) до 1 (в конце)
object.rotation = N*t*Math.PI; //от -N*PI в начале вращения до N*PI в конце

Таким же макаром можно, при желании, заставить угол изменяться по синусоиде, например. И про накопление погрешности можно забыть.

К чему-то подобному бесконечно стремятся мои умозаключения. Не совсем понятен T=10000; чуть подробней можно?

Еще раз про задачу.
Пользователь накручивает некоторый вектор Nое кол-во раз, может совершить хоть 20000 витков, и в этоге получится какой-то бешеный угол в 34234Пи+отступ
И вот на этот угол совершенно не торопясь будет поворачиваться объект. (r+=(endR-r)*speed)
Причём чем больше кол-во витков тем "туже" идёт поворот (скорость уменьшим), но это уже лирика =)

P.s.
немного пояснений: нет проблемы от -180 до 180, преобразовать это не составляет труда, есть проблема, что после 360 идёт 0 а не 361 и т.д.
Ибо при "мгновенном" повороте что 360 что 0 - одно и тоже, а при динамическом, думаю понятно как всё происходит.

SamFR 06.11.2009 23:20

Цитата:

Сообщение от me2 (Сообщение 863862)
Не совсем понятен T=10000; чуть подробней можно?

T – это время, в течение которого будет продолжаться вращение (назовём его полное время). Так как getTimer() даёт время в миллисекундах, то для удобства (чтобы всё время не делить начальное время на 1000) полное время также задаётся в миллисекундах.

Полное время нужно, во-первых, для того, чтобы привести текущее время к заданному отрезку отрезку (в моём примере (-1, 1), можно к любому другому, как вам удобно). А, во-вторых, чтобы определить момент окончания вращения. Таким образом, в каждом кадре нужно проверять текущее время вращения, которое равно getTimer() - t0. Вычитать t0 нужно для того, чтобы время шло с 0, так как getTimer() возвращает время, прошедшее с момента запуска плеера. Как только величина getTimer() - t0 превзойдёт T, то в последний раз вычисляем угол для времени T, а затем заканчиваем анимацию (путём отписывания от события ENTER_FRAME, либо установки флага, как вам больше нравится).

Цитата:

Сообщение от me2 (Сообщение 863862)
Еще раз про задачу.
Пользователь накручивает некоторый вектор Nое кол-во раз, может совершить хоть 20000 витков, и в этоге получится какой-то бешеный угол в 34234Пи+отступ
И вот на этот угол совершенно не торопясь будет поворачиваться объект.

Смотрим пример, который я вам приводил. Задаём N, исходя из того, сколько витков пользователь совершил (N не обязательно должно быть целым). Засекаем t0 и запускаем анимацию по тем формулам, что я привёл. Как только перешли за T, поворачиваем объект на угол, вычисленный для времени T и останавливаем анимацию. По-моему, всё просто :)

Можно (и даже лучше) взять не такую формулу, а что-то типа вашОбъект.rotation = angle0 + (angle1 – angle0)*t/T, где angle0 – начальный угол поворота в радианах, angle1 – конечный угол поворота в радианах, t = getTimer() – t0 задаёт текущее время.

Цитата:

Сообщение от me2 (Сообщение 863862)
Причём чем больше кол-во витков тем "туже" идёт поворот (скорость уменьшим), но это уже лирика =)

Это как раз-таки можно сделать, задавая перед запуском анимации T в зависимости от нужного количества витков. Чем больше будет полное время вращения, тем меньше будет скорость, естественно.


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

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