PDA

Просмотр полной версии : Хранение и вывод иллюстраций для игры


Appleman
22.01.2018, 17:17
Друзья, вопрос по gui. Спасибо за дельные советы, прекрасно получилось организовывать все мелкие графические объекты (иконки, портреты персонажей, предметы и т.п.) в атласы. Все координаты хранятся в XML, выдаются по строковому идентификатору, загрузить саму BitmapData - дело техники. Красота!

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

undefined
22.01.2018, 18:04
класть рядом и грузить по мере надобности.

Appleman
22.01.2018, 18:56
С помощью Filestream или URLLoader? Сорри за тупые вопросы, я тут совсем плаваю. А у отца родного нашего - Мука - по AIR ничего нет :(

undefined
22.01.2018, 19:06
стримами обычно грузят потоковые данные(аудио/видео).Для картинок хватит и обычного Loader'а

Wolsh
22.01.2018, 22:10
Если не хочется при установке игры выкладывать все изображения в папку игры "как есть", можно попробовать упаковать их в архивы по, например, локациям или уровням, если есть в игре какая-то линейность и можно предполагать, что вот сейчас и в течении какого-то игрового времени понадобятся только вот такие слайды. Затем по мере надобности можно брать нужный архив и распаковывать его во временную директорию (в AIR есть такая возможность, File.createTempDirectory()), чтобы не занимать оперативку, и оттуда уже таскать нужные слайды.
Более сложный вариант — читать изображения в оперативку файлстримом из какого-то общего файла-хранилища-всех-изображений, но для этого надо будет знать position первого байта и длину файла для каждого слайда, и хранить их либо в отдельной описи, либо в этом же файле. Тут уже нужен некоторый опыт ковыряния в файлах и инструмент для сборки этого самого файла. Зато "на выходе" будет какой-то непонятный файл, который никто не сможет запросто посмотреть или отредактировать по своему хотению.

caseyryan
23.01.2018, 12:05
Так а что за игра то? Под плеер или под AIR?
Если под эйр то под какой, десктоп или мобильный?

ZergMaster
23.01.2018, 13:07
да, и не забудь указать Wolsh-а в команде разработчиков)))

Appleman
23.01.2018, 18:17
Более сложный вариант — читать изображения в оперативку файлстримом из какого-то общего файла-хранилища-всех-изображений, но для этого надо будет знать position первого байта и длину файла для каждого слайда, и хранить их либо в отдельной описи, либо в этом же файле. Тут уже нужен некоторый опыт ковыряния в файлах и инструмент для сборки этого самого файла. Зато "на выходе" будет какой-то непонятный файл, который никто не сможет запросто посмотреть или отредактировать по своему хотению.

Спасибо, запомнил. Думаю, это пока излишне. На данный момент цель - сделать рабочий вариант вывода нужной картинки в нужный момент. Все эти фокусы можно оставить на потом ближе к релизу. К тому моменту и структура базы изображений будет более понятна. А если совсем честно, почему-то меня совсем не прут все эти внутрипрограммные утилиты. Движок делать, всю логику планировать, взаимодействие классов, визуальные компоненты и их работу - дико нравится и интересно. А все эти файл-, XML-, asset- и прочие менеджеры - нет. Просто хочется, чтоб работало и не отвлекало от содержательной работы :)

Ещё общий краткий вопрос, пока писать не начал. Я правильно понимаю, что когда изображение уже больше не нужно, достаточно его просто убрать из DOC, отменить все висящие на нём слушатели событий и записать null в переменную, в которой оно хранилось? Или ещё что-то, чтобы нормально уходило и не занимало ресурсы?

Так а что за игра то? Под плеер или под AIR?
Если под эйр то под какой, десктоп или мобильный?

Всё та же, под десктоп на эйр. Личный проект в жанре RPG с механикой текстового квеста.

да, и не забудь указать Wolsh-а в команде разработчиков)))

Я вас всех в команде разработчиков укажу, или как минимум в списке тех, кому благодарен и без кого ничего бы не вышло. :drinks: Главное, чтобы было где указывать. До релиза пока как до Китая :) Но прогресс идёт, а главное, доставляет удовольствие.

