AS3: if-function doesn't listen to a boolean in another class - actionscript-3

So... I'm working on a chess-game, and trying to make it so that a "public static boolean" (turn) dictates which player can make a move. This boolean is in a class (Board.as) which imports all the classes for all the chess-pieces (e.g. QueenW.as (for the White Queen)).
I've tried multiple ways: Trying to make functions not run anymore, and replacing the pieces (which are buttons) to other objects (non-clickable movieclips). Decided to go with the latter. I've traced the boolean in a chess-piece class, as well as the Board-class, in an ENTER_FRAME function. Both seem to trace it correctly when the value changes.
Problem is: Flash doesn't remove the chess-pieces and replaces them with a non-clickable object, even though the class in which it should happen (Board.as) does listen to the boolean when tracing. Anybody knows a solution?
A little piece of my code, which is relative to the problem:
Board class (which is the Documentclass for my .fla file)
package
{
import QueenWclass; //imports the class used for example.
public class Board extends MovieClip
{
public static var turn:Boolean = new Boolean; //creates public static bool.
var queenW:QueenWclass = new QueenWclass(); //creates aforementioned chess-piece.
var queenWnoturn:QueenWnoturn = new QueenWnoturn; //creates a non-clickable object.
}
public function Board()
{
turn = true;
this.addEventListener(Event.ENTER_FRAME, frameEnter);
addChild(queenW); //adds pieces to the screen.
}
if (turn == true)
{
}
if (turn == false)
{
removeChild(queenW); //Removes chess-piece.
addChild(queenWnoturn); //Adds a non-clickable object.
}
}
And my QueenWclass.as class:
package
{
public class QueenWclass extends MovieClip
{
var queenW:QueenW = new QueenW();
}
public function QueenWclass()
{
addChild(queenW);
this.addEventListener(MouseEvent.CLICK, CLICKqueenW);
}
function CLICKqueenW(event.MouseEvent):void
{
Board.turn = false;
}
}
I hope I wrote this example correctly and understandably. There's no real timelimit to my project as I already had to turn it in an hour ago (but still got a 6/10 because of effort and how far I've come with this rather complex game). I just want to finish it for myself... Thanks in advance!

Maybe the code has not been copied correctly or there is a small problem.
This code:
if (turn == true)
{
}
if (turn == false)
{
removeChild(queenW); //Removes chess-piece.
addChild(queenWnoturn); //Adds a non-clickable object.
}
Will only run once, when "Board" is created, it will not run when the state of "turn" changes.

Well, you have nothing that's listening for the boolean's change. The code that's checking the boolean is located in constructor, while the actual change is done in a MouseEvent.CLICK event listener. You have to either implement a function that's called repeatedly via Event.ENTER_FRAME listening, SetInterval(), or TimerEvent.TIMER (with a timer), or implement a publicly available property as a function, that would check which turn is it and do corresponding actions. The latter is a little better, as it works only when something is changed.
private static var _turn:Boolean=false;
public static function get turn():Boolean { return _turn; } // getter part
public static function set turn(value:Boolean):void // setter part
{
if (_turn==value) return; // no need to change turn
_turn=value;
if (_turn) YouGetATurn(); else EnemyGetsATurn();
// this part is what will get called when you change Board.turn
}

Related

How to make a class file apply an eventhandler to instance or object on main stage asides from itself?

