Форум 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=179133)

s3dworld 07.05.2012 17:37

Непонятные вещи с загрузкой изображений и клипов
 
Всем доброго дня!

Имеется Game.swf, которая лежит в контакте. Она подгружает изображения и другие swf нашего сервера следующим образом:

Код AS3:

public function load():Boolean
{
        if(isLoading || isComplete) return false;
 
        isLoading=true;
        isComplete=false;
 
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onComplete);
        loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityError);
        loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,onIOError);
 
        try
        {
                if(url.search(".swf")!=-1 && Game.socialAPI.isLocal)
                {
                        loaderContext.checkPolicyFile=false;
                        loaderContext.applicationDomain=ApplicationDomain.currentDomain;
                        loaderContext.securityDomain=null;
                }
                else if(url.search(".swf")!=-1 && !Game.socialAPI.isLocal)
                {
                        loaderContext.checkPolicyFile=false;
                        loaderContext.applicationDomain=ApplicationDomain.currentDomain;
                        loaderContext.securityDomain=null;
                }
                else
                {
                        loaderContext.checkPolicyFile=true;
                        loaderContext.applicationDomain=null;
                        loaderContext.securityDomain=null;
                }
 
                loader.load(urlRequest,loaderContext);
        }
        catch(_error:Error)
        {
                onCallError();
        }
 
        return true;
}

В переменной isLocal в Game.socialAPI лежит значение false, если игра была запущена из социальной сети, либо true - если игра была запущена локально. Вот собственно как я это всё гружу. Я написал менеджер загрузок. Вся его соль в том, что он позволяет распределять Loader'ы по группам и давать для каждого идентификатор. Таким образом, если мне нужно получить экранный объект волка, я укажу:

Код AS3:

var displayObject:DisplayObject=Game.resourceManager.getData("wolf",ResourceGroup.GROUP_MONSTER);

Если экранного объекта в этой группе и с таким идентификатором нету, то в ответ я получу null и смогу вручную добавить его для загрузки:

Код AS3:

Game.resourceManager.add("wolf",URL,ResourceGroup.GROUP_MONSTER);

И после этого произвести его загрузку:

Код AS3:

Game.resourceManager.load("wolf",ResourceGroup.GROUP_MONSTER);

При этом я подпишусь на событие и когда произойдёт загрузка либо ошибка, я узнаю об этом. Вот если загрузка произошла успешно, я смогу снова вызвать Game.resourceManager.getData(ID,GROUP) и получить экранный объект (то есть Loader.content). При этом на каждый Game.resourceManager.getData(ID,GROUP) у "изображения" увеличивается счётчик обращения. А когда нам уже не нужен данный ресурс, мы можем вызывать Game.resourceManager.release(ID,GROUP) и для текущего "изображения" будет уменьшен счётчик. А когда счётчик будет равен 0, то я выгружу данные:

Код AS3:

public function unload():void
{
        if(isLoading)
                loader.close();
        else if(isComplete)
                loader.unload();
 
        isLoading=false;
        isComplete=false;
}

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

Теперь покажу как я делаю копии (в _displayObject передаём то, что нам выдал Game.resourceManager.getData(ID,GROUP)):

Код AS3:

if(_displayObject)
{
        if(_displayObject is Bitmap)
        {
                soObjType=SO_OBJ_BITMAP;
                soObjBitmap=new Bitmap((_displayObject as Bitmap).bitmapData);
                soObjBitmap.smoothing=true;
 
                if(_width!=0) soObjBitmap.width=_width;
                if(_height!=0) soObjBitmap.height=_height;
 
                addChild(soObjBitmap);
        }
        else if(_displayObject is MovieClip)
        {
                soObjType=SO_OBJ_CLIP;
                var mcSource:Class=Object(_displayObject).constructor as Class;
                soObjMC=new mcSource();
                soObjMC.mouseEnabled=false;
                addChild(soObjMC);
                soLastFrame=soObjMC.currentFrame;
 
                if(_width!=0) soObjMC.width=_width;
                if(_height!=0) soObjMC.height=_height;
 
                soObjLabels=new Vector.<String>();
                array=soObjMC.currentLabels;
                len=array.length;
 
                for(i=0;i<len;i++)
                {
                        frameLabel=array[i];
                        soObjLabels.push(frameLabel.name);
                }
 
                addEventListener(Event.ENTER_FRAME,onEnterFrame);
        }
}