Wolsh
23.01.2018, 22:03
Я правильно понимаю, что когда изображение уже больше не нужно, достаточно его просто убрать из DOC, отменить все висящие на нём слушатели событий и записать null в переменную, в которой оно хранилось? Или ещё что-то, чтобы нормально уходило и не занимало ресурсы?BitmapData#dispose() (https://help.adobe.com/ru_RU/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#dispose()).
"убрать из DOC" ты можешь только Битмап, а он весит около килобайта. Мегабайты весит БитмапДата; указанный метод очищает память от нее.

caseyryan
24.01.2018, 09:50
Всё та же, под десктоп на эйр. Личный проект в жанре RPG с механикой текстового квеста.
Тогда создай в проекте в папке bin папку под картинки и загружай просто при старте игры обычным Loader'ом. Если в бин будет лежать папка images, то из программы путь к ней будет такой:

var imageDir:File = File.applicationDirectory.resolvePath("images");

Appleman
24.01.2018, 14:26
Wolsh, спасибо.

caseyryan, спасибо. Я уже методом тыка, совмещённым со свойством nativePath, это место установил :) Туда спрайтшиты складываю. Сейчас подумываю приспособить уже имеющийся файл-менеджер для загрузки картинок.

загружай просто при старте игры обычным Loader'ом
Не при старте, а в рантайме нужно. Чтобы наоборот всё чохом не грузить, а каждую нужную пикчу по одной. Или я не прав?

caseyryan
25.01.2018, 06:03
Не при старте, а в рантайме нужно. Чтобы наоборот всё чохом не грузить, а каждую нужную пикчу по одной. Или я не прав?
Всё верно. "При старте" - это и есть рантайм. Приложение запустилось, сразу загрузил всё, что нужно, показав процесс загрузки пользователю, а дальше уже используешь.
Посмотри как в старлинге устроен AssetManager (https://github.com/Gamua/Starling-Framework/blob/master/starling/src/starling/utils/AssetManager.as). Это конечно не подойдет тебе с простым дисплей листом на 100%, но может навести на некоторые полезные мысли.
Он умеет сам определять что за вид ресурса перед ним (правда простой проверкой расширения, но в обычном случае этого достаточно, если тебе не требуется определять ресурс без расширения, чтением байт заголовков), и сам раскладывает их по нужным массивам

Appleman
25.01.2018, 10:12
"При старте" - это и есть рантайм. Приложение запустилось, сразу загрузил всё, что нужно, показав процесс загрузки пользователю, а дальше уже используешь.

Стоп. Я тогда всё-таки не понимаю. Чем такой метод лучше, чем [Embed]? Я-то думал, ничего вообще никуда не грузить на старте, а в момент, когда непосредственно требуется отобразить нужную картинку, программа обращается к ней через Loader, загружает и выводит. Когда требуется следующая, аналогично грузится она.

ZergMaster
25.01.2018, 12:29
Embed вшивает ресурс в swf, увеличивая его конечный размер, например. А Loader загружает ресурс при исполнении.

undefined
25.01.2018, 12:49
и в чем разница грузить большую флэшку либо грузить легкую флэшку и потом долго тянуть все ресурсы?Еще раз: грузить надо тогда,когда это требуется и только то,что требуется.

ZergMaster
25.01.2018, 13:38
Ну, это зависит от задачи.. А так то да, если подгружать, потихонечку надо. Вообще картиночки можно и сразу после загрузки подгружать. Смысл в том, что флешка уже будет работать и пользователь пока может почитать че-нить, как-то уже взаимодействовать даже быть может. Пока контент грузится

caseyryan
25.01.2018, 14:27
Стоп. Я тогда всё-таки не понимаю. Чем такой метод лучше, чем [Embed]? Я-то думал, ничего вообще никуда не грузить на старте, а в момент, когда непосредственно требуется отобразить нужную картинку, программа обращается к ней через Loader, загружает и выводит. Когда требуется следующая, аналогично грузится она.
1) Загрузчик грузит ресурсы асинхронно, не замораживая всю программу, а Embed сразу, всё в одном кадре. Это вызовет подвисание приложения, если ресурсов много.
2) Способом с подгрузкой ты можешь загрузить в каждый момент вермени только те ресурсы, которые требуются в данный момент. Например ты загрузил игру и игроку доступен только первый уровень. Зачем тогда ему грузить второй, третий.. десятый и т.д.
3) Загруженные ресурсы очень сильно жрут оперативку. В случае с Embed, они будут сразу все загружены и будут висеть в памяти.

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

