Просмотр полной версии : Баг, мистика(?) с программным изменением координат MovieClip
AlexStukoff
18.01.2008, 19:30
Очень простой пример. Рассмотрите пожалуйста.
В событии onLoad устанавливается координата _y = 0;
В событии onEnterFrame увеличивается координата на 0.05.
Увеличивается... до величины 2.15. После этого операция сложения работать отказывается.
Пускалось на восьмерке.
onEnterFrame = function()
{
s1_mc._y += 0.05;
trace(s1_mc._y);
}
onLoad = function()
{
s1_mc._y = -0.05;
}
__y = 0;
onEnterFrame = function()
{
__y = __y + 0.05
s1_mc._y = Math.floor(__y);
}
Так получится)
AlexStukoff
18.01.2008, 20:25
Спасибо за ответ, если бы все было так просто :)
В MovieClip на самом деле растр в настройках которого стоит AllowSmoothing. Смысл в том, что картинка ооооооочень медленно опускается.
Ну вот... опускается... до 2.15. А потом перестает.
В ходе исследований оказалось что растр ни при чем - дело в коорждинатах объекта MovieClip как такогого. На этом мысль остановилась.
Хочется ведь не преодолеть (я и сам нашел решение, прибавлять не 0.05 а 0.051 :) ), а понять почему так.
aQuestion
18.01.2008, 20:32
ну, видать после сложения координата округляется неудачно, и флеш думает, что количество 1/20х не должно инкрементится.
Дело в дробных координатах. Приведенный мною код для данного исходника заработал. Выкладывать не буду, так как у меня flash cs3.
1. Все координаты флеша задаются в твипсах (1/20 пикселя), значит все координаты должны быть кратны 0,05. А _y - это геттер/сеттер, а не прямое обращение к координатам
2. У флеша, как и у многих языков, точность математических вычислений с дробными числами не идеальная.
Изменим код
onEnterFrame = function () {
s1_mc._y += 0.05;
var z:String = " = ";
if (s1_mc._y > 2.15) {
z = " > ";
} else if (s1_mc._y < 2.15) {
z = " < ";
}
trace (s1_mc._y + z + " 2.15 " + " | " + (2.15 - s1_mc._y));
};
s1_mc._y = 1.95;
и получим
2 < 2.15 | 0.15
2.05 < 2.15 | 0.0999999999999996
2.1 < 2.15 | 0.0499999999999998
2.15 = 2.15 | 0
2.15 = 2.15 | 0
2.15 = 2.15 | 0
...
Как видим, в какой-то момент разница была не кратным 0,05 (строчка 2 и 3), это значит, что _y был равен не 2.05 или 2.1, а чуть-чуть-чуть больше, но на столько, что флеш отбрасывал при выводе. Причина эта в пункте 2.
В какой-то момент ошибка накапливается и флеш округляет значение, чтобы оно было кратным 0,05.
Исходя из трейсов, можно предположить, что при сложении 2.15 + 0.05 результат опять не равен 2.2, а меньше и флеш округляет до 2.15
ps.
Еще один кодonEnterFrame = function () {
var y = s1_mc._y + 0.05;
s1_mc._y = y;
trace (y + " " + (s1_mc._y - y));
};
s1_mc._y = 2.0;
И трейс к нему
2.05 4.44089209850063e-16
2.1 0
2.15 0
2.2 -0.0499999999999998
2.2 -0.0499999999999998
2.2 -0.0499999999999998
2.2 -0.0499999999999998
AlexStukoff
19.01.2008, 13:58
Спасибо за столь развернутый ответ, про твипсы слышал, но face2face както не приходилось столкнуться.
Поизучаю еще сам этот феномен, может еще чтонить откопаю.
Но в итоге получается, что задавать смещение на величину меньше твипса (т.е. 0.05) нет смысла в приницпе? т.е. все равно округлится либо до 0 либо до 0.05 :)
Дополнение: Окраугляет ВСЕГДА в меньшую сторону. Т.е. изменение MovieClipa на величину меньшую 0.05 округлится в 0. Мало того, даже увеличивая именно на 0.05 нельзя быть уверенным... вдруг интерпретатор решит представить 0.05 как 0.049999999999
Поэтому СОЛЮШЕН
1. Хранить координаты MC в отдельной переменной Number чтобы избежать выкрутасов с округлением координат.
2. Так как Number один хрен глючит (как я уже писал 0.05 превращается в унылое непотребство 0.049999999) то мы его заборем с помощью старого трюка с разрядами.
var s1mc_x:Number = 0;
onEnterFrame = function()
{
s1mc_x = (s1mc_x * 100 + 5)/100;
s1_mc._x = s1mc_x;
}
а еще лучше увеличивать координату на 0.51 :)
var a:Number = 2.15
var b:Number = 0.05
var c:Number = a+b
trace(c) >> 2.2
var a:Number = 2.15
var b:Number = 0.00005
onEnterFrame=function(){
a+=b
trace(a)
}
>>
2.15005
2.1501
2.15015
2.1502
2.15025
2.1503
2.15035
2.1504
2.15045
2.1505
2.15055
Это к тому, что с математикой все у него в порядке. А проблема на самом деле заключается в setter/getter method'e _x/_y вот там и идет округление, которое дает infinite loop.
удачи.
Это к тому, что с математикой все у него в порядке.
var a:Number = 7;
for (var i:Number = 0; i < 20; i++) {
a = a + .1;
trace (a);
}7.1
7.2
7.3
7.4
7.5
7.6
7.7
7.8
7.9
8
8.1
8.2
8.3
8.4
8.49999999999999
8.59999999999999
8.69999999999999
8.79999999999999
8.89999999999999
8.99999999999999
Так и должно быть?:)
Mr. Fixit
24.01.2008, 01:14
а че так показывает?(
Уже 100 раз расказывалось.
Про _alpha осталось ещё вспомнить :)
Да, и это, мы переезжаем.
так действительно должно быть и флеш тут ни причем. Не будем забывать, что числа в компьютере представлены в бинарном виде и многие конечные десятичные дроби имееют бесконечное двоичное представление. Дробь 0.1 периодична в двоичной системе 0,0(0011), поэтому обрезается в зависимости от разрядности компьютера, от этого и накапливается погрешность.
С какой стати она переодична?
двоичное представление 0.1 является периодической дробью. что значит с какой стати?
Ах, в двоичной, я первоначально пропустил это слово, видимо запятая сбила с толку:D
Нокс об этом подробно рассказывал (http://flash-mx.ru/forum/topic_show.pl?tid=167)
Работает на vBulletin ® версия 3.7.3. Copyright ©2000-2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Copyright © 1999-2008 Flasher.ru. All rights reserved.