I'm pretty new with ActionScript 3 and I'm stuck with trying to perform the following above in a class file. I tried to look for a solution online, but I can't find a suitable answers, perhaps because I'm not looking for the right search terms, etc.
Anyway, I'm trying to make a basic animation in Adobe Animate CC in an FLA file, "Campfire.FLA", where pressing the mouse down on a Campfire causes a piece of Coal attaching to a levitating stick to glow, and cooldown upon letting go of the mouse button. On the main timeline, I can execute it fine, but I want to transfer the information to a class file/ document file, but to no avail.
The code is what I used on the FLA's main timeline, Frame 1, and it works below works perfectly fine:
stop();
/* Instance names:
Fire = Instance of "FireButton"; simplebutton.
STween = Instance of "Stick Tween"; MovieClip, simple tween animation the object, "MarshmallowStick" moving.
Stick = Instance of "Marshmallow Stick"; MovieClip.
CoalRock = Instance of "Coal"; MovieClip.
*/
Fire.addEventListener(MouseEvent.MOUSE_DOWN, RockHot)
function RockHot(e: MouseEvent): void {
stopPlayReverse();
// Causes Coal and Stick to play their animation upon clicking Fire.
STween.Stick.play();
STween.Stick.CoalRock.play();
}
Fire.addEventListener(MouseEvent.MOUSE_UP, RockCold)
function RockCold(e: MouseEvent): void {
STween.Stick.CoalRock.addEventListener(Event.ENTER_FRAME, playReverse, false, 0, true);
STween.Stick.gotoAndPlay(1);
// Upon letting go of mouse button, it causes the coal to cool down/ play reverse. Stick resets to Frame 1.
}
function playReverse(e: Event): void {
if (STween.Stick.CoalRock.currentFrame == 1) {
stopPlayReverse();
// If Coal is back on Frame 1, it stops.
} else {
STween.Stick.CoalRock.prevFrame();
// If Coal is not on Frame 1 it continues going reverse where it left off.
}
}
function stopPlayReverse(): void {
if (STween.Stick.CoalRock.hasEventListener(Event.ENTER_FRAME)) {
STween.Stick.CoalRock.removeEventListener(Event.ENTER_FRAME, playReverse);
// Stops the function playreverse()
}
}
However, when trying to migrate the information into an ActionScript File I ran into a couple of problems. First I tried making an ActionScript 3 class file for each of the objects above much of the information is blank because I had no idea how to communicate eventhandlers between them. Much of the information for the MovieClips have no information, "MarshmallowStick" is below:
package {
import flash.display.MovieClip;
public class MarshmallowStick extends MovieClip {
public function MarshmallowStick() {
// Empty, no constructor code.
}
}
}
For the "Fire" Class file I tried something like:
package {
import flash.display.*;
import flash.events.*;
import Coal;
public class FireButton extends SimpleButton {
public var CoalRock = Coal;
public function FireButton() {
Coalrock = new Coal ();
this.addEventListener(MouseEvent.CLICK, RockHot)
function RockHot(e: MouseEvent): void {
CoalRock.play();
trace("OK");
trace(CoalRock);
}
}
}
}
However, it turned out that upon testing, The file only appeared to create a new object named CoalRock, and is not related to the one on the mainstage. So clicking the FireButton causes only the new object to play.
I tried making a document class as seen below in a file named "Main.as":
package {
import flash.display.*;
import flash.events.*;
public class Main extends MovieClip {
public var Fire: FireButton;
public var CoalRock: Coal;
public var Stick: MarshmallowStick;
public var STween: StickTween;
public function Main() {
CoalRock = new Coal();
Fire = new FireButton();
Stick = new MarshmallowStick();
/*
addChild(Fire);
addChild(CoalRock);
addChild(Stick);
addChild(STween);
*/
// RIP, well it's pretty much the same code as above. Just without the nested symbols/ objects.
Fire.addEventListener(MouseEvent.MOUSE_DOWN, RockHot)
function RockHot(e: MouseEvent): void {
stopPlayReverse();
//Eye + Emblem glow
Stick.play();
CoalRock.play();
trace("OK");
}
Fire.addEventListener(MouseEvent.MOUSE_UP, RockCold)
function RockCold(e: MouseEvent): void {
CoalRock.addEventListener(Event.ENTER_FRAME, playReverse, false, 0, true);
Stick.gotoAndPlay(1);
}
function playReverse(e: Event): void {
if (CoalRock.currentFrame == 1) {
stopPlayReverse();
} else {
CoalRock.prevFrame();
}
}
function stopPlayReverse(): void {
if (CoalRock.hasEventListener(Event.ENTER_FRAME)) {
CoalRock.removeEventListener(Event.ENTER_FRAME, playReverse);
}
}
}
}
}
But it only turned out that it only affects objects added via the addChild() well as far as I have tested. But the main point of this is for the script to affect objects that already exist on the main stage/ scene.
If you want to see how it plays/ suppose to play out, you can take the main timeline code and paste it into an FLA file with instances of the ones provided.
I don't know how Stack will format it. / / is suppose to be multi-line comments.
That's one elaborate question.
The thing you (probably) need the most is some feudal hierarchy so that objects tend to their own and their direct children, but not deeper and totally not upwards:
Container → (interface method) → Child → (tends to own children)
Container ← (status event) ← Child
Normally, a child must not know of its parent and should communicate with status events. This way you can put such a child into any container with no risk of that child possibly reaching upwards expecting some parent structure that is not there.
So, your problems.
First. Accessing the objects that already exist on the main timeline. Well, the only trick is not to create new ones but to get references to the existing ones.
package
{
// Imports.
public class Main extends MovieClip
{
// If you have an instance of MarshmallowStick with the
// instance name "Stick" on the main timeline,
// you don't need to do anything else.
//
// Default publish settings are to auto-declare
// the main timeline instance into the
// appropriately named variable.
public var Stick:MarshmallowStick;
P.S. Figure the Stick out of Tween by yourself.
Second. To access Coal inside Stick you need to declare an appropriate variable inside the correspondent class. Also, it makes a lot of sense to put the things needed to play things forward and backward as close to the objects they operate as it is possible.
package
{
import flash.events.Event;
import flash.display.MovieClip;
public class MarshmallowStick extends MovieClip
{
// You don't seem to need a separate class for Coal.
// Having it as a regular MovieClip will suffice.
public var Coal:MovieClip;
// Call this to play animation forward.
public function playNormal():void
{
removeEventListener(Event.ENTER_FRAME, onReverse);
gotoAndPlay(1);
Coal.play();
}
// Call this to play animation backward.
public function playReverse():void
{
Coal.stop();
gotoAndPlay(1);
addEventListener(Event.ENTER_FRAME, onReverse);
}
// This method does not need to be seen from the outside
// so declare it as private rather than public.
private function onReverse(e:Event):void
{
if (Coal.currentFrame > 1)
{
Coal.prevFrame();
}
else
{
playNormal();
}
}
// Call this to stop playing into any direction.
public function stopPlaying():void
{
stop();
Coal.stop();
removeEventListener(Event.ENTER_FRAME, onReverse);
}
}
}
Third. Avoid declaring functions inside functions. You can read up what closures are and how to handle them in AS3, but for the time being (and probably for the foreseeable future) you won't need them.
package
{
// Imports.
public class Main extends MovieClip
{
public var Fire:SimpleButton;
public var Stick:MarshmallowStick;
public function Main()
{
Fire.addEventListener(MouseEvent.MOUSE_DOWN, makeHot);
// The rest of the code.
}
function makeHot(e:MouseEvent):void
{
Stick.playNormal();
trace("OK");
}
Fourth. Do not subclass buttons. It is pretty enough to create a simple class-free button and subscribe to its MouseEvent.CLICK or MouseEvent.MOUSE_DOWN events to process all the necessary actions in some place that knows what this buttons is for. I said that above already. Feudal hierarchy. Button should fire an event, then its holder should capture that event and react. The button itself should not know where it is or what its purpose is, even less to try doing things.

Scenes in Actionscript 3

Is there a way to set up scenes in AS3, without using the Flash tool? Basically when someone clicks a button I want to present a completely different screen. Right now if I try to draw a bitmap the bitmap starts at the upper left corner of the button rather than at the upper left corner of the program display.
This is easy using Flash, you just use gotoAndPlay(1, scenename). However, I want this program to be entirely in AS3 without using Flash.
Suggestions?
You'll have to create your own collection of classes that represent scenes. This also involves some type of foundation to run your scenes ontop of, managing loading and unloading those scenes and their content.
In a simple scenario, this would begin as something along the lines of:
class SceneManager extends Sprite
{
private var _currentScene:Scene;
public function loadScene(scene:Scene):void
{
unloadCurrentScene();
_currentScene = scene;
_currentScene.load(this);
addChild(_currentScene.view);
}
public function unloadCurrentScene():void
{
if(hasScene)
{
_currentScene.unload(this);
_currentScene.view.parent === this && removeChild(_currentScene.view);
}
_currentScene = null;
}
public function get currentScene():Scene{ return _currentScene; }
public function get hasScene():Boolean{ return _currentScene !== null; }
}
With the Scene class:
class Scene
{
private var _view:Sprite;
public function Scene()
{
_view = new Sprite();
}
public function load(sceneManager:SceneManager):void
{
// Abstract.
// Load children, initialize components, etc.
}
public function unload(sceneManager:SceneManager):void
{
// Abstract.
// Remove children, event listeners, references, etc.
}
public function get view():Sprite{ return _view; }
}
Used like (assuming you have a class MainMenuScene extending Scene):
var sceneManager:SceneManager = new SceneManager();
addChild(sceneManager);
sceneManager.loadScene( new MainMenuScene() );

Controlling objects of another class that are already on the stage

I'm quite ashemed to ask this question here because I'm sure that I'm missing something very basic. I'm not even sure what should be the correct title for this question.
Let's say that I've a button object (instance of Flip) and a coin object (instance of Coin) on the stage. The coin object has two frames: one showing Heads and one for Tails.
MyCoin class is as following:
package
{
import flash.display.MovieClip;
public class Coin extends MovieClip
{
protected var _coinFace:uint;
public function Coin()
{
stop();
}
public function get coinFace():uint {
return _coinFace;
}
public function set coinFace(value:uint):void {
_coinFace = value;
}
public function show():void {
gotoAndStop(_coinFace);
}
}
}
Objective: When user clicks the button, the coin should flip and show a random coinFace. I've added an eventListener to the Flip class as follows:
public function Flip()
{
this.addEventListener(MouseEvent.CLICK, onMouseClick);
}
Problem: How do I reach the coin object on the screen via onMouseClick function? Let's say that the object on the stage has instance name of myCoin. I suppose that had I not done this with an external class and simply used actions from the frame I could just use the instance name as a variable. I couldn't figure to do the same it in an external class. Do I first create the object which is already on the stage?
Where you create the instance of each, the flip object needs to be passed an instance of the coin object.
var myCoin:Coin = new Coin();
var myFlip:Flip = new Flip(myCoin);
Then inside the Flip class:
private var _coin:Coin;
public function Flip(coin:Coin) {
_coin = coin;
this.addEventListener(MouseEvent.CLICK, onMouseClick);
}
private function onMouseClick(e:MouseEvent):void {
_coin.gotoAndStop(2); // Or what ever needs to be done to the coin on click
}
Alternatively, depending on the complexity of the overall structure, you can a build a control class that acts as a link between the two.

AS3 driving me nuts

Ok here is what I am currently trying to do. I have a class called vdata.as which takes 2 paramaters both are strings sent from the main stage. Parameter one is the location for an XML file that I need to open and read. The second parameter is the name of the video I am currently looking for.
Now I can get the data from the XML file and display it with out any issue if its called from my class but when I try to access any of it from the stage I get undefined.
import flash.net.*;
import flash.display.*;
import flash.events.*;
public class videoData
{
private var mName:String;
private var mLink:String;
private var mCategory:String;
public static var elementArray:Array;
// Constructor
public function videoData(xmlPath:String,xmlVidSrc:String,pMC:MovieClip)
{
pXmlPath = xmlPath;
pXmlVidSrc = xmlVidSrc;
xmlloader = new URLLoader();
elementArray = new Array();
}
public function getXML()
{
XMLData();
}
private function XMLData()
{
xmlloader.load(new URLRequest(pXmlPath));
xmlloader.addEventListener(Event.COMPLETE,parseXMLData);
}
private function parseXMLData():void
{
var x:XML = new XML(xmlloader.data);
Init(x);
}
private function Init(m:XML):*
{
var i:Number;
for(i=0; i<m.videos.videoname.length(); i++)
{
if(m.videos.videoname[i].#name == pXmlVidSrc)
{
videoData.elementArray.push(m.videos.videoname[i].#name);
videoData.elementArray.push(m.videos.videoname[i].#category);
videoData.elementArray.push(m.videos.videoname[i].link.#url);
}
}
}
}
When I call it from the main stage the code is as follows.
var xData:videoData = new videoData(xmlPath,vidSrc,this);
xData.getXML();
then when I try to access any elements of videoData.elementArray they come up undefined...
Im just smacking my head on my desk trying to figure this out any help would be great.
Why is elementArray a static var, you only need to make it public to use it outside the function.
I'm quite confusing but you may want to try a debugging tool like "De MonsterDebugger", I would start by tracing xmlloader.data in the parseXMLData function.
"addEventListener" doesn't "fire"...the event does. You'll need to add a boolean to state for the stage that elementArray has been populated and set that after the init function.
Is elementArray something that needs to be true across all instances of videoData? If not, it shouldn't be static. You can use MovieClip(this.root).xData to access that instance of the video class from one of your other classes.
If the event has completed and the array is still empty - then it wasn't populated by your parser. You can also do checks to see if the elementArray.length > 0.
EDIT in response to comment:
as a public member or preferably a read-only property make a boolean variable:
var parseComplete:Boolean;
Set it to false in your constructor.
Then, after your call to "Init" in your Event.COMPLETE callback set:
parseComplete=true;
Then make sure parseComplete == true before you ever access elementArray. If you're waiting for the parser to complete you might want to set a timeout or some sort of try/catch mechanism just in case there are any unforeseen errors that would cause some sort of:
while( !xData.parseComplete ) { }
To loop indefinitely. It all depends on the usage. Personally I'd probably add a callback from the event listener to the stage to trigger whatever is supposed to happen next.

Creating a custom trace() class in AS3

I got this idea of expanding my trace() messages.
Why
trace() is all over my code, I want to turn them on/off by a simple command and maybe add some sort of priority functionality to the trace(), i.e.
myTrace.TraceMsg("loosehere",debugme, 0);
myTrace.TraceMsg("winhere",debugme, 1);
And when I run, only the one with the higher priority, "1" in this case, shows.
There is a lot more functionality I would like to add as well, like logging messages to file and so on.
Problem
How do trace() work? -Is it possible to overload trace() somehow? -How would I implement the custom TraceMsg(what code here?) method?
Having some serious problems finding info on this subject on our favourite search engine, so any help would be appreciated.
I have come up with a rather efficient, yet tedious way of using my own trace() function in Flash only projects, but calling it simply with
trace("this", "that", "and that too");
I basically implement one trace() method in every class of my project, that calls a public function (so that i can call the real trace() function from there.
here is what I do : in every class I call this
include "trace_implementation.as";
in the .as file comes a simple method implementation (it could be a static method too).
public function trace(... arguments){
for(var i in arguments){
myTrace(arguments[i]);
}
}
and the myTrace function is defined in its own myTrace.as file
package pt.utils{
import flash.external.ExternalInterface
public function myTrace(_s:String):void{
trace(_s);// this will call the original flash trace() function
ExternalInterface.call("console.log", _s);// to get traces outside of flash IDE
/*implement what you want here*/
}
}
so now when I compile with "omit trace actions", my whole debugging is ignored as if I used trace() simply.
the really good part here is that you could implement custom actions depending on instructions you give in the trace, so :
trace(Debug.DEBUG_MESSAGE, "message to output in debug");
trace(Profile.START_PROFILING, this, 'name');
/*do heavy code*/
trace(Profile.STOP_PROFILING, this);
then dispatch it from myTrace, or a Tracer class or anything :)
Hope this helps future tracers.
trace() itself is a top-level function, not a class, so unfortunately we cannot extend it. That being said, we can utilize it in a simple class to do just what it does normally, only in this case the trace is based on conditions (i.e. Boolean - true|false, etc). First we create the Trace class, which we wouldn't instantiate ourselves because we are utilizing a Factory design pattern through the class below, Tracer. Tracer is built around the singleton design pattern, yet utilizes the Factory pattern to instantiate instances of Trace, when the trace method of Tracer is called.
//This class is handled by Tracer, which is right below it.
//You WILL NOT instantiate these, nor hold references.
package
{
public class Trace
{
private function _value:*;
private function _trace:Boolean;
public function Trace(pValue:*, pTrace:Boolean):void
{
_value = pValue;
_trace = pTrace;
}
public function get value():*
{
return _value;
}
public function get trace():Boolean
{
return _trace;
}
}
}
//This is the important class and the only one you will work with.
package
{
/**
*Utilizes Singleton and Factory design patterns.
*/
public class Tracer
{
private var _traceArray:Array;
private static var _instance:Tracer;
public function Tracer(pvt:PrivateClass = null):void
{
if(pvt == null)
{
throw(new Error("You cannot instantiate this class directly, please use the static getInstance method."));
}
_init();
}
public static function getInstance():Tracer
{
if(Tracer._instance == null)
{
Tracer._instance = new Tracer(new PrivateClass());
}
return Tracer._instance;
}
public function trace(pValue:*, pTrace:Boolean):void
{
var trace:Trace = new Trace(pValue, pTrace);
if(trace.pTrace)
{
trace(pValue);
}
}
//Since we have the option for individual traces to be disabled
//I provide this to get access to any and all later.
public function traceAll():void
{
traceStr:String = _traceArray.toString();
}
public function get traceables():Array
{
return _traceArray;
}
//Here we provide a method to trace all, even if set to false in their constructor.
private function _init():void
{
_traceArray = new Array();
}
}
}
//Here we create a class that is OUTSIDE of the package.
//It can only be accessed from within this class file. We use this
//to make sure this class isn't instantiated directly.
class PrivateClass
{
function PrivateClass():void
{
trace('can only be accessed from within this class file');
}
}
//Now for use in doc class
package
{
import flash.display.Sprite;
import flash.events.Event;
//No need to import Tracer and Trace, they are also in the
//unnamed package.
public class DocumentClass extends Sprite
{
private var _tracer:Tracer;
public function DocumentClass():void
{
if(stage) _init();
else addEventListener(Event.ADDED_TO_STAGE, _init);
}
private function _init(e:Event = null):void
{
_tracer = Tracer.getInstance();
_tracer.trace(10*20, false);
_tracer.trace(10*20, 0); //SAME AS ABOVE
_tracer.trace("I love AS3", true); //traces
_tracer.traceAll(); //Would trace: 200, 200, I love AS3
}
}
}
Keep in mind this is off the hip and very well could have a bug or two, but the idea is there; That is to say that this is not tested, it is merely to give you an idea of how you might implement this.
I hope this helps.
Look at the Flex logging API, particularly the section: Implementing a custom logger with the logging API.
Look up the TraceTarget class as well.
You can't override trace itself, but for ease of typing I like to create a global function called 'tr'. It's a little known fact that you can create global functions in AS3, but it's easy.
Create a file called tr.as inside you main source directory (not in a subdirectory or package), with the contents:
package {
public function tr(msg:String, ...):void {
// add custom trace logic here
trace("tr message: "+msg);
}
}
If you need to have a lot of logic or static storage variables etc, it might be better to make a separate static class, and have the global tr function call out to that, such as:
package {
import org.code.MyTracer;
public function tr(msg:String, ...):void {
MyTracer.tr(msg); // all the tracing logic is inside the MyTracer class
}
}
Here is a super simple custom trace function I use. debugFlag can be set to true/false
elsewhere in the package.
public static function myTrace(... vars) :void {
if (debugFlag) {
var output:Array = new Array;
for each (var arg in vars) {
output.push(arg);
}
trace(output);
}
}
In AS2, it was possible to override the global trace function by doing something like this (taken from memory, might be a bit wrong but the gist of it is there):
public static var realTrace:Function = _global["trace"];
// This is put in some init code somewhere
_global["trace"] = myTrace;
public static function myTrace(... args):void
{
// Do whatever you want with args here, build a nice formatted string or whatever
// before passing to realTrace. Using with MTASC one could add line numbers, class
// names and all sorts of nice meta data. Or just return should you want to turn
// tracing off.
realTrace.apply(args);
}
Unfortunately I haven't found a way to do the same in AS3. Yet.
Trace is a top-level function, so you can't override it, and as far as I know, it does not fire any events. Since it's a top-level function (not contained in any named package), you can use it without import statements.
Here is an example of a top-level "Tracer" class that you can use in place of trace without import statements.
Just call "Tracer.write" or "Tracer.writeError" for tracing Error objects.
"Tracer.write" accepts a variable number of arguments, just like the built-in trace function. "Tracer.writeError" is a helper method that allows you to easily trace Error objects.
Features:
Calls built-in trace.
Keeps a log of all your calls to Tracer.write as an array of strings.
The call log is accessible as a string through getText, which joins all elements in the array with a newline character and will optionally tack on line numbers!
Fires events when new lines are added to the log, so if you have some kind of display window for the log, the display window can listen for Tracer events to update the log display in real-time as the events occur. This is great for displaying trace events when running inside a web browser or stand-alone player.
-Tracer class definition
package
{
import flash.events.EventDispatcher;
public class Tracer extends EventDispatcher
{
private static var traced_text:Array = new Array( "--Start of Trace Log--" );
public static var enabled:Boolean = true;
private static var suspended:Boolean = false;
public static var instance:Tracer = new Tracer();
public static const newline:String = "\n"; //workaround for TextField.appendText bug.. use "\n" instead of "\r". See note and link to bug post in getText method
public function Tracer()
{
}
static public function write( ...args ):void
{
if (enabled && !suspended)
{
trace.apply( null, args );
var text:String = args.join( newline );
var next_index:int = traced_text.length;
traced_text.push( text );
suspended = true; //prevent recursive calls from TracerEvent handler
instance.dispatchEvent( new TracerEvent( text, next_index ) );
suspended = false;
}
}
static public function writeError( e:Error ):void
{
write( "errorID: " + e.errorID, "errorName: " + e.name, "errorMessage: " + e.message, "stackTrace: " + e.getStackTrace() );
}
static public function getText( include_line_numbers:Boolean ):String
{
var line_count:int = traced_text.length;
var lines:Array = traced_text; //store pointer to traced_text; pointer may be changed to reference an altered array that includes line numbers
if (include_line_numbers) //create temporary trace log copy with altered lines; allows quick call to join at end
{
var new_lines:Array = new Array();
for (var i:int = 0; i < line_count; i++)
new_lines.push( i.toString() + ": " + lines[i] );
lines = new_lines;
}
return lines.join( newline ); //do not include last newline character (workaround for bug in appendText method (https://bugs.adobe.com/jira/browse/FP-1982); I have to call appendText with newline character first, otherwise it has issues like not acknoledging the newline thats already there at the end).
}
static public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
{
instance.addEventListener(type, listener, useCapture, priority, useWeakReference);
}
static public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
{
instance.removeEventListener(type, listener, useCapture);
}
static public function willTrigger(type:String):Boolean
{
return instance.willTrigger(type);
}
static public function hasEventListener(type:String):Boolean
{
return instance.hasEventListener(type);
}
}
}
-TracerEvent class definition
package
{
import flash.events.Event;
public class TracerEvent extends Event
{
public static const WRITE:String = "te_write";
public var text:String;
public var index:int; //index of newly traced text in the traced_text array (trace log)
public function TracerEvent( text:String, index:int )
{
super( WRITE, false, false );
this.text = text;
this.index = index;
}
override public function clone():Event
{
return new TracerEvent( text, index );
}
}
}
As mentioned below, there is no way to override trace (at least not if you want your traces to reach the output stream), but it's actually very easy to create your own universally accessable logging function. Plus, you can even define a universally accessable boolean to turn logging on or off:
log.as (note that the filename must reflect the name of the function)
package {
function log(... arguments):void {
trace("Custom logging FTW!");
if (logEnabled)
trace(arguments);
}
}
logEnabled.as (note that the filename must reflect the name of the variable)
package {
var logEnabled:Boolean = true;
}
Main.as
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public function Main() {
log("Testing");
logEnabled = false;
log("Testing2");
}
}
}
Response
Custom logging FTW!
Testing
Custom logging FTW!
you dont need to override it , just create a function in your project and call it trace then any trace call will point to this.trace ;)
function trace(... arguments){
yourfunction(arguments);
}