Godwarlock
25.01.2018, 16:45
caseyryan Подойдет ли вариант, с ручной деактивацией ресурсов в менеджере? Например если какой-то объект не был активен в течении длительного времени. То есть поставить таймер на такие штуки и если они долго не активны, очищаем из менеджера свойства этого объекта. А потом когда опять будет вызов, подгружать заново, ибо Null. Тогда по идее вообще память будет по минимуму нагружаться.

caseyryan
26.01.2018, 06:06
caseyryan Подойдет ли вариант, с ручной деактивацией ресурсов в менеджере? Например если какой-то объект не был активен в течении длительного времени. То есть поставить таймер на такие штуки и если они долго не активны, очищаем из менеджера свойства этого объекта. А потом когда опять будет вызов, подгружать заново, ибо Null. Тогда по идее вообще память будет по минимуму нагружаться.
А как ты проверишь активность объекта? Вот есть у тебя какая-то BitmapData, к примеру. Как ты узнаешь используется она где-то или нет?
Или звук. Может быть это звук удара, а игрок долго никого не бьет. Как ты определишь, нужно его считать неактивным, или нет?
Ну и плюс, такое непредсказуемое поведение чревато внезапными включениями сборщика мусора, который будет подтормаживать весь процесс.

Тут главное, чтобы оптимизация не доходила до маразма. Нам (современным программистам) повезло, у нас есть в распоряжении довольно много оперативной памяти и процессорных ресурсов. Можно себе позволить не оптимизировать вообще всё и вся. Я думаю, достаточно лишь заранее условно разделить ресурсы (вручную) на те, которые могут потребоваться в данный момент, и те, которые точно не нужны здесь и сейчас. И по этому принципу всё загружать или разгружать

Appleman
06.05.2018, 02:52
Друзья!

Вот что у меня получилось по части использования loader-ов. Файл находит по адресу и даже вроде как загружает. Но я никак не могу сообразить, как мне теперь его вернуть.

public function getLoadedAsset(fileID: String) : Bitmap
{
var file: File = File.applicationDirectory.resolvePath("assets" + File.separator + "backgrounds" + File.separator + fileID + PNG);
var request: URLRequest = new URLRequest(file.url);

trace(file.url); // Показывает правильный путь

var loader: Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loader.load(request);
trace(loader.content); // null
}

private function completeHandler(e: Event) : void
{
var loader: Loader = Loader(e.target.loader);
var image: Bitmap = Bitmap(loader.content);
trace(image); // [object Bitmap]
}

То есть как мне вернуть битмапку из метода getLoadedAsset, когда она становится доступной только в методе completeHandler?

Wolsh
06.05.2018, 13:11
как мне вернуть битмапку из метода getLoadedAsset, когда она становится доступной только в методе completeHandler?
Ответ содержится в вопросе. Никак.

Непонятно, зачем использовать асинхронный Loader в AIR-приложении для чтения файлов с диска. Есть же FileStream.

Appleman
06.05.2018, 15:27
Да, я так и думал :) Мне тут страницей выше рекомендовали Loader, т.к. FileStream, мол, больше для потокового аудио и видео. Ща попробуем, спасибо.

Добавлено через 46 минут
Вот до такого доковырялся сам.

