Where must be custom logic in pureMVC (as3)? - actionscript-3

I tried to write small as3 program based on framework pureMVC.
I understood basic principles of it, but I can't understand, where I must place custom logic.
For example, I must load 10 images. I created command, that init Proxy.
package app.controller
{
import app.model.GalleryProxy;
import dicts.Constants;
import org.puremvc.interfaces.INotification;
public class LoadFilesCommand extends BaseCommand
{
public function LoadFilesCommand() { }
override public function execute(note:INotification):void
{
facade.registerProxy(new GalleryProxy(Constants.FILES_LIST));
}
}
}
And Proxy is:
package app.model
{
import dicts.Constants;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.net.URLRequest;
import org.puremvc.interfaces.IProxy;
import org.puremvc.patterns.proxy.Proxy;
public class GalleryProxy extends Proxy implements IProxy
{
public function GalleryProxy(list:Vector.<String>)
{
super(Constants.PROXY_GALLERY);
_fileList = list;
_total = _fileList.length;
load();
}
public function get currentImage():Bitmap
{
return _images[_index];
}
//--------------------------------------------------------------------------
// PRIVATE SECTION
//--------------------------------------------------------------------------
private var _fileList:Vector.<String>;
private var _total:uint;
private var _loaded:uint = 0;
private var _images:Array = [];
private var _index:int;
private function load():void
{
var loader:Loader;
for (var i:int = 0; i < _total; i++)
{
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoadHandler);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
loader.load(new URLRequest(_fileList[i]));
}
}
private function imageLoadHandler(event:Event):void
{
var info:LoaderInfo = LoaderInfo(event.currentTarget);
_images[Constants.FILES_LIST.indexOf(info.url)] = info.content;
info.removeEventListener(Event.COMPLETE, imageLoadHandler);
info.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
_loaded++;
if (_loaded >= _total)
sendNotification(Constants.COMMAND_SHOW_MAIN);
}
private function errorHandler(event:ErrorEvent):void
{
throw new Error("bad link or internet disconnect");
}
}
}
Now my Proxy is loading images independently (functions load() and imageLoadHandler)
Is it correct?
Or I must move this logic to Command class?
Or I must create some LoadService.as, which will contains this logic?
What is the correct variant for pureMVC?

Do you want to load your 10 images on application startup? If not, make load() public and call it from a Mediator, responding to a UI event.
If so, what you have will work fine. One alternative would be writing GalleryProxy so it doesn't call load() in the constructor - instead, you could have the Command register the proxy, load the image list, and call proxy.load(images[i]) in a loop.

Related

AS3: ReferenceError: Error #1069:

