AS3 Windows style drag and drop - actionscript-3

I'm making a windows style app with different windows which contain different elements. I know how to code a drag and drop function to change the position of the windows on the stage but I'd like to use a single code for all windows without repeating infinite functions. My code is:
public function fl_WindowDrag(event: MouseEvent): void {
instance.startDrag();
}
public function fl_WindowDrop(event: MouseEvent): void {
instance.stopDrag();
}
I'd like the istance name was retrived automatically from the selected window, is it possible?
I hope you understand my need
Any help is well accepted
Thanks in advance
package {
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.ui.Keyboard;
import flash.ui.Mouse;
import flash.display.MovieClip;
public class MainTimeline extends MovieClip {
//Variabili
public var VFullscreen: int = 1;
//Import var
public var VTerminal: Terminal = new Terminal();
public var nTerminal:String;
public function MainTimeline(): void {
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
//Import
//Terminal
VTerminal.x = 288;
VTerminal.y = 384;
stage.addChild(VTerminal);
//Event Listeners
//addEventListener(MouseEvent.CLICK, fl_BringToFront);
VTerminal.addEventListener(MouseEvent.MOUSE_DOWN, fl_WindowDrag);
VTerminal.addEventListener(MouseEvent.MOUSE_UP, fl_WindowDrop);
}
//public functions
//Gestione Fullscreen
public function fl_Fullscreen(event: MouseEvent): void {
switch (VFullscreen) {
case 0:
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
VFullscreen = 1;
break;
case 1:
stage.displayState = StageDisplayState.NORMAL;
VFullscreen = 0;
break;
}
}
public function fl_FSCheck(event: Event): void {
if (stage.displayState == StageDisplayState.NORMAL) {
VFullscreen = 0;
}
if (stage.displayState == StageDisplayState.FULL_SCREEN_INTERACTIVE) {
VFullscreen = 1;
}
}
//Primo Piano Finestre
public function fl_BringToFront(event: MouseEvent): void {
this.addChild(event.currentTarget as DisplayObject);
}
public function fl_WindowDrag(event: MouseEvent): void {
event.currentTarget.startDrag();
nTerminal = event.currentTarget.name.toString();
trace(nTerminal);
}
public function fl_WindowDrop(event: MouseEvent): void {
event.currentTarget.stopDrag();
}
//Chiusura
public function fl_Close(event: MouseEvent): void {
stage.nativeWindow.close();
}
//Apertura/Chiusura Terminal
public function fl_Terminal(event: MouseEvent): void {
if (contains(VTerminal)) {
removeChild(VTerminal);
} else {
VTerminal.x = 288;
VTerminal.y = 320;
addChild(VTerminal);
}
}
}
}