public function getLoadedAsset(fileID: String) : Bitmap // Загружает и возвращает asset
{
var file: File = File.applicationDirectory.resolvePath("assets" + File.separator + "backgrounds" + File.separator + fileID + PNG);
var filestream: FileStream = new FileStream;
var bytes: ByteArray = new ByteArray;
var data: BitmapData = new BitmapData(800,600);
var rect: Rectangle = new Rectangle(0, 0, 800, 600);

trace(file.url);

filestream.open(file, FileMode.READ);
filestream.position = 0;
filestream.readBytes(bytes);

data.setPixels(rect, bytes);

var result: Bitmap = new Bitmap(data);
trace (result);

return result;
}

Проблемных точек три:
Во-первых, периодически получаю ошибку [Fault] exception, information=Error: Error #2030: End of file was encountered.
Во-вторых, надо как-то заранее получать разрешение загружаемого файла. Я пока для теста написал в лоб 800*600, то это не дело.
Наконец, даже если всё получается без ошибок, то на экран какая-то каша выходит :)

И вообще, в правильном направлении двигаюсь?

Wolsh
06.05.2018, 18:41
1. Стрим надо закрывать после чтения методом close();
2. B setPixels() нужно передавать пиксели, как ни странно, а не файл. Подсказка: файл изображения содержит еще кучу данных кроме собственно пикселей, а собственно "пиксели" в файле могут содержаться в сжатой архиватором форме, а то и вообще быть "вычисляемыми" в процессе декодирования изображения кодеком.
Резюме: нужен декодер, точнее декодерЫ основных форматов (либо один, если все изображения будут в одном формате). Годный декодер примет файл и выдаст битмапдату ее собственного размера синхронно. Насколько я помню, нативный набор AS3 предоставляет только асинхронный декодер в виде загрузки байтЭррей в Лоадер)) круг замкнулся.
Ищи кастомный декодер.
Ну, например https://github.com/furusystems/Aishiteru/blob/master/tools/Tilesheeter/src/ion/utils/png/PNGDecoder.as

Appleman
06.05.2018, 19:21
Хм... А стоит ли игра свеч, если есть нативный loader, который на раз-два всё загружает и отдаёт? В чём его такое подавляющее преимущество? Уже придумался рабочий вариант - при заходе в локацию сразу загружать пачку картинок от этой локации и с данными персонажами (и первое, и второе известно, файлов не должно быть много), забивая BitmapDat-ы в Dictionary, а потом просто отдавать по идентификатору. А при смене локации - убивать старые и заполнять новые.

Wolsh
06.05.2018, 19:38
Это уж как вам нравится) Мое дело отвечать на поставленные вопросы)

ZergMaster
06.05.2018, 23:26
Друзья!

Вот что у меня получилось по части использования loader-ов. Файл находит по адресу и даже вроде как загружает. Но я никак не могу сообразить, как мне теперь его вернуть.

public function getLoadedAsset(fileID: String) : Bitmap
{
var file: File = File.applicationDirectory.resolvePath("assets" + File.separator + "backgrounds" + File.separator + fileID + PNG);
var request: URLRequest = new URLRequest(file.url);

trace(file.url); // Показывает правильный путь

var loader: Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loader.load(request);
trace(loader.content); // null
}

private function completeHandler(e: Event) : void
{
var loader: Loader = Loader(e.target.loader);
var image: Bitmap = Bitmap(loader.content);
trace(image); // [object Bitmap]
}

То есть как мне вернуть битмапку из метода getLoadedAsset, когда она становится доступной только в методе completeHandler?

Не совсем православный, но самый очевидный и рабочий вариант - через функцию-callback

public function getLoadedAsset(fileID: String, callback:Function) : void
{
var file: File = File.applicationDirectory.resolvePath("assets" + File.separator + "backgrounds" + File.separator + fileID + PNG);
var request: URLRequest = new URLRequest(file.url);

var loader: Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function():void
{
var loader: Loader = Loader(e.target.loader);
var image: Bitmap = Bitmap(loader.content);
callback(image);
});
loader.load(request);
}

Appleman
07.05.2018, 00:05
ZergMaster, спасибо. Даже не знал, что так можно. А почему не православный?