Вот в общем и получается что после такой обработке у меня будет либо в soObjBitmap, либо в soObjMC экранный объект. А теперь о проблемах...

Если таким образом обрабатывать изображения, то иногда получается, что некоторые копии не создаются. Приведу пример. В самом начале запуска игры я получаю карту и определяю список всех объектов на ней и список для загрузки в менеджер ресурсов. То есть перед отрисовкой карты я уже определяю все объекты на ней и через менеджер ресурсов загружаю их изображения. И когда карта начинает выводится, она уже просто создаёт копию экранного объекта из менеджера ресурсов. Так работает всё нормально. Но вот представим что мы подошли к какому-то NPC поговорить и он нам даёт задание собрать 10 досок. Но к этому моменту на карте их не было и они теперь должны появиться. В менеджере ресурсов их нет. При создании первой доски, она даст менеджеру возможность загрузить туда изображение доски и затем уже все эти 10 досок должны будут сделать из него копию. А на деле получается так, что когда все 10 досок отображаются, а когда только первая. Причём такое происходит только если запускаешь из контакта (при локальном тестировании проблем нет).

Теперь что касается клипов. Предположим что 10 этих досок выполнены не как изображение, а как swf. Сейчас речь идёт только про запуск из под контакта (в локалке все отлично). Игра рушится с таким вот сообщением:

Цитата:

RangeError: Error #1125: Индекс 15 выходит за границы диапазона 0.
at d.game.screen.screenGUI::GUIArrow()
at d.game.manager::ArrowManager/addObject()
at d.game.manager::ArrowManager/setArrows()
at d.game.screen::UpdateMap$/analysis()
at d.game.screen::ScreenMap/onGetMapInfoNetworkEvent()
at d.game.network.gameAPI::ParsingGetMapInfo$/success()
at d.game.network::GameAPI/onComplete()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at flash.net::URLLoader/onComplete()
Но когда я в коде:

Код AS3:

soObjType=SO_OBJ_CLIP;
var mcSource:Class=Object(_displayObject).constructor as Class;
soObjMC=new mcSource();
soObjMC.mouseEnabled=false;
addChild(soObjMC);

Закомментирую строчку:

Код AS3:

// addChild(soObjMC);

То никакой ошибки не возникает. Не странно ли?! Получается что клип загружен, я к нему смог обратиться и отключить мышку, а вот как добавляю на отображение, так ошибка. Кстати, после этого окна с ошибкой сразу появляется вот это:

Цитата:

Error #2044: Необработанный AsyncErrorEvent:. text=Error #2095: flash.net.LocalConnection не удалось осуществить обратный вызов apiCallback. error=TypeError: Error #1006: value не является функцией.
Собственно тут я даже не понимаю что это и откуда.

В общем вот такая ерунда происходит с загрузкой. Почему так происходит?

Acrossfy 07.05.2012 17:54

Цитата:

Не странно ли?!
Нет, ибо объект, как таковой не добавлен в сцену. Вы не обращались к объекту, а указывали его параметры до его фактического создания.

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

Приведите листинг след. функций – at d.game.screen.screenGUI::GUIArrow(), at d.game.manager::ArrowManager/addObject(), at d.game.manager::ArrowManager/setArrows() и тогда возможно что-то станет понятно.

s3dworld 07.05.2012 18:09

Acrossfy
Цитата:

Приведите листинг след. функций – at d.game.screen.screenGUI::GUIArrow(), at d.game.manager::ArrowManager/addObject(), at d.game.manager::ArrowManager/setArrows() и тогда возможно что-то станет понятно.
Хорошо. Вот функция d.game.manager::ArrowManager/setArrows():

Код AS3:

public function setArrows(_mapArrows:Vector.<MapArrow>):void
{
        var i:uint=0;
        var len:uint=_mapArrows.length;
        var mapArrow:MapArrow=null;
 
        for(i=0;i<len;i++)
        {
                mapArrow=_mapArrows[i];
 
                if(mapArrow.targetObject)
                        addObject(mapArrow.targetObjectType,mapArrow.targetObject);
                else
                        addCell(mapArrow.targetCell.x,mapArrow.targetCell.y);
        }
}

MapArrow - это:

Код AS3:

public class MapArrow extends MapObject
{
        public var targetObjectType:uint=0;
        public var targetObject:String=null;
        public var targetCell:Vector2=null;
 
        public function MapArrow()
        {
                type=TYPE_ARROW_OBJECT;
        }
 
        public override function getIsPassability():Boolean
        {
                return true;
        }
 
}

В общем это просто информация на какой объект стрелка будет показывать. Если на ячейку на карте, то targetCell не равно null, а если на какой-то объект, то его ID будет в targetObject, а его тип в targetObjectType.

Вот функция d.game.manager::ArrowManager/addObject():

Код AS3:

public function addObject(_type:uint,_id:String):void
{
        var arrow:GUIArrow=new GUIArrow(ScreenGUI.SO_NAME_GUI_ARROW,Game.screen.soGUI,_type,_id);
        arrow.x=Game.gameWidth/2;
        arrow.y=Game.gameHeight/2;
        arrow.soEnable();
        arrow.soShow();
        arrows.push(arrow);
}

Вот конструктор GUIArrow:

Код AS3:

public function GUIArrow(_name:String,_parent:ScreenObject,_type:uint,_target:String,_column:uint=0,_row:uint=0)
{
        super(_name,_parent,false,false,null);
        swType=SW_TYPE_ARROW;
        mouseEnabled=false;
        arrow.mouseEnabled=false;
 
        var i:uint=0;
        var j:uint=0;
        var lenI:uint=0;
        var lenJ:uint=Game.screen.soMap.dynamics.length;
        var object:ScreenDraw=null;
        var mapDynamic:MapDynamic=null;
        var mapDynamicJ:MapDynamic=null;
        var mapMonster:MapMonster=null;
        var mapNPC:MapNPC=null;
        var screenDynamic:ScreenDynamic=null;
 
        if(arrow.numChildren==1 && arrow.getChildAt(0) is Bitmap)
        {
                (arrow.getChildAt(0) as Bitmap).smoothing=true;
        }
 
        targetObjectType=_type;
        targetObject=_target;
        if(!targetObject) targetCell=new Vector2(_column,_row);
 
        soSetContainer(Game.screen.soGUI.layerArrows);
        Game.screen.soGUI.guis.push(this);
 
        if(targetObject)
        {
                objects=new Vector.<ScreenDraw>();
 
                if(targetObjectType==MapObject.TYPE_DYNAMIC_OBJECT)
                {
                        lenI=Game.screen.soMap.dynamics.length;
 
                        for(i=0;i<lenI;i++)
                        {
                                object=Game.screen.soMap.dynamics[i];
                                mapDynamic=object.sdGetDesc() as MapDynamic;
 
                                if(mapDynamic.desc.id==targetObject)
                                {
                                        object.sdCreateQuestEffect();
                                        objects.push(object);
                                }
                        }
 
                }
                else if(targetObjectType==MapObject.TYPE_MONSTER_OBJECT)
                {
                        lenI=Game.screen.soMap.monsters.length;
 
                        for(i=0;i<lenI;i++)
                        {
                                object=Game.screen.soMap.monsters[i];
                                mapMonster=object.sdGetDesc() as MapMonster;
                                if(mapMonster.desc.id==targetObject) objects.push(object);
                        }
                }
                else
                {
                        lenI=Game.screen.soMap.npcs.length;
 
                        for(i=0;i<lenI;i++)
                        {
                                object=Game.screen.soMap.npcs[i];
                                mapNPC=object.sdGetDesc() as MapNPC;
                                if(mapNPC.desc.id==targetObject) objects.push(object);
                        }
                }
        }
 
        soResize(Game.gameWidth,Game.gameHeight);
}

В данном примере ошибка возникает в:

Код AS3:

object.sdCreateQuestEffect();

Потому что если её вызов закомментировать, то никакой ошибки нет. А вот что в ней происходит:

Код AS3:

public function sdCreateQuestEffect():void
{
        if(sdQuestTargetEffect) return;
 
        var effectDesc:EffectDesc=Game.description.getEffectOnID("QuestTarget");
        if(!effectDesc) return;
 
        sdQuestTargetEffect=new ScreenQuestEffect(
                ScreenMap.SO_NAME_MAP_QUEST_TARGET_EFFECT,
                Game.screen.soMap,
                this,
                effectDesc.id,
                effectDesc.url);
 
        var displayObject:DisplayObject=Game.resourceManager.getData(effectDesc.id,ResourceGroup.GROUP_EFFECTS);
 
        if(displayObject)
                sdQuestTargetEffect.setImage(displayObject);
        else
                sdQuestTargetEffect.loadingImage();
 
        var vector:Vector2=Iso.toScreen(sdDesc.column,sdDesc.row);
 
        sdQuestTargetEffect.x=vector.x+Game.description.fieldWidth/2-sdQuestTargetEffect.width/2-7;
        sdQuestTargetEffect.y=vector.y+Game.description.fieldHeight/2+10;
        sdQuestTargetEffect.soEnable();
        sdQuestTargetEffect.soShow();
}

По какому бы мы пути не пошли:

Код AS3:

sdQuestTargetEffect.setImage(displayObject);
 
...
 
public function setImage(_displayObject:DisplayObject):void
{
        soUpdateDisplay(_displayObject,0,0);
}

либо по:

Код AS3:

sdQuestTargetEffect.loadingImage();
 
...
 
public function loadingImage():Boolean
{
        Game.resourceManager.addEventListener(GameEvent.RESOURCE_LOAD,onResourceLoadGameEvent);
        Game.resourceManager.addInGroup(sqeID,sqeURL,ResourceLoad.PARAM_MAIN,ResourceGroup.GROUP_EFFECTS);
 
        if(!Game.resourceManager.loadOnIDInGroup(sqeID,ResourceGroup.GROUP_EFFECTS))
        {
                Game.resourceManager.removeEventListener(GameEvent.RESOURCE_LOAD,onResourceLoadGameEvent);
                return false;
        }
 
        return true;
}
 
private function onResourceLoadGameEvent(_event:ResourceLoadGameEvent):void
{
        Game.resourceManager.removeEventListener(GameEvent.RESOURCE_LOAD,onResourceLoadGameEvent);
        if(_event.status!=EventStatus.STATUS_SUCCESS) return;
 
        var displayObject:DisplayObject=Game.resourceManager.getData(sqeID,ResourceGroup.GROUP_EFFECTS);
        var vector:Vector2=Geom.determinationSize(displayObject.width,displayObject.height,sqeParent.width,sqeParent.height);
 
        soUpdateDisplay(displayObject,0,0);
}


Всё равно попадём в эту функцию:

Код AS3:

public final function soUpdateDisplay(_displayObject:DisplayObject,_width:uint=0,_height:uint=0):void
{
        var i:uint=0;
        var len:uint=0;
        var array:Array=null;
        var frameLabel:FrameLabel=null;
 
        if(soObjBitmap)
        {
                removeChild(soObjBitmap);
                soObjBitmap=null;
        }
 
        if(soObjMC)
        {
                removeEventListener(Event.ENTER_FRAME,onEnterFrame);
                removeChild(soObjMC);
                soObjMC=null;
        }
 
        soObjType=SO_OBJ_NULL;
 
        if(_displayObject)
        {
                if(_displayObject is Bitmap)
                {
                        soObjType=SO_OBJ_BITMAP;
                        soObjBitmap=new Bitmap((_displayObject as Bitmap).bitmapData);
                        soObjBitmap.smoothing=true;
 
                        if(_width!=0) soObjBitmap.width=_width;
                        if(_height!=0) soObjBitmap.height=_height;
 
                        addChild(soObjBitmap);
                }
                else if(_displayObject is MovieClip)
                {
                        soObjType=SO_OBJ_CLIP;
                        var mcSource:Class=Object(_displayObject).constructor as Class;
                        soObjMC=new mcSource();
 
                        soObjMC.mouseEnabled=false;
                        addChild(soObjMC);
 
                        soLastFrame=soObjMC.currentFrame;
 
                        if(_width!=0) soObjMC.width=_width;
                        if(_height!=0) soObjMC.height=_height;
 
                        soObjLabels=new Vector.<String>();
                        array=soObjMC.currentLabels;
                        len=array.length;
 
                        for(i=0;i<len;i++)
                        {
                                frameLabel=array[i];
                                soObjLabels.push(frameLabel.name);
                        }
 
                        addEventListener(Event.ENTER_FRAME,onEnterFrame);
                }
        }
}