There are many ways you can do this.
You can prepare base class for all windows wich will inherit this behavior and if you plan to design over a dozen of windows this is definitelly thing you should consider. Another way is to create sperarate class designed to only do this and register all windows you want to it.
But since you asking if this is even possible I would recommend you to try some third party libraries.
GreenShock has a good tool for this but i didn't use their libralies a while and I don't know what are their licecing programs.
In case you don't like it, you can use my code i made some time ago.
It's very easy to use but it's not fully implemented(can't rotate and such) and documentation is very weak but if you were interested i can help you with this.
All you need to do is pass objects you want to move along with some bassic properties:
TransformTool.addClient(target:InteractiveObject, operations:uint = 3, edgesMask:uint = 15, sizeBounds:Array = null, dragBounds:Array = null, grabRange:Number = 5):TransformData
terget - that would be your window.
operations - bit-flags representing type of transformation (scale, drag, rotate)
edgesMask - bit-flags defining which edges should be involved in scaling operation (left, right, top, bottom) all these flags values as well as operations flags can be found in TransformData class.
sizeBounds - array contian minimum and maximum size of scaled object accordingly for with and height.
dragBounds - position boundries for draged object. Basically those are arguments for flash Rectangle class.
grabRange - distance from mouse to edge in which you can grab and edge (or edges in case of corner). You can grab an edge also with mouse outside the object and scale two separate objects edges at once.
So assuming w and w2 are your windows, usage looks like this:
TransformTool.addClient(w, TransforData.SCALE|TransformData.DRAG, TransformData.BOTTOM_EDGE|TransformData.RIGHT_EDGE, null, null, 10);
TransformTool.addClient(w2, 3, 15, [20, 10, 350, 350], [100, 100, 600, 500], 10);
That is only this line required to use it.
You can also add listener if you would like to change cursor.
TransformTool.eventDispatcher.addEventListener(TransformToolEvent.EDGES_HIT, transformTestHit);
private function transformTestHit(e:TransformToolEvent):void
{
trace(TransformData(e.data).hitEdges);
}
Below is all the code involved. You can use it as you wish however be Aware that TransformTool is static class and uses only one stage instance.
I you want to develop app in Air and use native windows you would need to modify this code because each navtive window instance has its own unique stage.
TransformTool class:
package utils
{
import flash.display.DisplayObject;
import flash.display.InteractiveObject;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* ...
* #author Audionysos
*/
public class TransformTool
{
private static var clients:Vector.<TransformData> = new Vector.<TransformData>();
private static var transforming:Vector.<TransformData> = new Vector.<TransformData>();
private static var _stage:Stage;
public static var checkEdgesOnMMove:Boolean = true;
private static var _eventDispatcher:EventDispatcher = new EventDispatcher();
public static function addClient(target:InteractiveObject, operations:uint = 3, edgesMask:uint = 15, sizeBounds:Array = null, dragBounds:Array = null, grabRange:Number = 5):TransformData {
var sBR:Rectangle;
var dBR:Rectangle;
if (sizeBounds) sBR = new Rectangle(sizeBounds[0], sizeBounds[1], sizeBounds[2], sizeBounds[3]);
if (dragBounds) dBR = new Rectangle(dragBounds[0], dragBounds[1], dragBounds[2], dragBounds[3]);
var td:TransformData = new TransformData(target, operations, edgesMask, sBR, dBR, grabRange);
if (operations & TransformData.SCALE) td.allowDrag = true;
clients.push(td);
if (stage) return td;
if (!target.stage) target.addEventListener(Event.ADDED_TO_STAGE, onStage);
else { stage = target.stage; addStageListeners(); }
return td;
}
/**
* Return TransformData object associated with given target.
* #param target object associated with searched TransformData.
* #return TransformData object associated with given target.
*/
static public function getTransformData(target:InteractiveObject):TransformData {
for (var i:int = 0; i < clients.length; i++){
if (clients[i].targetObject == target) return clients[i];
}return null;
}
/**
* Mouse position relative to specifed object.
* #param target InteractiveObject or TransformData object.
* #return Mouse position relative to specifed object.
*/
static public function getTargetMouse(target:*):Point
{
var t:InteractiveObject = target as InteractiveObject;
if (!t && target as TransformData) t = TransformData(target).targetObject;
else throw new Error ("property object must be of type InteractiveObject or TransformData");
return new Point(t.parent.mouseX, t.parent.mouseY);
}
/**
* Adds MOUSE_DOWN and MOUSE_UP listener for current stage;
*/
static private function addStageListeners():void
{
//trace("TT adding stage listeners");
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMUp);
}
static private function onStage(e:Event):void
{
//trace("TT client on stage");
InteractiveObject(e.target).removeEventListener(Event.ADDED_TO_STAGE, onStage);
stage = InteractiveObject(e.target).stage;
addStageListeners();
}
static private function onMUp(e:MouseEvent):void
{
for (var i:int = 0; i < transforming.length; i++){
transforming[i].isTransforming = false;
}
transforming = new Vector.<TransformData>();
}
static private function onMDown(e:MouseEvent):void
{
//trace("TT MousDown");
findAffectedObjects();
}
static private function findAffectedObjects():void
{
for (var i:int = 0; i < clients.length; i++) {
clients[i].hitEdges = findEdges(clients[i]);
if (!clients[i].hitEdges) continue;
//trace("TT got R", clients[i].hitEdges);
transforming.push(clients[i]);
clients[i].isTransforming = true;
clients[i].updateMouseVector();
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
}
static private function onMMove(e:MouseEvent):void
{
//trace("Transforming", transforming.length);
if (TransformTool.checkEdgesOnMMove) dispatchEdges();
//trace("TT Moving");
for (var i:int = 0; i < transforming.length; i++) {
if (transforming[i].operations & TransformData.ROTATE) rotateTarget();
//if (!checkEdgesOnMMove)
transforming[i].updateMouseVector();
scaleTarget(transforming[i]);
fixSize(transforming[i]);
fixPlacement(transforming[i]);
}
}
/**
* Performs fingEdges() operation on each client TransformData object and dispatches EDGES_HIT event if result is different form last hitEdges state;
*/
static private function dispatchEdges():void
{
for (var i:int = 0; i < clients.length; i++) {
if (clients[i].isTransforming) continue;
var r:uint = findEdges(clients[i]);
if (r != clients[i].hitEdges) {
clients[i].hitEdges = r;
_eventDispatcher.dispatchEvent(new TransformToolEvent(TransformToolEvent.EDGES_HIT, clients[i]));
}
}
}
static private function rotateTarget():void
{
}
/**
* If a part of an object is outside defined dragBounds rectangle area it will move this object to closest allowed position.
* #param td
*/
static public function fixPlacement(td:TransformData):void
{
if (!td.dragBounds) return;
td.targetObject.x = Math.max(td.targetObject.x, td.dragBounds.x);
td.targetObject.x = Math.min(td.dragBounds.right - td.targetObject.width, td.targetObject.x);
td.targetObject.y = Math.max(td.targetObject.y, td.dragBounds.y);
td.targetObject.y = Math.min(td.dragBounds.bottom-td.targetObject.height, td.targetObject.y);
}
/**
* Changes the object to fit min/max size defined in sizeBounds object of the transformation data.
* #param td
*/
static public function fixSize(td:TransformData):void
{
if (!td.sizeBounds) return;
td.targetObject.width = Math.min(td.targetObject.width, td.sizeBounds.width);
td.targetObject.width = Math.max(td.targetObject.width, td.sizeBounds.x);
td.targetObject.height = Math.min(td.targetObject.height, td.sizeBounds.height);
td.targetObject.height = Math.max(td.targetObject.height, td.sizeBounds.y);
}
/**
* Scales the object accordingly to grabed edges and move of the mouse.
* #param td
*/
static public function scaleTarget(td:TransformData):void
{
//trace("TT mouse vector", td.mouseVector);
var rD:Point = td.mouseVector//new Point(td.mouseVector.x * td.targetObject.parent.scaleX, td.mouseVector.y * td.targetObject.parent.scaleY); //relativeDisplacement
if (td.hitEdges & TransformData.LEFT_EDGE) { td.targetObject.width -= rD.x; td.targetObject.x += rD.x; }
if (td.hitEdges & TransformData.RIGHT_EDGE) { td.targetObject.width += rD.x; }
if (td.hitEdges & TransformData.TOP_EDGE) { td.targetObject.height -= rD.y; td.targetObject.y += rD.y; }
if (td.hitEdges & TransformData.BOTTOM_EDGE) { td.targetObject.height += rD.y; }
}
/**
* Check if mouse position is in grab range to any of specified object edge.
* #param target examined object
* #param grabRange minimal distance from mouse position to edge of the object.
* #return resul of the inspection.
*/
static public function findEdges(td:TransformData):uint
{
if (!isMouseNearTarget(td)) return 0;
var t:InteractiveObject = td.targetObject;
var gR:Number = td.grabRange;
var r:uint;
if (Math.abs(t.x - t.parent.mouseX) < gR && t.parent.mouseX) r |= TransformData.LEFT_EDGE;
if (Math.abs(t.x + t.width- t.parent.mouseX) < gR) r |= TransformData.RIGHT_EDGE;
if (Math.abs(t.y - t.parent.mouseY) < gR) r |= TransformData.TOP_EDGE;
if (Math.abs(t.y + t.height - t.parent.mouseY) < gR) r |= TransformData.BOTTOM_EDGE;
return r;
}
/**
* Check if mouse relative position is cantained within target rectangle + grabRange;
* #param td object to examine.
* #return true if mouse is near object (edges can be grabbed);
*/
static public function isMouseNearTarget(td:TransformData):Boolean
{
td.updateMouseVector();
var exRect:Rectangle = td.targetObject.getRect(td.targetObject.parent).clone();
exRect.inflate(td.grabRange, td.grabRange);
return exRect.containsPoint(td.mouseStart);
}
/**
* Dispatches events associated with transformed client objects.
* TransformToolEvent contains reference to interested TransformData object.
* #eventType TransformToolEvent.EDGE_HIT dispatched when mouse cursor is close enought client object edges to let it to be scaled.
* You can for example use it's hitEdges property to change cursor icon accordingly.
*/
static public function get eventDispatcher():EventDispatcher
{
return _eventDispatcher;
}
/**
* Stage property on which mouse events will be proceded.
* This will be set automaticly from client object (it it was null before).
*/
static public function get stage():Stage
{
return _stage;
}
static public function set stage(value:Stage):void
{
if (_stage) {
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMMove);
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMUp);
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMDown);
}
_stage = value;
addStageListeners();
if(checkEdgesOnMMove) value.addEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
}
}
TransformData class:
package utils
{
import flash.display.InteractiveObject;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* ...
* #author Audionysos
*/
public class TransformData
{
public static const SCALE:uint = 1;
public static const DRAG:uint = 2;
public static const ROTATE:uint = 4;
public static const TOP_EDGE:uint = 1;
public static const RIGHT_EDGE:uint = 2;
public static const BOTTOM_EDGE:uint = 4;
public static const LEFT_EDGE:uint = 8;
public var targetObject:InteractiveObject;
public var grabRange:Number;
public var sizeBounds:Rectangle;
public var dragBounds:Rectangle;
public var mouseStart:Point;
public var mouseVector:Point;
public var hitEdges:uint;
public var edgesMask:uint;
public var operations:uint;
public var isTransforming:Boolean;
private var _allowDrag:Boolean;
private var isDraging:Boolean;
public function TransformData(target:InteractiveObject, operations:uint = 3, edgesMask:uint = 15, sizeBounds:Rectangle = null, dragBounds:Rectangle = null, grabRange:Number = 5)
{
targetObject = target;
this.sizeBounds = sizeBounds;
this.dragBounds = dragBounds;
this.grabRange = grabRange;
this.edgesMask = edgesMask;
this.operations = operations;
}
public function updateMouseVector () {
var mP:Point = new Point(targetObject.parent.mouseX, targetObject.parent.mouseY);
if (!mouseStart) mouseStart = mP;
mouseVector = mP.subtract(mouseStart);
mouseStart = mP;
}
public function get allowDrag():Boolean
{
return _allowDrag;
}
public function set allowDrag(value:Boolean):void
{
if (_allowDrag && !value) {
targetObject.stage.removeEventListener(MouseEvent.MOUSE_UP, onMUp);
targetObject.removeEventListener(MouseEvent.MOUSE_DOWN, onMDown);
if (isDraging) targetObject.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
_allowDrag = value;
if (value) targetObject.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
}
private function onMDown(e:MouseEvent):void
{
isTransforming = true;
mouseStart = TransformTool.getTargetMouse(this);
targetObject.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMMove);
targetObject.stage.addEventListener(MouseEvent.MOUSE_UP, onMUp);
}
private function onMUp(e:MouseEvent):void
{
isTransforming = false;
targetObject.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
private function onMMove(e:MouseEvent):void
{
updateMouseVector();
targetObject.x += mouseVector.x;
targetObject.y += mouseVector.y;
TransformTool.fixPlacement(this);
}
}
}
TransformToolEvent:
package utils
{
import flash.events.Event;
/**
* ...
* #author Audionysos
*/
public class TransformToolEvent extends Event
{
public static const EDGES_HIT:String = "edgesHit";
private var _data:TransformData;
public function TransformToolEvent(type:String, data:TransformData, bubbles:Boolean=false, cancelable:Boolean=false) {
super(type, bubbles, cancelable);
_data = data;
}
public override function clone():Event {
return new TransformToolEvent(type, _data, bubbles, cancelable);
}
public override function toString():String {
return formatToString("TransformToolEvent", "type", "bubbles", "cancelable", "eventPhase", "data");
}
public function get data():TransformData {
return _data;
}
}
}

You can use the target or currentTarget propterty of the mouse-event to reference the instance that triggers the event, like this (i have not tested this code):
public function fl_WindowDrag(event: MouseEvent): void {
event.currentTarget.startDrag();
}
this way you can add the event handler to multiple instances. You can read more about the events properties here

Related

Image remains null no matter what I do

I am working on a Action Script project and no matter what I did I wasn't able to get a texture from a Atlas, in the end I had to do some quick changes that I rather not keep. Does anyone know why I cannot get a texture from the createDiabloCrashArt method with this:
package gameObjects
{
import starling.core.Starling;
import starling.display.Image;
import starling.display.MovieClip;
import starling.display.Sprite;
import starling.events.Event;
import starling.utils.deg2rad;
public class Diablo extends Sprite
{
private var _type:int;
private var _speed:int;
private var _distance:int;
private var _alreadyHit:Boolean;
private var _position:String;
private var _hitArea:Image;
private var diabloImage:Image;
private var diabloAnimation:MovieClip;
private var diabloCrashImage:Image;
public function Diablo(_ptype:int, _pdistance:int)
{
super();
this._type = _ptype;
this._distance = _pdistance;
this._speed = GameConstants.DIABLO_SPEED;
_alreadyHit = false;
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(e:Event):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
createDiabloArt();
}
private function createDiabloArt():void
{ //Gets some other stuff using the same getAtlas but as MovieAnimation and works.
}
private function createDiabloCrashArt():void
{
// trace("diablo_chingo" + _type + "KO");
if (diabloCrashImage == null)
{
diabloCrashImage = new Image(Assets.getAtlas().getTexture("diablo_chingo" + _type + "KO"));
this.addChild(diabloCrashImage);
}
else
{
diabloCrashImage.texture = Assets.getAtlas().getTexture("diablo_chingo" + _type + "KO");
}
diabloCrashImage.visible = false;
}
private function hidePreviousInstance():void
{
if (diabloAnimation != null && _type <= GameConstants.DIABLO_TYPE_4)
{
diabloAnimation.visible = false;
Starling.juggler.remove(diabloAnimation);
}
if (diabloImage != null) diabloImage.visible = false;
}
public function get type():int { return _type; }
public function set type(value:int):void
{
_type = value;
resetForReuse();
hidePreviousInstance();
createDiabloArt();
}
public function get alreadyHit():Boolean { return _alreadyHit; }
public function set alreadyHit(value:Boolean):void
{
_alreadyHit = value;
if (value)
{
diabloCrashImage.visible = true;
if (_type >= GameConstants.DIABLO_TYPE_1 || _type <= GameConstants.DIABLO_TYPE_4)
{
diabloAnimation.visible = false;
}
else
{
diabloImage.visible = false;
Starling.juggler.remove(diabloAnimation);
}
}
}
public function resetForReuse():void
{
this.alreadyHit = false;
this.rotation = deg2rad(0);
}
}
}
But it works by changing the following things:
private function onAddedToStage(e:Event):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
createDiabloArt();
createDiabloCrashArt();
}
private function createDiabloCrashArt():void
{
// trace("diablo_chingo" + _type + "KO");
if (diabloCrashImage == null)
{
diabloCrashImage = new Image(Assets.getTexture("Diablo1"));
this.addChild(diabloCrashImage);
}
else
{
diabloCrashImage.texture = Assets.getTexture("Diablo1");
//Assets.getAtlas().getTexture("diablo_chingo" + _type + "KO");
}
diabloCrashImage.visible = false;
}
I verified time and time again with debugger, trace and the like that the right parameters where reaching the function such as _type, as a matter of fact in the long method that I didn't include getting the texture I need using the above syntax worked wonderfully.
I tried to:
Change Image to MovieClip
Initialize before getting to createCrashArt
Getting other textures like the ones I can already display (didn't work)
Staring at it really hard.
Setting a default string for the texture.
None yielded anything until I changed the code to look like in the second snippet, the thing is that I don't get why it didn't work and I rather not depend on a quick fix that may or may not turn into a setback later.
Seriously any help to understand this would be great. I don't even care that ir is working right now I just can't for the life of me figure what was wrong in the first place.
Thanks in advance.
EDIT:
public static function getAtlas():TextureAtlas
{
if (gameTextureAtlas == null)
{
var texture:Texture = getTexture("AtlasTextureGame");
var xml:XML = XML(new AtlasXmlGame());
gameTextureAtlas=new TextureAtlas(texture, xml);
}
return gameTextureAtlas;
}
/**
* Returns a texture from this class based on a string key.
*
* #param name A key that matches a static constant of Bitmap type.
* #return a starling texture.
*/
public static function getTexture(name:String):Texture
{
if (gameTextures[name] == undefined)
{
var bitmap:Bitmap = new Assets[name]();
gameTextures[name]=Texture.fromBitmap(bitmap);
}
//trace("Tomando textura!");
return gameTextures[name];
}
EDIT: Assets class
package
{
import flash.display.Bitmap;
import flash.utils.Dictionary;
import starling.textures.Texture;
import starling.textures.TextureAtlas;
public class Assets
{
/**
* Atlas de texturas.
*/
[Embed(source="../Witchmedia/graphics/Spritesheet/ScarletWitch.png")]
public static const AtlasTextureGame:Class;
[Embed(source="../Witchmedia/graphics/Spritesheet/ScarletWitch.xml", mimeType="application/octet-stream")]
public static const AtlasXmlGame:Class;
/**
* Assets de Fondo y botones.
*/
[Embed(source="../Witchmedia/graphics/bgLayer3.jpg")]
public static const BgLayer1:Class;
[Embed(source="../Witchmedia/graphics/Diablo1.png")]
public static const Diablo1:Class;
/**
* Cache de Texturas
*/
private static var gameTextures:Dictionary = new Dictionary();
private static var gameTextureAtlas:TextureAtlas;
/**
* Returna una instancia del atlas de texturas.
* #return the TextureAtlas instance (Singleton)
*/
public static function getAtlas():TextureAtlas
{
if (gameTextureAtlas == null)
{
var texture:Texture = getTexture("AtlasTextureGame");
var xml:XML = XML(new AtlasXmlGame());
gameTextureAtlas=new TextureAtlas(texture, xml);
}
return gameTextureAtlas;
}
/**
* Returns a texture from this class based on a string key.
*
* #param name A key that matches a static constant of Bitmap type.
* #return a starling texture.
*/
public static function getTexture(name:String):Texture
{
if (gameTextures[name] == undefined)
{
var bitmap:Bitmap = new Assets[name]();
gameTextures[name]=Texture.fromBitmap(bitmap);
}
//trace("Tomando textura!");
return gameTextures[name];
}
}
Can you check with this method, Give the texture declaration in a separate class, i guess it doesnt take the appropriate texture.
public static function getAtlas(atlasNumb:uint = 1):TextureAtlas
{
if(sTextureAtlas[atlasNumb - 1] == null)
{
var texture:Texture = getTexture("AtlasTexture"+atlasNumb);
var xml:XML = XML(create("AtlasXml"+atlasNumb));
sTextureAtlas[atlasNumb-1] = new TextureAtlas(texture, xml);
}
return sTextureAtlas[atlasNumb - 1];
}
private static function create(name:String):Object
{
var textureClass:Class = AssetEmbeds_2x;
return new textureClass[name];
}
And define the textures .png and xml in a separate file called AssetEmbeds_2x.
while calling the texture define like
Assets.getAtlas(1).getTextures("xxx"). I hope it wll

MVC AS3 Error: Call to a possibly undefined method through a reference with static type

I'm new to AS3 from Java and was trying to implement a Java style as3 mvc implementation which essentially has two views with an input field and text box which has it's contents changed by buttons.
I keep getting Error: Call to a possibly undefined method handleMouseClick through a reference with static type controller:Controller. and can't understand why. This is for the function handleMouseClick in TextToolsView
Here is my code (sorry for it being so long, I'm not sure how to condense it further without losing my error):
TextModel
package model
{
import flash.events.Event;
import flash.events.EventDispatcher;
public class TextModel extends EventDispatcher
{
private var text:String = new String();
private var initialText:String = new String("Initial Text");
public function TextModel()
{
setText(initialText);
}
public function setText(text:String):void {
this.text = text;
}
public function getText():String {
return this.text;
}
public function updateText(text:String):void {
setText(text);
dispatchEvent(new Event(Event.CHANGE));
}
public function clearText():void {
setText("Text has been cleared");
dispatchEvent(new Event(Event.CHANGE));
}
public function resetText():void {
setText(initialText);
dispatchEvent(new Event(Event.CHANGE));
}
}
}
TextController
package controller
{
import flash.events.MouseEvent;
import model.TextModel;
public class TextController extends AbstractController
{
/**
* Constructor
* #param m model to modify
*/
public function TextController(m:TextModel)
{
super(m);
}
private function updateText(text:String):void {
TextModel(getModel()).updateText(text);
}
private function clearText():void {
TextModel(getModel()).clearText();
}
private function resetText():void {
TextModel(getModel()).resetText();
}
/*override public function update(obj: Object) {
}*/
public function handleMouseClick(event:MouseEvent):void {
switch(event.currentTarget.id) {
case "_updateButton":
updateText("TEXT INPUT TO BE ADDED LATER");//add text input later
break;
case "_clearButton":
clearText();
break;
case "_resetButton":
resetText();
break;
}
}
}
}
AbstractController
package controller
{
import model.TextModel;
import view.View;
/**
* Provides basic services for the "controller" of
* a Model/View/Controller triad.
*
*/
public class AbstractController
{
private var model:TextModel;
private var view:View;
public function AbstractController(m:TextModel)
{
setModel(m);
}
public function setModel(m:TextModel):void
{
model = m;
}
public function getModel():TextModel
{
return model;
}
public function setView(v:View):void
{
view = v;
}
public function getView():View
{
return view;
}
public function update(obj:Object):void {
}
}
}
TextBoxView
package view
{
import controller.Controller;
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;
import flash.text.TextFormat;
import model.TextModel;
import model.TextUpdate;
/**
* ...
*/
public class TextBoxView extends AbstractView {
private var wrapper:Sprite = new Sprite();
private var textBox:TextField = new TextField();
private var inputField:TextField = new TextField();
public function TextBoxView(m:TextModel, c:Controller, x:int, y:int) {
super(m, c);
textBox.text = "This is a text Panel with lots of text!!!!!!!!!!!!dghsdfghdfghdfghdfghdfghdfghdfghdfghdfghdfghdfghdfghdfgh";
textBox.border = true;
textBox.borderColor = 0x000000;
textBox.multiline = true;
textBox.width = 425;
textBox.height = 115;
textBox.x = 145;
textBox.y = 20;
textBox.wordWrap = true;
var myFormat:TextFormat = new TextFormat();
myFormat.color = 0xAA0000;
myFormat.size = 24;
myFormat.italic = true;
//myFormat.align = TextFormatAlign.CENTER
textBox.setTextFormat(myFormat);
addEventListener(Event.CHANGE, this.update);
//inputable text box
inputField.border = true;
inputField.width = 200;
inputField.height = 150;
inputField.x = 200;
inputField.y = 50;
inputField.type = "input";
inputField.multiline = true;
wrapper.addChild(textBox);
wrapper.addChild(inputField);
addChild(wrapper);
}
public function update(event:Event):void {
textBox.text = super.getModel().getText();
}
}
}
TextToolsView
package view
{
import controller.Controller;
import flash.events.Event
import controller.TextController;
import flash.display.Sprite;
import flash.events.MouseEvent;
import model.TextModel;
import model.TextUpdate;
import ui.CustomButton;
public class TextToolsView extends AbstractView
{
private var updateButton:CustomButton;
private var clearButton:CustomButton;
private var resetButton:CustomButton;
private var wrapper:Sprite = new Sprite();
private var textModel:TextModel;
private var textController:TextController;
public function TextToolsView(m:TextModel, c:Controller, x:int, y:int) {
super(m, c);
makeTools(x, y);
}
override public function defaultController (model:TextModel):Controller {
return new TextController(model);
}
private function makeTools(x:int, y:int):void {
updateButton = new CustomButton("update", "_updateButton", 100, 22);
updateButton.x = 0;
updateButton.y = 0;
updateButton.addEventListener(MouseEvent.CLICK, handleMouseClick);
clearButton = new CustomButton("clear", "_clearButton", 100, 22);
clearButton.x = 120;
clearButton.y = 0;
clearButton.addEventListener(MouseEvent.CLICK, handleMouseClick);
resetButton = new CustomButton("reset", "_resetButton", 100, 22);
resetButton.x = 240;
resetButton.y = 0;
resetButton.addEventListener(MouseEvent.CLICK, handleMouseClick);
wrapper.x = x;
wrapper.y = y;
wrapper.addChild(updateButton);
wrapper.addChild(clearButton);
wrapper.addChild(resetButton);
addChild(wrapper);
}
private function handleMouseClick(event:MouseEvent):void {
super.getController().handleMouseClick(event);
}
}
}
Abstract View
package view
{
import controller.Controller;
import flash.display.Sprite;
import model.TextModel;
/**
* Provides basic services for the "view" of
* a Model/View/Controller triad.
*/
public class AbstractView extends Sprite
{
private var model:TextModel;
private var controller:Controller;
public function AbstractView(m:TextModel, c:Controller)
{
setModel(m);
setController(c);
}
/**
* returns the default controller for this view
*/
public function defaultController (model:TextModel):Controller {
return null;
}
/**
* Sets the model this view is observing.
*/
public function setModel (m:TextModel):void {
model = m;
}
/**
* Returns the model this view is observing.
*/
public function getModel ():TextModel {
return model;
}
/**
* Sets the controller for this view.
*/
public function setController (c:Controller):void {
controller = c;
// Tell the controller this object is its view.
getController().setView(this);
}
/**
* Returns this view's controller.
*/
public function getController():Controller {
return controller;
}
}
}
I won't post the custom button because essentially it works fine like any normal button.
and Main
package
{
import controller.TextController;
import flash.display.Sprite;
import flash.events.Event;
import model.TextModel;
import view.TextBoxView;
import view.TextToolsView;
/**
* ...
*/
public class Main extends Sprite
{
private var text_model:TextModel;
private var text_box:TextBoxView;
private var text_tools:TextToolsView;
private var textController:TextController;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
text_model = new TextModel();
textController = new TextController(text_model);
text_box = new TextBoxView(text_model, textController, 0,0);
//text_model.addObserver(text_box);
text_tools = new TextToolsView(text_model, textController, 120, 300);
//text_model.addObserver(text_tools);
addChild(text_box);
addChild(text_tools);
}
}
}
I don't see code of Controller, but I think problem is linked to it.
super.getController().handleMouseClick(event);
In this code getController() method returns Controller instance, but this class doesn't contain method handleMouseClick(). So, I think, you need to cast Controller to TextController like this:
(getController() as TextController).handleMouseClick(event);

as3 addEventListner on a function in another class

I have a class calling a function in another class. I want to know
if we can add an Event Listener to know if that function has fired and is finished etc.
Here is the section of the code that is relevant.
myMC = new pictures();
addChild(myMC);
myMC.loadImages("Joyful",1)
// Add Event Listener here to let me know loadImages was called and worked.
As you can see the function is called loadImages() and it is located in a class called pictures.as
Can I add an event listener to this?
Here is a new issue. I am using a similar method and I used your example below and it did not work. Am I missing an import or something? I am only showing the functions that pertain and not my whole script.
Main.class
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.display.*;
import flash.filesystem.*;
import com.greensock.*;
import com.greensock.easing.*;
import flash.system.System;
// Ed's Scripts
import com.*;
import com.views.*;
public class iRosaryMain extends MovieClip
{
/// (Get Main Doc flow) this creates an instace of the main timeline
/// and then I send it
private static var _instance:iRosaryMain;
public static function get instance():iRosaryMain
{
return _instance;
}
/// Declaring Vars
var audio:audioPrayers;
/// Loading Images
//public var theImages:pictures = new pictures();
/// Movie Clips
public var myMary:beautifulMary;
public var myMC:MovieClip;
public var myPic:MovieClip;
public var myFlags:MovieClip;
public static var mt:MovieClip;
var vars:defaultVars = new defaultVars();
public function iRosaryMain()
{
// (Get Main Doc flow) Here I send the an instacne of iRosaryMain to defaultVars.as
_instance = this;
vars.getMainDoc(_instance);
// Sets timeline to mt :) I hope
mt = _instance;
audio = new audioPrayers();
trace("Jesus I trust in you!");// constructor code
audio.sayHailMary();
if (stage)
{
init();
}
}
public function moveLanguages()
{
/// File to languages folder
var checkLanguageFolder:File = File.applicationStorageDirectory.resolvePath("Languages");
///// CHECK LANGUAGES FOLDER - if not in App Storage move it
if (! checkLanguageFolder.exists)
{
var sourceDir:File = File.applicationDirectory.resolvePath("Languages");
var resultDir:File = File.applicationStorageDirectory.resolvePath("Languages");
sourceDir.copyTo(resultDir, true);
trace( "Moved Language!");
}
}
//// MAIN FUNCTIONS IN iRosaryMainClass
function init()
{
//loadFlags();
moveLanguages();
//addChild(theImages);
intro();
}
public function loadFlags()
{
myFlags.addEventListener("MyEvent", eventHandler);
myFlags = new viewLanguages();
addChild(myFlags);
myFlags.x = stage.stageWidth / 2 - myFlags.getBounds(this).width / 2;
function eventHandler()
{
trace("yes loaded");
TweenMax.fromTo(myMary,3, {alpha:1}, {alpha:0, ease:Quint.easeOut, onComplete: closePic} );
}
}
function intro()
{
myMary = new beautifulMary();
addChild(myMary);
loadFlags();
}
public function closePic()
{
removeChild(myMary);
}
public function languageLoaded(lang:String)
{
trace("YES... " + lang);
homeIn();
}
public function homeIn()
{
if (myFlags)
{
TweenMax.fromTo(myFlags,1, {x:myFlags.x}, {x:0-myFlags.width, ease:Quint.easeInOut, onComplete:unloadMyFlags} );
}
function unloadMyFlags()
{
trace("Called Ease out");
if (myFlags is MovieClip)
{
//trace("CURRENT DISPLAY " + currentDisplayScreen);
trace("CURRENT mc " + myFlags);
removeChild(myFlags);
System.gc();
myFlags = null;
trace("CURRENT mc " + myFlags);
}
}
if (! myMC)
{
myMC = new viewHome();
myMC.name = "Home";
myMC.x = stage.stageWidth / 2 - myMC.width / 2;
addChild(myMC);
}
theEaseIn(myMC);
//Home.B1.addEventListener(MouseEvent.CLICK, theEaseOut(Home));
}
public function loadLanguage(Language:String):Function
{
return function(e:MouseEvent):void ;
{
trace("Did it work? " +Language);
vars.loadButtonVars(Language);;
};
//TweenMax.fromTo(EnglishButton,1, {x:EnglishButton.x}, {x:0-EnglishButton.width, ease:Quint.easeOut} );
}
public function loadView(screen:String)
{
trace("Received " + screen);
if (screen=="Home")
{
myMC = new viewHome();
addChild(myMC);
theEaseIn(myMC);
//Home.B1.addEventListener(MouseEvent.CLICK, theEaseOut(Home));
}
if (screen=="PrayTheRosary")
{
myMC = new viewPrayTheRosary();
addChild(myMC);
theEaseIn(myMC);
//Home.B1.addEventListener(MouseEvent.CLICK, theEaseOut(Home));
}
if (screen=="Options")
{
myMC = new viewOptions();
addChild(myMC);
theEaseIn(myMC);
}
if (screen=="Downloads")
{
myMC = new viewDownloads();
addChild(myMC);
theEaseIn(myMC);
}
if (screen=="beautifulMary")
{
myMC = new beautifulMary();
addChild(myMC);
theEaseIn(myMC);
}
if (screen=="Flags")
{
myFlags = new viewLanguages();
addChild(myFlags);
theEaseIn(myFlags);
}
if (screen=="Joyful" || screen=="Sorrowful" || screen=="Glorious" || screen=="Luminous")
{
myPic = new pictures();
addChild(myPic);
myPic.addEventListener( "ImagesLoaded", doTheEaseIn);
myPic.loadImages(""+screen+"",1);
function doTheEaseIn()
{
theEaseIn(myPic);
}
}
}
public function theEaseIn(mc:MovieClip)
{
if (myMC)
{
TweenMax.fromTo(mc,1, {x:stage.stageWidth+mc.width}, {x:stage.stageWidth/2 - mc.width/2, ease:Quint.easeInOut} );
}
}
public function theEaseOut(mc:MovieClip,nextMC:String):Function
{
return function(e:MouseEvent):void ;
{
loadView(nextMC);
/// Tweens out view on screen
TweenMax.fromTo(mc,1, {x:mc.x}, {x:0-mc.width, ease:Quint.easeInOut, onComplete:unloadMC} );
function unloadMC();
{
trace("Called Ease out");
if(mc is MovieClip);
{
//trace("CURRENT DISPLAY " + currentDisplayScreen);
trace("CURRENT mc " + mc);
removeChild(mc);
System.gc();
myMC = null;
trace("CURRENT mc " + mc);
};
};
};/// end return
}
////////////
}/// End iRosaryMain
}// End Package
viewLanguages.as
package com.views
package com.views
{
import flash.display.MovieClip;
import flash.filesystem.File;
import com.roundFlag;
import flash.events.*;
import flash.display.*;
public class viewLanguages extends MovieClip
{
var Flag:MovieClip;
//public static const FLAGS_LOADED:String = "flagsLoaded";
public function viewLanguages()
{
getLang();
}
function numCheck(num:int):Boolean
{
return (num % 2 != 0);
}
/// Get for App Opening
public function getLang()
{
/// When Live
var folderLanguages:File = File.applicationStorageDirectory.resolvePath("Languages");
var availLang = folderLanguages.getDirectoryListing();
var Lang = new Array();
var LangPath = new Array();
var fl:int = 0;
for (var i:uint = 0; i < availLang.length; i++)
{
if (availLang[i].isDirectory)
{
//flag = new Loader();
//flag.load(new URLRequest(File.applicationStorageDirectory.url + "Languages/" + Lang[i] + "/roundFlag.png"));
Lang.push(availLang[i].name);
LangPath.push(availLang[i].nativePath);
Flag = new roundFlag(availLang[i].name);
Flag.name = availLang[i].name;
if (numCheck(i)==false)
{
Flag.y = fl;
Flag.x = 0;
}
else
{
Flag.y = fl;
Flag.x = Flag.width + 33;
fl = fl + Flag.height + 33;
}
Flag.btext.text = availLang[i].name;
addChild(Flag);
trace(availLang[i].nativePath);// gets the name
trace(availLang[i].name);
}
}
trace("Get Lang Called");
dispatchEvent(new Event("MyEvent"));
}
}
}
Yes, you can. Considering you are adding your clip to the display list I assume it extends either Movieclip or Sprite, both of which extend EventDispatcher. In your pictures class you can simply use dispatchEvent(new Event("MyEvent"); to dispatch an event. Then you could add myMC.addEventListener("MyEvent", eventHandler); to react to it.
You should also not use strings for events like I wrote above. It would be better if you declared a public static const IMAGES_LOADED:String = "imagesLoaded"; in your pictures class. Then you should use this constant by dispatching and by listening to it.
EDIT: Here how it would look with the constant:
//your class
package {
import flash.events.Event;
import flash.display.Sprite;
public class Pictures extends Sprite {
public static const IMAGES_LOADED:String = "imagesLoaded";
public function Pictures() {
}
public function onAllImagesLoaded():void {
dispatchEvent(new Event(IMAGES_LOADED));
}
//rest of your methods
}
}
//you would call it like this:
var myMc:Pictures = new Pictures();
myMc.addEventListener(Pictures.IMAGES_LOADED, onImagesLoaded);
myMc.loadImages();
function onImagesLoaded(e:Event):void {
//...etc
}
You have to create custom event class for this to work. Like:
package com.some
{
import flash.events.Event;
public class SomeEvent extends Event
{
// Loading events
public static const MAINDATA_LOADING:String = "onMainDataLoading";
// Other event
public static const SOME_LOADING:String = "onSomeLoading";
public var params:Object;
public function SomeEvent($type:String, $params:Object, $bubbles:Boolean = false, $cancelable:Boolean = false)
{
super($type, $bubbles, $cancelable);
this.params = $params;
}
public override function clone():Event
{
return new SomeEvent(type, this.params, bubbles, cancelable);
}
}
}
Add event dispatch inside wanted class (Pictures) and pass wanted params to event (this or any else)
dispatchEvent(new SomeEvent(SomeEvent.IMAGES_LOADED, this));
Handle event listening:
var myMc:Pictures = new Pictures();
myMc.addEventListener(SomeEvent.IMAGES_LOADED, onImagesLoaded);
myMc.loadImages();
function onImagesLoaded(e:SomeEvent):void {
// handle event.
var picts:Pictures = (e.params as Pictures);
}

ActionScript compilation error: The name of definition 'Main' does not reflect the location of this file

Can someone tell me what I am doing wrong with this?
I have a movie clip called turret that is on the screen and is instanced as Turret,
I have a movie clip called bullet and that is in the library exported for AS "bullet" no quotes.
Here is the website http://wonderfl.net/c/du34
My frame (main) class is called du34
My code for du34 is:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(width=1000, height=1000, framerate=24)]
public class Main extends Sprite
{
private static const SCREEN_WIDTH: int = 1000
private static const SCREEN_HEIGHT: int = 1000
private var turret: Turret = null
private var me: MouseEvent = null
private var trigger: Boolean = false
private var bullets: Array = []
public function Main():void
{
graphics.beginFill(0x0)
graphics.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)
graphics.endFill()
turret = new Turret(SCREEN_WIDTH / 2, SCREEN_HEIGHT)
turret.addEventListener(Turret.ADD_BULLET, onAddBullet)
addChild(turret)
addEventListener(Event.ENTER_FRAME, onEnterFrame)
stage.addEventListener(MouseEvent.MOUSE_DOWN, function(): void { trigger = true } )
stage.addEventListener(MouseEvent.MOUSE_UP, function(): void { trigger = false } )
}
private var nextAddBullet: Bullet = null;
private function onAddBullet(e: BulletEvent): void {
nextAddBullet = new Bullet(turret.x + e.pos, turret.y, mouseX, mouseY)
}
private var frameProcessing: Boolean = false
private function onEnterFrame(e: Event): void {
if (frameProcessing) return
frameProcessing = true
if (null != nextAddBullet) {
bullets.push(nextAddBullet)
addChild(nextAddBullet)
nextAddBullet = null
}
turret.frameAction(trigger)
var i: int
for (i = 0; i < bullets.length; i++) {
var bullet: Bullet = bullets[i]
if (null != bullet) {
if (bullet.frameAction()) {
removeChild(bullet)
bullets[i] = null
}
}
}
i = bullets.length
while (0 < i--) {
if (null == bullets[i]) bullets.splice(i, 1)
}
frameProcessing = false
}
}
}
import flash.events.Event
import flash.display.Sprite
import flash.geom.Point
class BulletEvent extends Event {
private var _pos: int = 0
public function get pos(): int { return _pos }
public function BulletEvent(type:String, pos: int, bubbles:Boolean = false, cancelable:Boolean = false) {
super(type, bubbles, cancelable);
_pos = pos;
}
}
// 弾丸
class Bullet extends Sprite {
private var t: Point
private var d: Point
private static const BULLET_SIZE: int = 3
public function Bullet(_x: int, _y: int, _tx: int, _ty: int): void {
graphics.beginFill(0xFFFFFF)
graphics.drawEllipse(-BULLET_SIZE/2, -BULLET_SIZE/2, BULLET_SIZE, BULLET_SIZE)
graphics.endFill()
x = _x
y = _y
t = new Point(_tx, _ty)
d = t.subtract(new Point(x, y))
d.normalize(10)
frameAction()
}
public function frameAction(): Boolean {
x += d.x
y += d.y
var cx: Boolean = (0 <= d.x) ? t.x <= x : x <= t.x;
var cy: Boolean = (0 <= d.y) ? t.y <= y : y <= t.y;
return (cx && cy)
}
}
// 砲身
class Barrel extends Sprite {
private static const BARREL_LENGTH: int = 20
private var _pos: int = 0
private var _loading: int = 0
public function get pos(): int { return _pos }
public function loading(): Boolean { return 0 < _loading }
public function Barrel(pos: int = 0) { _pos = pos }
public function frameAction(): void {
if (0 < _loading) _loading -= 2
var d: Point = new Point(mouseX, mouseY)
d.normalize(BARREL_LENGTH - _loading)
graphics.clear()
graphics.lineStyle(2, 0xc0c0c0)
graphics.moveTo(_pos, 0)
graphics.lineTo(d.x + _pos, d.y)
}
public function shot(): void {
_loading = 8
}
}
// 砲塔
class Turret extends Sprite {
public static const ADD_BULLET: String = "addBullet"
private static const SIZE: int = 25
private var barrels: Array = []
private var actionIndex: int = 0
private var _loading: int = 0
public function Turret(_x: int, _y: int): void {
x = _x
y = _y
barrels.push(new Barrel(-3))
barrels.push(new Barrel(0))
barrels.push(new Barrel(+3))
for each (var barrel: Barrel in barrels) addChild(barrel)
var armor: Sprite = new Sprite()
with (addChild(armor)) {
graphics.beginFill(0xe0e0e0)
graphics.drawEllipse(-SIZE/2, -SIZE/2, SIZE, SIZE)
graphics.endFill()
}
}
public function loading(): Boolean { return 0 < _loading }
public function shot(): void {
if (loading()) return
actionIndex = (actionIndex + 1) % barrels.length
var barrel: Barrel = barrels[actionIndex]
if (barrel.loading()) return
barrel.shot()
_loading = 3;
dispatchEvent(new BulletEvent(ADD_BULLET, barrel.pos))
}
public function frameAction(trigger: Boolean): void {
if (0 < _loading) _loading -= 1
if (trigger) shot()
for each (var barrel: Barrel in barrels) barrel.frameAction()
}
}
I keep getting the compiled error
5008: The name of definition 'Main' does not reflect the location of this file. Please change the definition's name inside this file, or rename the file.du34.as
Follow the advice in the error. Rename the Main class inside the package definition to du34 (or whatever the AS3 file is called), or rename the file it is in to Main. The class and filename have to match:
ActionScript 3.0 allows you to include multiple classes in one source file, but only one class in each file can be made available to code that is external to that file. In other words, only one class in each file can be declared inside a package declaration. You must declare any additional classes outside your package definition, which makes those classes invisible to code outside that source file. The name of the class declared inside the package definition must match the name of the source file.
Do you need more semicolons ? It seems a lot of semicolons are missing.
Perhaps changing the class name might help.
In actionscript under normal uses you need one class per "as" file.
The "as" file needs to be named the same as the class.
Class names should be named with a captial first letter ex:MyClass
All class files need to be included in a package.
A package structure needs to reflex the director it is in relation to the source fla/mxml files
In your sample code you supplied you have 5 classes and you need 5 "as" files
The following example assumes the package/class is in the same directory as your FLA
saved off as Main.as
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(width=1000, height=1000, framerate=24)]
public class Main extends Sprite
{
private static const SCREEN_WIDTH: int = 1000
private static const SCREEN_HEIGHT: int = 1000
private var turret: Turret = null
private var me: MouseEvent = null
private var trigger: Boolean = false
private var bullets: Array = []
public function Main():void
{
graphics.beginFill(0x0)
graphics.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)
graphics.endFill()
turret = new Turret(SCREEN_WIDTH / 2, SCREEN_HEIGHT)
turret.addEventListener(Turret.ADD_BULLET, onAddBullet)
addChild(turret)
addEventListener(Event.ENTER_FRAME, onEnterFrame)
stage.addEventListener(MouseEvent.MOUSE_DOWN, function(): void { trigger = true } )
stage.addEventListener(MouseEvent.MOUSE_UP, function(): void { trigger = false } )
}
private var nextAddBullet: Bullet = null;
private function onAddBullet(e: BulletEvent): void
{
nextAddBullet = new Bullet(turret.x + e.pos, turret.y, mouseX, mouseY)
}
private var frameProcessing: Boolean = false
private function onEnterFrame(e: Event): void
{
if (frameProcessing) return
frameProcessing = true
if (null != nextAddBullet) {
bullets.push(nextAddBullet)
addChild(nextAddBullet)
nextAddBullet = null
}
turret.frameAction(trigger)
var i: int
for (i = 0; i < bullets.length; i++) {
var bullet: Bullet = bullets[i]
if (null != bullet) {
if (bullet.frameAction()) {
removeChild(bullet)
bullets[i] = null
}
}
}
i = bullets.length
while (0 < i--) {
if (null == bullets[i]) bullets.splice(i, 1)
}
frameProcessing = false
}
}
}
you still need "as" files for BulletEvent, Bullet, Barrel, Turret
Try this.. Rename the Main class inside the package definition to du34. In the directory (same location with .fla) create folder name du34 and put du34.as into it.