Wolsh, я тогда с позволения поставлю вопрос, почему ты ратуешь на использование FileStream-а для AIR как альтернативы Loader-у. Кстати, я данную ветку сначала перечитал, вспомнил твою идею не выкладывать графические файлы как есть, а закатать их в один не-пойми-какой-снаружи файл, и оттуда при загрузке уже в программе нарезать картинки. С точки зрения такого подхода, есть какие-то аргументы "за" и "против" каждого из вариантов?

Wolsh
07.05.2018, 07:09
FileStream умеет читать из открытого файла фрагменты "от такого-то байта до такого-то".
Loader, конечно же, так не умеет. Если будет нужна какая-то одна иконка, лоадером придется грузить весь файл и только потом выискивать в нем нужный кусочек.
В любом случае асинхронная загрузка требует сложного менеджмента: нужно постоянно точно знать, что это сейчас пришло в лоадер, именно потому, что последовательность получения файлов не совпадает с последовательностью запросов (асинхрон). Так же и вариант ZergMaster, использующий безымянного беса — только делает вид, что возвращает картинку заказчику. На самом-то деле он возвращает ее не в место вызова и уж конечно не сразу после вызова, а в еще одну функцию, колбэк-функцию. И эта колбэк-функция понятия не имеет, что за файл в нее свалился: если у "заказчика картинок" будет один такой приемный пункт, а картинок заказано несколько, то он точно так же не будет знать, в каком порядке они поступят в приемник (колбэк), то есть буквально про каждую картинку будет неизвестно, что это такое, что за файл. Асинхронность никуда не делась (она и не может деться, если используется асинхронная загрузка), проблема осталась такой же, как и была, только перенесена с больной головы на здоровую. Если можно использовать только лоадер (например, если файлы нужно забирать с сервера), то конечно правильный подход твой — загрузить и рассортировать всю пачку для текущего уровня до его активации. Я бы по возможности и при синхронной загрузке делал так же, но это уже зависит от задачи, от особенностей проекта. Синхрон нравится мне тем, что ты получаешь файл тут же, где запросил и точно знаешь что запросил и что с ним делать, не нужно городить систему надсмотрщиков и сортировщиков.

Еще раз: выбор подхода зависит от особенностей проекта. Есть например такое понятие в UX, как ожидаемая задержка. То есть пользователь, взаимодействуя с программой, в какие-то моменты ДОПУСКАЕТ, что программа будет выполнять действие, не реагируя на него — например, при переходе между уровнями игры или при открытии дополнительного окна (инвентаря например). В другие моменты такая задержка пугала и раздражала бы, вызывая ощущение что программа "виснет" и "тормозит". Загружать иконки предметов при открытии Инвентаря — это нормально, но совершенно неприемлемо подгружать изображение пули в момент выстрела)) Надо учитывать эти моменты, решая что когда грузить — и то лишь в том случае, когда загрузить все заранее невозможно (например, просто нет такого понятия как элементы уровня: на любом уровне может понадобиться любой "предмет" игры, неизвестно заранее какой, а все ассеты весят столько, что памяти для нормальной работы не хватит).

ZergMaster
07.05.2018, 12:40
И эта колбэк-функция понятия не имеет, что за файл в нее свалился: если у "заказчика картинок" будет один такой приемный пункт, а картинок заказано несколько, то он точно так же не будет знать, в каком порядке они поступят в приемник (колбэк), то есть буквально про каждую картинку будет неизвестно, что это такое, что за файл.

да, поэтому на этот случай правильней было бы, конечно, сделать так
callback(fileID, image);

А почему не православный?
Потому что безымянная функция, над которой мы не имеем никакой власти. Если ими пользоваться бездумно, то начинает происходить всякая чертовщина. Иногда её удобно использовать, если компактно и пока никто не видит. Но если не чувствуешь в себе силы джедая, то правильней оформлять callback через private переменную, тогда и от безымянной функции можно избавиться.

Appleman
08.05.2018, 00:57
Пока забил болт и Loader-ом сделал, как и планировал: при выборе персонажа - забиваем в Dictionary графику для персонажа, при выборе локации - картинки от данной локации и т.п.

У меня ещё тут по ходу мелкий вопрос возник. Я правильно понимаю, что после того, как каждый из Loader-ов закончил работу, с него нужно руками снять слушатели событий? Почему-то в хелпе Adobe-овском об этом ни слова ни в тексте, ни в примерах.