Ну вот на addChild(soObjMC) всё рушится. Помогите!

-De- 07.05.2012 18:40

Ошибка
>RangeError: Error #1125: Индекс 15 выходит за границы диапазона 0.
Не может вылетать на строчке
Код AS3:

object.sdCreateQuestEffect();

Она вылетает там, где есть доступ по индексу.

s3dworld 07.05.2012 19:21

-De-
Цитата:

Она вылетает там, где есть доступ по индексу.
Ну а почему тогда при закомментированном addChild() работает?

-De- 07.05.2012 20:45

Скорее всего потому что вы так написали. Нет никаких проблем написать код так, чтоб оно не вылетало при закоментированном addChild(), но вылетало если он написан.
Смотрите, у вас есть там 3 строки, где возможен вылет по неправильному индексу:
Код AS3:

object=Game.screen.soMap.dynamics[i];

Код AS3:

object=Game.screen.soMap.monsters[i];

Код AS3:

object=Game.screen.soMap.npcs[i];

Судя по тому, что вы упоминаете object.sdCreateQuestEffect(); то в первой. Но возможно и нет - забросайте всё трейсами и найдите точно, где и кто. Или дебаггер подцепите. Ну как всегда в общем. Похоже, кто-то у вас пересоздает Game.screen.soMap.dynamics. Т.к. он доступен глобально, то это может быть кто угодно. Возможно, что это конструктор ScreenQuestEffect, куда передается Game.screen.soMap.

s3dworld 08.05.2012 12:30

-De-
Цитата:

Судя по тому, что вы упоминаете object.sdCreateQuestEffect(); то в первой. Но возможно и нет - забросайте всё трейсами и найдите точно, где и кто. Или дебаггер подцепите. Ну как всегда в общем. Похоже, кто-то у вас пересоздает Game.screen.soMap.dynamics. Т.к. он доступен глобально, то это может быть кто угодно. Возможно, что это конструктор ScreenQuestEffect, куда передается Game.screen.soMap.
Да всё то ничего, но ошибка возникает только при запуске из под контакта. Когда я запускаю у себя локально (из под FlashDevelop), то никаких проблем вообще нет и всё работает как и планировалось.

-De- 08.05.2012 12:49

Вполне возможно, что виноваты всё-таки вы, а не адобы, контакт или несовершенство мира. Чтобы трейсить вконтакте можете воспользоваться логгером от инфокоры вон =)

s3dworld 08.05.2012 13:09

-De-
Можете подсказать на что мне сейчас в первую очередь обратить внимание, что проверить? А я проверю и отпишусь.

-De- 08.05.2012 13:51

Понять, что же ошибка означает. Она значит "попытка получить доступ по индексу 15 в векторе, длина которого 0". В функции GUIArrow.
Вот пишете перед строчками, где есть там доступ по индексу
Код AS3:

trace("Game.screen.soMap.dynamics", Game.screen.soMap.dynamics.length, i);

И перед концом цикла тоже можно сразу влепить. Ставите плагин, чтоб трейсы видеть или логгером инфокоровским воспользуйтесь (тогда не трейс, а что там у него в логгере). Тогда между строчками, где length был не 0, а стал 0 - случилась фигня. Делаете то же самое в функциях между теми строчками. Так пока не найдете, где же он обнулился.
Может можно подцепиться в дебаггере к флешке в контакте, но я не подскажу как %)


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

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