ActionScript - Global Custom Events?

up until now, the way i've been needing to handle my own custom events is by adding an event listener to the object that was dispatching the custom event. while this method of event handling works just fine, i've come to the point where i would like my custom events to be globally accessible, where the listening object does not need to be the same object that is dispatching the event.
in this example, my main Controller class is instantiating and adding to the display list 2 sprite classes: Square and Triangle. the 4th and final class is a custom event called ColorChangeEvent.
i'm attempting to dispatch a new ColorChangeEvent from the Square class, which uses a timer to dispatch a new random color once every second, while Triangle will listen for the dispatched event and change its fill color to the color that was dispatched by Square.
Controller.as:
package
{
import flash.display.Sprite;
public class Controller extends Sprite
{
public function Controller()
{
var sq:Square = new Square();
sq.x = sq.y = 100;
var tr:Triangle = new Triangle();
tr.x = tr.y = 250;
addChild(sq);
addChild(tr);
}
}
}
Square.as:
package
{
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Square extends Sprite
{
public function Square()
{
graphics.beginFill(0x999999);
graphics.drawRect(0, 0, 100, 100);
graphics.endFill();
var myTimer:Timer = new Timer(1000);
myTimer.addEventListener(TimerEvent.TIMER, dispatchNewColor);
myTimer.start();
}
private function dispatchNewColor(evt:TimerEvent):void
{
var randomColor:Number = Math.random() * 0xFFFFFF;
trace("Square Class Dispatched: " + randomColor);
dispatchEvent(new ColorChangeEvent(ColorChangeEvent.CHANGE, randomColor));
}
}
}
Triangle.as:
package
{
import flash.display.Sprite;
import flash.geom.ColorTransform;
public class Triangle extends Sprite
{
public function Triangle()
{
graphics.beginFill(0x999999);
graphics.moveTo(0, 0);
graphics.lineTo(100, 50);
graphics.lineTo(-50, 150);
graphics.endFill();
addEventListener(ColorChangeEvent.CHANGE, changeColor);
}
private function changeColor(evt:ColorChangeEvent):void
{
var ct:ColorTransform = new ColorTransform;
ct.color = evt.color;
transform.colorTransform = ct;
trace("Triangle Class Received: " + evt.color);
}
}
}
ColorChangeEvent.as:
package
{
import flash.events.Event;
public class ColorChangeEvent extends Event
{
public static const CHANGE:String = "change";
public var color:Number;
public function ColorChangeEvent(type:String, color:Number)
{
super(type);
this.color = color;
}
override public function clone():Event
{
return new ColorChangeEvent(type, color);
}
}
}
needless to say, this isn't working.
of course, i could add the event listener to the Square instance in the Controller class, who's event handler could pass that value to Triangle via a public function to change the color, but this is exactly the kind of limitation i'm trying to avoid.
it's not always easy to access and pass a value to a class from where the custom event is dispatched, which is why i'm looking for an actual global solution to handling custom events.
I have been using this class for some time now. To use it you would do this in square:
data.EventManager.instance.publish("someName", randomColor);
and then in your Triangle:
data.EventManager.instance.subscribe("someName", handleColorChange);
private function handleColorChange(color:Number):void {
// implementation here
}
You can even pass the ColorChangeEvent instead of just the color.
data.EventManager.instance.publish(ColorChangeEvent.CHANGE, new ColorChangeEvent(ColorChangeEvent.CHANGE, randomColor);
And then
data.EventManager.instance.subscribe(ColorChangeEvent.CHANGE, handleColorChange);
private function handleColorChange(colorChangeEvent:ColorChangeEvent):void {
// implement here
}
I removed a lot of code that is specific to my projects, so I am not 100% it is usable exactly as-is. But, you should be able to modify it to get it working correctly. If not, let me know and I can try to work it out with you.
This class handles additional things that I will not go into, though you are free to explore. Be aware, however, that anything that subscribes for event notification has a strong reference by the EventManager. That means that if you want to destroy something for garbage collection, you need to call EventManager.instance.cancel(ColorChangeEvent.CHANGE, handleColorChange) before the Triangle instances can be collected.
package data {
import flash.utils.*;
public class EventManager extends Object {
private var _subscribers:Dictionary;
private var _calls:Dictionary;
private var _feeds:Dictionary;
private var _requests:Dictionary;
private var _notify:Dictionary;
private var _services:Dictionary;
private static var __instance:EventManager;
public function EventManager() {
if (__instance) {
trace("EventManager is a Singleton class which should only be accessed via getInstance()");
}
_feeds = new Dictionary(true);
_subscribers = new Dictionary(true);
_requests = new Dictionary(true);
_services = new Dictionary(true);
_notify = new Dictionary(true);
}
public function getFeedData($name:String) {
if (_feeds[$name]) {
return _feeds[$name];
}
return undefined;
}
public function unpublish($name:String) {
var _post:* = _feeds[$name];
delete _feeds[$name];
return _post;
}
public function cancel($name:String, $subscriberFunc:Function, ...args): void {
var _cnt:Number;
var _subscriberArray:Array;
if (_subscribers[$name]) {
for (_cnt = 0; _cnt < _subscribers[$name].length; _cnt++) {
if (_subscribers[$name][_cnt] == $subscriberFunc) {
_subscribers[$name].splice(_cnt, 1);
}
}
}
if (_requests[$name]) {
_subscriberArray = _requests[$name];
_cnt = _subscriberArray.length;
while (_cnt > 0) {
if (_subscriberArray[_cnt] == $subscriberFunc) {
_subscriberArray.splice(_cnt, 1);
}
_cnt--;
}
}
}
public function subscribe($name:String, $subscriber:Function, ...args): void {
var _funcArray:Array;
var _func:Function;
if (_feeds[$name]) {
$subscriber(_feeds[$name]);
}
if (! _subscribers[$name]) {
_subscribers[$name] = new Array();
}
_subscribers[$name].push($subscriber);
if (_notify[$name]) {
_funcArray = _notify[$name];
for each (_func in _funcArray) {
_func();
}
delete _notify[$name];
}
}
public function request($name:String, $feedFunction:Function): void {
var _requestArray:Array;
var _request:Function;
if (! _feeds[$name]) {
if (! _requests[$name]) {
_requests[$name] = new Array();
}
_requests[$name].push($feedFunction);
} else {
$feedFunction(_feeds[$name]);
}
if (_notify[$name]) {
_requestArray = _notify[$name];
for each (_request in _requestArray) {
_request();
}
delete _notify[$name];
}
}
public function publish($name:String, $data:*, $args:Object = null): void {
var _subscriberArray:Array;
var _func:Function;
var cnt:Number = 0;
_feeds[$name] = $data;
if (_subscribers[$name] != undefined) {
_subscriberArray = _subscribers[$name].slice();
_cnt = 0;
while (_cnt < _subscriberArray.length) {
_func = _subscriberArray[_cnt] as Function;
if ($args) {
_func($data, $args);
}else {
_func($data);
}
_cnt++;
}
}
if (_requests[$name]) {
_subscriberArray = _requests[$name].slice();
delete _requests[$name];
_cnt = 0;
while (_cnt < _subscriberArray.length) {
if (_subscriberArray[_cnt] != null) {
_subscriberArray[_cnt]($data);
}
_cnt++;
}
}
}
public function notify($name:String, $subscriber:Function): void {
if (_requests[$name] || _subscribers[$name]) {
$subscriber();
}else {
if (! _notify[$name]) {
_notify[$name] = new Array();
}
_notify[$name].push($subscriber);
}
}
public static function getInstance(): EventManager {
if (! __instance) {
__instance = new EventManager();
}
return __instance;
}
public static function get instance(): EventManager {
return getInstance();
}
}
}
I got this to work by creating a singleton: EventDispatchSingleton that extends EventDispatcher. It's basically an empty singleton that provides the dispatchEvent and add/removeEventListener methods (these are automatically provided by extending EventDispatcher).
Anywhere I want to dispatch an event I import EventDispatchSingleton and then call EventDispatchSingleton.instance.dispatchEvent(<someEvent>);.
Then, wherever I want to listen to that event, I just import EventDispatchSingleton and call EventDispatchSingleton.instance.addEventListener(eventName, callback);
You should look into event bubbling, specificly I think you will find the Capturing phase of the event propagation useful. Take a read of Event propagation from Adobe LiveDocs. It's in the Flex docs, but it is about AS3 Events.
Also Senocular has a good post on Flash Event Bubbling.