Плюс есть ещё пара вопросов крупных, пойду с ними в тему про MVC. :)

Wolsh
08.05.2018, 04:19
Почему-то в хелпе Adobe-овском об этом ни словаПотому что адобовский хелп про то, как всё работает, а не про твою игру ;)
В обработчике нажатия на кнопку ты отписываешься от события? А если кнопка больше не нужна? А если нужна? Так же и с лоадером — кто сказал, что он может грузить только один файл? Тогда про что должен писать хелп? Это твое личное дело, отписываться или использовать лоадер дальше.

Appleman
08.05.2018, 10:10
Наверное, правильнее будет сказать, что хелп "не для ламерья" ;)

Я вспомнил, у меня так давеча с таймерами было, когда в теле метода каждый раз создавался новый таймер. Полагаю, при последовательной загрузке файлов, вполне можно создать лоадер на уровне класса, один раз повесить слушатели, а потом убрать, когда вся грядка будет загружена.

Tails
08.05.2018, 11:26
Адобовский хелп всем хелпам хелп. На русском, всё расписано в деталях. Вот бы все хелпы были такими. :)

caseyryan
08.05.2018, 11:32
Полагаю, при последовательной загрузке файлов, вполне можно создать лоадер на уровне класса, один раз повесить слушатели, а потом убрать, когда вся грядка будет загружена.
логично
Но если ты будешь использовать локальный слушатель, и обработчик сделаешь анонимный, то время жизни слушателя, вместе с обработчиком будет равно времени его использования. Как только все загрузилось (например картинка) ты передал ее куда-то, не сохраняя ссылок на загрузчик, загрузчик больше не нужен и он становится доступным для сборщика мусора.
Но как разработчик игр с 9 летним стажем, могу посоветовать максимально использовать одни и те же ресурсы ;) Делай пулы объектов, не удаляй ничего без надобности. Лучше заведи себе привычку делать ресет состояний старых объектов, чем создавать новые. Новые создавай только в крайнем случае, когда полноценный ресет сделать очень трудно (даже не могу себе представить такой ситуации, если все сделано правильно), либо объектов в пуле просто не хватает.
Даже если ты грамотно от всего отписываешься, и сборщик все зачищает по феншую, весь этот процесс приводит к фризам в игре. Если нужен плавный геймплей, то это будет большой такой занозой в заднице, потому что сборщик может начать сборку в самый неожиданный момент
Адобовский хелп всем хелпам хелп. На русском, всё расписано в деталях. Вот бы все хелпы были такими.
Согласен. Если почитаешь хелп джавы, к примеру, сразу поймешь, на сколько круто адобовцы постарались над своим хелпом

ZergMaster
08.05.2018, 11:50
Адобовский хелп всем хелпам хелп. На русском, всё расписано в деталях. Вот бы все хелпы были такими. :)

+стопицот!

Appleman
08.05.2018, 14:08
Поясни плиз:

логично
Но если ты будешь использовать локальный слушатель, и обработчик сделаешь анонимный

Не понял про анонимный обработчик. Что имеется в виду?

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

Не понял на счёт ресета состояний. Ты имеешь в виду, не удалять ставшие ненужными asset-ы из программы для их возможного последующего использования? Я как раз наоборот планировал: открываем локацию - загрузили с диска пачку картинок для неё. Вышли - всё поубивали на фиг, чтобы память не занимать.

caseyryan
08.05.2018, 17:21
Я как раз наоборот планировал: открываем локацию - загрузили с диска пачку картинок для неё. Вышли - всё поубивали на фиг, чтобы память не занимать.
Я не говорю, что все нужно сохранять, если картинки больше не нужны, и занимают много памяти, то можно и грохнуть. Но если что-то, будет использоваться в будущем, не нужно его убивать.
Не понял про анонимный обработчик. Что имеется в виду?
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event) {
// анонимный обработчик
});

Appleman
08.05.2018, 17:52
caseyryan, спасибо, понятно.