I'm trying to load a sound file into my Flash project. I keep getting this error however.
ReferenceError:
Error #1069: Property COMPLETE not found on flash.events.Event and there is no default value. at LoadSND/soundLoaded()[C:\Users\Admin\Desktop\Final Project\LoadSND.as:38]
The relevant code:
package {
import flash.events.*;
import flash.media.*;
import flash.net.URLRequest;
public class LoadSND {
//declare variables
private var sndTrack: Sound;
private var sndChannel: SoundChannel;
private var sndVolume: Number;
private var newTrack: String;
private var canRepeat: Boolean;
public function LoadSND(myTrack: String, myRepeat: Boolean = true) {
// constructor code
// set a default volume and track
sndVolume = 0.5;
setTrackData(myTrack, myRepeat);
}
private function loadSound(): void {
// first stop all old sounds playing
SoundMixer.stopAll();
// create a new sound for the track and a new sound channel
sndTrack = new Sound();
sndChannel = new SoundChannel();
// load the required sound
sndTrack.load(new URLRequest(newTrack));
// when loaded – play it;
sndTrack.addEventListener(Event.COMPLETE, soundLoaded);
}
private function soundLoaded(Event): void {
// finished with this listener so remove it
sndTrack.removeEventListener(Event.COMPLETE, soundLoaded);
// call the play sound function
playSound();
}
private function playSound(): void {
// assign music to the musicChannel and play it
sndChannel = sndTrack.play();
// setting the volume control property to the sound channel
sndChannel.soundTransform = new SoundTransform(sndVolume, 0);
// but add this one to make repeats
sndChannel.addEventListener(Event.SOUND_COMPLETE, playAgain);
}
private function playAgain(Event): void {
// remove this listener and repeat playSound()
sndChannel.removeEventListener(Event.SOUND_COMPLETE, playAgain);
playSound();
}
private function setTrackData(myTrack: String, myRepeat: Boolean): void {
// update the new track information
newTrack = myTrack;
canRepeat = myRepeat;
// and load it
loadSound();
}
private function setVolumeLevel(Number): void {
}
} //end class
} //end package
Loading a default track through my Main.as
package {
import flash.display.MovieClip;
import flash.text.TextField;
import flash.display.SimpleButton;
import flash.utils.Dictionary;
import flash.text.TextFormat;
import flash.net.*;
import flash.events.*;
import fl.controls.*;
import flash.media.*;
import fl.events.ComponentEvent;
import fl.managers.StyleManager;
import fl.data.DataProvider;
import fl.data.SimpleCollectionItem;
import fl.managers.StyleManager;
import fl.events.ComponentEvent;
import flash.events.Event;
import flash.net.SharedObject;
import LoadSWF;
import GameButton;
import LoadSND;
public class Main extends MovieClip {
//Sound Variables
private var MAX_TRAX: int = 7;
private var MAX_SFX: int = 9;
private var sndPath: String;
private var sndTrack: LoadSND;
private var isMuted: Boolean;
private var canRepeat: Boolean;
private var sndVolume: Number;
public function Main() {
// constructor code
sndPath = "musicSFX/Fury.mp3";
isMuted = false;
sndTrack = new LoadSND(sndPath, canRepeat);
}
Any help is appreciated :) Thanks
The problem lies in the definition of soundLoaded function. You put just class in there instead of argument with type declaration. It should be solved if you adjust definition of the soundLoaded function in the following way:
private function soundLoaded(event:Event): void
By the way same problem is in functions playAgain and setVolumeLevel.

AS3: 1180 Call to a possibly undefined property: Add Child

Pretty big noob at AS3. I'm trying to Load a SWF into another file. (Main .fla loading external SWFS on mouse click)
I keep getting the error: 1180 Call to a possibly undefined property: Add Child, however.
My LoadSWF code is:
package {
import flash.display.*;
import flash.events.*;
import flash.net.*;
public class LoadSWF {
private var loaderFile: Loader;
private var swfFile: Object;
private var sourceFile: String;
private var fileLabel: String;
private var canDrag: Boolean;
private var popX: int;
private var popY: int;
public function LoadSWF(myFile: String, myLabel: String, myX: int = 0, myY: int = 0, myDrag: Boolean = false) {
// constructor code
trace("Loading SWF file:", myFile);
sourceFile = myFile;
fileLabel = myLabel;
canDrag = myDrag;
popX = myX;
popY = myY;
openSWF();
}
private function openSWF(): void {
// initialise variables
loaderFile = new Loader();
swfFile = addChild(loaderFile);
// set initial position of the SWF popup
loaderFile.x = popX;
loaderFile.y = popY;
try {
loaderFile.load(new URLRequest(sourceFile));
// runs after the SWF popup has finished loading
loaderFile.contentLoaderInfo.addEventListener(Event.COMPLETE, SWFloaded);
} catch (err: Error) {
// provide some error messages to help with debugging
trace("Error loading requested document:", sourceFile);
trace("Error:", err);
sourceFile = null;
}
} //end openSWF
private function SWFloaded(evt: Event): void {
// and add the required event listeners
loaderFile.addEventListener(MouseEvent.MOUSE_DOWN, dragSWF);
loaderFile.addEventListener(MouseEvent.MOUSE_UP, dropSWF);
// use the POPUP reference to access MovieClip content
swfFile.content.gotoAndStop(fileLabel);
// assigns a close function to the button inside the popup
swfFile.content.closeBtn.addEventListener(MouseEvent.CLICK, closeSWF);
// remove the COMPLETE event listener as it’s no longer needed
loaderFile.contentLoaderInfo.removeEventListener(Event.COMPLETE, SWFloaded);
} //end SWFLOaded
private function dragSWF(evt: MouseEvent): void {
swfFile.content.startDrag();
}
private function dropSWF(evt: MouseEvent): void {
swfFile.content.stopDrag();
}
private function closeSWF(evt: MouseEvent): void {
// remove the required event listeners first
loaderFile.removeEventListener(MouseEvent.MOUSE_DOWN, dragSWF);
loaderFile.removeEventListener(MouseEvent.MOUSE_UP, dropSWF);
swfFile.content.closeBtn.removeEventListener(MouseEvent.CLICK, closeSWF);
// remove the pop-up
loaderFile.unloadAndStop();
}
} //end class
} //end package
I'm calling it into my main class file, which code is (I left out the rest, guessing its unnecessary):
package {
import flash.display.MovieClip;
import flash.text.TextField;
import flash.display.SimpleButton;
import flash.utils.Dictionary;
import flash.text.TextFormat;
import flash.net.*;
import flash.events.*;
import fl.controls.*;
import flash.media.*;
import fl.events.ComponentEvent;
import fl.managers.StyleManager;
import fl.data.DataProvider;
import fl.data.SimpleCollectionItem;
import fl.managers.StyleManager;
import fl.events.ComponentEvent;
import flash.events.Event;
import flash.net.SharedObject;
import LoadSWF;
public class Main extends MovieClip {
//Declare variables
private var componentFmt: TextFormat;
private var radioBtnFmt: TextFormat;
private var playerData: Object;
private var savedGameData: SharedObject;
// Pop-up Variables
private var popupFile: LoadSWF;
private var swfPath: String;
public function Main() {
// constructor code
this.savedGameData = SharedObject.getLocal("savedPlayerData");
this.setComponents();
this.setPlayerData();
//this.swfPath = "";
//this.isHelpOpen = false;
//this.sndPath = "musicSFX/music2.mp3";
//this.isMuted = false;
//this.sndTrack = new LoadSND(this.sndPath, this.canRepeat);;
//this.muteBtn.addEventListener(MouseEvent.CLICK, this.setMute);
swfPath = "";
helpBtn.addEventListener(MouseEvent.CLICK, openSWF);
//hauntedForestBtn.addEventListener(MouseEvent.CLICK, openSWF);
}
public function openSWF(evt: MouseEvent): void {
// determine which button was pressed
var myFile: String = evt.currentTarget.name.replace("Btn", ".swf");
myFile = (swfPath == "") ? myFile : swfPath + myFile;
if (myFile == "help.swf") {
// load the help SWF file - is draggable
swfFile = new LoadSWF(myFile, currentFrameLabel, 80, 60, true);
} else {
// load the selected SWF file - is not draggable
swfFile = new LoadSWF(myFile, currentFrameLabel);
}
addChild(swfFile);
}
If anyone could help me find a solution, i'd greatly appreciate it.
Thanks :)
addChild is defined by DisplayObjectContainer.
So to access this function, you'll have to alter LoadSWF so that it extends DisplayObjectContainer.

as3 calling a function in Main.as Document Class from another class

I am sure this is a popular question but I can't find the exact answer I need. I simply need to access a function or functions created in the Main.as document class. I have tried several methods and they do not seem to work. Here is one example I tried.
anotherClass.as // This needs to access functions Main.as
package com
{
import Main;
public class anotherClass
{
private var stageMain:Main;
public function anotherClass()
{
// tries to call a function in Main.as called languageLoaded. NO WORK!
stageMain.languageLoaded("English");
// in the Main.as languageLoaded is a public function
}
}
}
The cleaner way is to simply pass a reference to Main to the constructor of the class you want to be able to access it.
For example, your AnotherClass could look like this:
class AnotherClass
{
private var _main:Main;
public function AnotherClass(main:Main)
{
_main = main;
_main.test(); // Success!
}
}
And your main class:
class Main
{
public function Main()
{
var another:AnotherClass = new AnotherClass(this);
}
public function test():void
{
trace("Success!");
}
}
public class MainDoc extends MovieClip // as long as it extends eventDispatcher you re fine
{
private var otherClass:OtherClass;
public function MainDoc()
{
otherClass = new OtherClass();
otherClass.addEventListener("otherClassCustomEvent", onOtherClassReady);
otherClass.startLogic();
}
public function onOtherClassReady(event:Event = null)
{
trace("from other class:", otherClass.infoToShare) // traces "from other class: YOLO!"
}
}
public class OtherClass extends EventDispatcher // must extend the event dispatcher at least
{
public var infoToShare:String;
public function OtherClass()
{
}
public function startLogic()
{
// do what you got to do
// when you have your data ready
infoToShare = "YOLO!";
dispatchEvent("otherClassCustomEvent");
}
}
Once you're confortable with that, you can start looking into building custom events that could carry the variable to send back
Ok I got the following code to work. It's really a messy solution but I didn't know of a better way. It works. I just hope it's stable and does not use a lot of resources.
If you have a much better Idea I am open.
Here is the MainDoc.as
package {
import flash.display.MovieClip;
import flash.events.*;
import com.*;
import com.views.*;
import flash.display.*;
import flash.filesystem.*;
import com.greensock.*;
import com.greensock.easing.*;
import flash.system.System;
public class mainDoc extends MovieClip
{
/// (Get Main Doc flow) this creates an instace of the main timeline
/// and then I send it
private static var _instance:mainDoc;
public static function get instance():mainDoc { return _instance; }
/// Calls the defaultVars.as in to "vars".
var vars:defaultVars = new defaultVars();
public function mainDoc()
{
/// Makes this class ready to be passed to defautVars.as
_instance = this;
// Sends the _instance to defaulVars.as to be accessed later.
vars.getMainDoc(_instance);
// Calls a function in defaultVars.as and loads a var
vars.loadButtonVars("English");
}
}
}
Here is the defaultVars.as
package com {
import flash.display.Stage;
import flash.events.*
import flash.net.*;
import flash.display.*;
import flash.filesystem.*;
public class defaultVars
{
/// Makes the MainDoc.as a MovieClip
// Not sure if this is good but it works.
public var MainDoc:MovieClip;
public function defaultVars()
{
}
public function getMainDoc(_instance:MovieClip)
{
trace("CALLED" + _instance);
/// receives the _instance var and its converted to a MovieClip
// This can now be used in any function because I declared it a public var.
MainDoc = _instance;
}
public function loadButtonVars(Language:String)
{
myLoader.load(new URLRequest("Languages/" + Language + "/vars.xml"));
myLoader.addEventListener(Event.COMPLETE, processXML);
function processXML(e:Event):void
{
myXML = new XML(e.target.data);
/// Home Screen Buttons
homeT = myXML.Button.(#Title=="homeT");
homeB1 = myXML.Button.(#Title=="homeB1");
homeB2 = myXML.Button.(#Title=="homeB2");
homeB3 = myXML.Button.(#Title=="homeB3");
homeB4 = myXML.Button.(#Title=="homeB4");
homeB5 = myXML.Button.(#Title=="homeB5");
/// HERE IS WHERE I CALL FUNCTION from MainDoc after xml is loaded.
/////////////////
trace("xml loaded!!!! " + homeB1);
MainDoc.languageLoaded(Language);
}
}
}
}

Loading flex Modules from an XML file

I am trying to parse an xml file and load Flex modules dynamically in my application. But it loads only the last module everytime. I have a singleton class which does the parsing and loading of modules. Here is the class
package
{
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
import mx.controls.Alert;
import mx.events.ModuleEvent;
import mx.modules.IModuleInfo;
import mx.modules.ModuleLoader;
import mx.modules.ModuleManager;
public class VappModuleManager
{
private static var _instance:VappModuleManager;
private static const MODULE_PATH:String="./com/emc/vapp/";
private static const MANIFEST_PATH:String="module-manifest.xml";
private var _module:IModuleInfo;
private var _handler:Function;
private var loader:URLLoader;
public function VappModuleManager(object:SingletonEnforcer)
{
}
public function set handler(handler:Function):void
{
_handler=handler;
}
public static function get instance():VappModuleManager
{
if(_instance==null)
{
_instance=new VappModuleManager(new SingletonEnforcer());
}
return _instance;
}
public function load():void
{
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE, xmlLoaded);
loader.load(new URLRequest(MANIFEST_PATH));
}
private function xmlLoaded(event:Event):void
{
Alert.show("Event Completed");
var manifest:XML=new XML(event.target.data);
Alert.show(manifest.module.length());
for (var index:int=0;index<manifest.module.length();index++)
{
Alert.show(MODULE_PATH+manifest.module[index].#name);
_module=ModuleManager.getModule(MODULE_PATH+manifest.module[index].#name);
_module.addEventListener(ModuleEvent.READY,_handler);
_module.load();
}
}
}
}
internal class SingletonEnforcer {}
I use the above class as follows.
moduleManager=VappModuleManager.instance;
moduleManager.handler=myhandler;
moduleManager.load();
I understand the problem is with eventlistener for variable "_module" but dont know how to solve it. Any help appreciated.
The call to IModuleInfo.load is asynchronous so your for loop has run completely before any of the modules have loaded. Also, your class level _module property is overwritten by a new Module instance each time the loop iterates.
I'd suggest loading each module sequentially by waiting for the READY event and initiating the load of the next module only when it has fired. I'd also fire an event when all the modules are loaded instead of executing a callback function as this will give you more flexibility (multiple objects can listen for an event for example).
The following isn't tested, but should give you the idea:
package
{
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
import mx.controls.Alert;
import mx.events.ModuleEvent;
import mx.modules.IModuleInfo;
import mx.modules.ModuleLoader;
import mx.modules.ModuleManager;
public class VappModuleManager
{
private static var _instance:VappModuleManager;
private static const MODULE_PATH:String="./com/emc/vapp/";
private static const MANIFEST_PATH:String="module-manifest.xml";
private var loader:URLLoader;
private var manifest:XML;
private var loadCount:int = 0; // track loaded modules
public function VappModuleManager(object:SingletonEnforcer)
{
}
public static function get instance():VappModuleManager
{
if(_instance==null)
{
_instance=new VappModuleManager(new SingletonEnforcer());
}
return _instance;
}
public function load():void
{
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE, xmlLoaded);
loader.load(new URLRequest(MANIFEST_PATH));
}
private function xmlLoaded(event:Event):void
{
manifest =new XML(event.target.data);
// load the first module
loadModule();
}
private function loadModule() {
// Use a locally scoped variable to avoid writing over the previous instance each time.
// You could push these onto an array if you need to be able to access them later
var module:IModuleInfo = ModuleManager.getModule(MODULE_PATH+manifest.module[loadCount].#name);
module.addEventListener(ModuleEvent.READY, moduleReadyHandler);
module.load();
}
private function moduleReadyHandler(event:ModuleEvent) {
// Remove the event listener on the loaded module
IModuleInfo(event.target).removeEventListener(ModuleEvent.READY, moduleReadyHandler);
loadCount ++;
// Are there still modules in the manifest to load?
if (loadCount < manifest.module.length()) {
// Yes... load the next module
loadModule();
} else {
// No... we're all finished so dispatch an event to let subscribers know
dispatchEvent(new Event("complete"));
}
}
}
}

Passing a variable between classes

I am trying to pass a variable "budget" from my DocumentClass of a flash file, to a class.
Currently I have :
(DocumentClassv5 , this is the code thats attached to the flash file in the properties panel, some code ommited)
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.*;
import flash.ui.Keyboard;
import flash.display.Stage;
import flash.text.TextFieldType;
import flash.media.Sound;
import flash.media.SoundChannel;
import miniGameOne;
import floorTileMC;
import flash.display.Loader;
import flash.net.URLRequest;
public class DocumentClassv5 extends MovieClip
{
/*#################################
## Defining Variables ##
#################################*/
public var budget:int = 0;
var gameOne:miniGameOne = new miniGameOne();
/*#################################
## Constructor ##
#################################*/
public function DocumentClassv5()
{
/*#################################
## Adding Event Listeners ##
#################################*/
trace("Document class loaded");
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*###################################################
## Begins the mini game ##
###################################################*/
public function begin(evt: MouseEvent)
{
beginGame.visible = false;
beginGame.removeEventListener(MouseEvent.CLICK, begin);
budget = 500;
cleanListeners();
gameOne.loadGame();
trace(gameOne.testVar);
trace(floorTile.testVar2);
/*#################################
## Adding Event Listeners ##
#################################*/
trace("Game started");
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
Then I have the miniGameOne class file, which at the moment does nothing
I also have another class file, called tileFloorMC. This is attached to a symbol.
package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import DocumentClassv5;
public class floorTileMC extends MovieClip
{
var propertyA:Number;
//var hackerClass:DocumentClassv5 = new DocumentClassv5;
public var testVar2:int = 50;
public function floorTileMC()
{
this.propertyA = randomRange(100, 500);
this.addEventListener(MouseEvent.ROLL_OVER, manageMouseOver, false, 0, true);
this.addEventListener(MouseEvent.ROLL_OUT, manageMouseOut, false, 0, true);
}
private function manageMouseOver(evt: MouseEvent)
{
this.gotoAndStop(2);
//trace(mainClass.budget);
}
private function manageMouseOut(evt: MouseEvent)
{
this.gotoAndStop(1);
//mainClass.budget += 1;
}
private function randomRange(minNum:Number, maxNum:Number):Number
{
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
}
}
Now, essentially I will need to be able to pass budget from DocumentClassv5 TO floorTileMC, and then BACK to DocumentClassv5. At the moment, I can pass anything from floorTileMC and anything from miniGameOne into DocumentClassv5, but when i try and pass from floorTileMC to DocumentClassv5, I get error
Error #2136: The SWF file file:///yadayada/GameV5.swf contains invalid data.
More specifically, as soon as I uncomment //var hackerClass:DocumentClassv5 = new DocumentClassv5;
Any help would be greatly appreciated!
Thanks,
Tiffany
You're trying to instantiate your document class in a subclass:
var hackerClass:DocumentClassv5 = new DocumentClassv5();
You want access to access the existing instance, not create a new one.
One thing you can do, is create a static reference to your document class. (see code sample below)
Static references can get ugly though, and you may just want to pass a reference of your doc class to your other classes when you instantiate them.
Both method below:
In your document class:
//instead of the line below:
var gameOne:miniGameOne = new miniGameOne(); //It's a bad idea to instantiate non primitive objects before the constructor of your document class runs.
//just declare it, and instantiate it in the constructor
var gameOne:miniGameOne;
//if you want to use a static reference:
public static var me:DocumentClassv5;
public function DocumentClassv5()
{
/*#################################
## Adding Event Listeners ##
#################################*/
//if using the static var me, set it's value to this (the instance of the document class):
me = this;
trace("Document class loaded");
gameOne = new miniGameOne(this); //pass a reference to the document class if NOT using the static var me
}
If using the static var me, you access it by doing the following from any class:
DocumentClassV5.me.budget;
Another cleaner alternative (if the values you need access to aren't really directly tied to any class, eg. global preferences), is make a whole new class that is just static (doesn't get instantiated) to hold your preferences.
package {
public class Global {
public static var budget:Number = 50;
}
}
Then you'd access budget by importing your Global class and doing Global.budget = 5