Уважаемые программисты! Обнаружил такую особенность в работе программы. Есть список, в который записаны указатели на частицы.
TFragment = record position, speed, direction : TD3DVector; life, scale, fps_dis : single; state : boolean; color : TRGBA; end; PFragment = ^TFragment;
Каждая частица существует определенное время, после чего state меняется на false
Когда срабатывает таймер, программа перебирает список и ищет частицу с state=false. Если таковая есть, частица перезапускается. В ином случае создается новая частица:
procedure TPowerEngine.launch_fragment; var i : integer; fragm : PFragment; flag : boolean; begin flag := false; if (objects.Count > 0) then for i := 0 to objects.Count - 1 do begin fragm := objects.Items[i]; if ( not fragm.state) then begin RestartFragment( fragm); flag := true; break; end; end; if ( not flag) then begin new( fragm); RestartFragment( fragm); objects.Add( fragm); end; end;
В листинге есть вызов RestartFragment(fragm). Вот эта процедура:
procedure TPowerEngine.RestartFragment(var fragm_ : PFragment); var r_vector : TD3DVector; begin fragm_.position := position; fragm_.life := 0.0; fragm_.state := true; fragm_.scale := scale; fragm_.fps_dis := dis_3d( fragm_.position, v_points.pnt1); //дальше заполнение других полей - не так важно end;
Одним словом, строчка
fragm_.position := position;
(position - поле объекта TPowerEngine) глючит. Это проявляется в некорректном подсчете поля life частицы после ее перезапуска (т.е. когда перебирается список, ищется частица со state=false и она перезапускается). Если убираю эту строчку, работа программы меняется, чего, вообще-то быть не должно.
Хотелось бы услышать некоторые идеи относительно этого глюка.
В коде явных ошибок не видно. И непонятно что ты хотел сказать "глючит. Это проявляется в некорректном подсчете поля life частицы после ее перезапуска". Так что нужны дополнительные сведения что глючит конкретно и как.
Так же замечу что fragm_ передаётся как var - это судя по коду не нужно делать, не ошибка, но неэффективность. Достаточно просто передать указатель как есть.
может, в цикле обработки частиц ошибка( например обрабатываются частицы с state= false)?
А идеально было бы если б готовый пример можно было скачать и откомпилировать.
что глючит конкретно и как
Создается частица. Поле life увеличивается каждый такт: 0 0.1 0.2 0.4 и т.д. до 2.0 секунд. После этого state меняется на false и частицы до перезапуска обновляться не должны. Там есть проверка типа
if fragm_.state then update_fragment(fragm_);
Дальше постепенно происходит перезапуск частицы. После этого поле life (я контролировал 4-ю частицу) меняется: 1.7 1.8 1.7 и т.д. Либо как 0.2 0.3 0.2 и т.д. Хотя при перезапуске поле life обнуляется.
Иными словами, строчка
fragm_.position := position;
меняет результат работы объекта со списком частиц. Точнее, влияет на содержимое полей записей.
Закрываю эту строчку кавычками, и поле life 4 частицы начинает на любом перезапуске меняться от 0 до 1 и 2 сек. Т.е. как и следует.
Выкладывать пример полностью сложно - это часть большой программы.
Обсуждаемый код достаточно простой, если не считать, что объект юзает принадлежащий ему список.
Пробовал проверять работу алгоритма со списком, указанным в var основной программы, вслед за описанием основной формы. Использовал 2 таймера (стандартных) - 1 для плюсования жизни частицам, второй - для переодического их запуска. Работает безупречно.
Я несколько часов сегодня проверял этот код. Явных и формальных ошибок нет.
Все-таки Delphi иногда глючит. Как и любая программа.
old_proger
> Я несколько часов сегодня проверял этот код. Явных и формальных ошибок нет.
> Все-таки Delphi иногда глючит. Как и любая программа.
Это говорит лишь о том, что вы начинающий писатель.
В данном контексте Delphi это не программа (среда разработки), а именно компилятор!
Вы даже не назвали версию компилятора Delphi, а уже говорите о баге.
old_proger
> Все-таки Delphi иногда глючит
Ну да, прям 2+2 не может сложить ) Ищите ошибку у себя
Я не вижу, где там созданные (через new) fragm удаляются
И почему обрабатываете только одну "умершую" частицу в списке
old_proger
> Все-таки Delphi иногда глючит. Как и любая программа.
))))
Даю 99.999% что дело не в дельфи.
Вообще поведение довольно странное - но тем и интереснее найти какой участок кода и как её создаёт.
Вообще может быть какая нибудь абсолютная банальщина типа кусочка забытого тестового кода модифицирующего state-ы и life-ы.
Еще может быть незначительная порча хипа, хотя обычно порча хипа приводит к крашу.
В общем надо отлаживать.
old_proger
ещё раз повтори пожалуйста
какое поле трётся
и на какой команде
Ошибка в другом месте.
У меня так тоже бывает, либо на время закомментирую, либо допишу тестовый участок, про который забуду, и это портит малину.
old_proger
> Работа с указателями в Delphi
Не, не слышал.
Aslan
> Я не вижу, где там созданные (через new) fragm удаляются
А зачем их там удалять? Они повторно используются.
Aslan
Ищите ошибку у себя
Искал. Долго искал. Но конкретный кусок кода достаточно простой и ... в общем выше все написано.
acDev
вы начинающий писатель
Мне трудно себя сравнивать с Джоном Кармаком
acDev
версию компилятора Delphi
7 Delphi 2003 г.
acDev
уже говорите о баге
Я говорил - делаю комментарием одну строку (это присваивание позиции частице в начальный момент времени), и плюсование life частицам идет совсем по другому. Разве это не глюк?
cyborg
Ошибка в другом месте
Очень возможно. Иногда глючит - а причина в том, что десятью строками выше поставили (не поставили) необязательную в данном случае точку с запятой, и компилятору это не нравится.
В общем, глюк некритичный. Частиц много, и система в целом отрисовывается сносно. Хотя с другой стороны, всегда стоит стремиться к 100% ясности и правильности работы программы. Не собираюсь ругать Delphi. Глюки - плата за сложность программ. Всем спасибо за советы и мнения.
Тема закрыта.
{$O-} пробовал? Я неоднократно сталкивался с ошибками оптимизатора в делфи7. Выглядело приблизительно как у тебя — элементарный код отрабатывал некорректно.
>>RestartFragment(var fragm_ : PFragment);
Можно поинтересоваться какой смысл передавать указатель с директивой var? Там указатель меняете где-то? Может в этом и ошибка. Не видя полного кода, а только кусочки, которые Вы посчитали важными, сложно что-то диагностировать. Но вот var тут точно лишний.
procedure TPowerEngine.RestartFragment(var fragm_ : PFragment);
...
fragm_.position := position;
...
1. При работе с указателем его не надо передавать как var
2. при доступе к полям записи через указатель его надо-бы разадресовывать:
fragm_^.position := position;
3. переменные-указатели называй как-то осмысленней, типа так: pFragm: PFragment
Тема в архиве.