whether I put start() method or not my particle emitter runs the same way, So what is the use of start() method.
If you look at the source code of ParticleEffect class and then look at the start method, you will see this -
public void start () {
for (int i = 0, n = emitters.size; i < n; i++)
emitters.get(i).start();
}
Basically, this means it is going through all the emitters and calling ParticleEmitter#start method.
Now let's look into the start method of ParticleEmitter.
public void start () {
firstUpdate = true;
allowCompletion = false;
restart();
}
Basically from the method, you can see that its setting the firstUpdate boolean to true which means "this is the first update" i.e. we will be doing something for the first time (look into the source code to see where the boolean is used)
The next line, it is setting allowCompletion to false which means, if the emitter was already in progress, don't let it complete (Check source code to see where the boolean is used)
The final call is to restart() which is self-explanatory (restarting this emitter if it was already running.)
I hope that helped.
Related
I have a numeric stepper and I want to add an event listener to its text box:
use namespace mx_internal;
durationStepper.inputField.addEventListener(Event.CHANGE,durationStepperTextInputChanged);
private function durationStepperTextInputChanged(event:Event):void
{
use namespace mx_internal;
trace(durationStepper.inputField.text);
}
However, the event function does not execute! I put a break point there and it does not reach it! What am I missing here? Thanks.
The problem is that the developer has stopped Change event from bubbling up. You can find it if you go to the source file of the NumericStepper. Here are two functions, which prevent you from getting the event.
override protected function createChildren():void
{
super.createChildren();
if (!inputField)
{
inputField = new TextInput();
//some code
//some code
inputField.addEventListener(Event.CHANGE, inputField_changeHandler);
addChild(inputField);
}
}
private function inputField_changeHandler(event:Event):void
{
// Stop the event from bubbling up.
event.stopImmediatePropagation();
var inputValue:Number = Number(inputField.text);
if ((inputValue != value &&
(Math.abs(inputValue - value) >= 0.000001 || isNaN(inputValue))) ||
inputField.text == "")
{
_value = checkValidValue(inputValue);
}
}
As you can see the second function has
event.stopImmediatePropagation();
In this case you have two options: either you should find another way of implementing your logic, or you can copy the source code of the component and eliminate this code line.
It would be fine to override the function, but it is private.
You can read about this common problem here
I have tried to choose the second way. It works perfectly! It is not only the *.as file, but some others, which are used in it.
You can download the component here.
So, I have successfully grabbed a value out of an XML document and set it into a separate class called "AddCommas." The trace functions have shown me that it sets properly.
For more details, my objective is to take the language indicator ("fr" for french or "en" for english), set it inside the appropriate class and into a variable I will use. Now, I am using this variable to be used in an if statement; which will help me format a number properly (commas, decimals, spaces) per the clients request.
However, my problem is when I try to get the value to use it. It always comes back as Null. I have placed traces all over my program trying to pinpoint when this happens, but I cannot find it. Here's the code...
The pull from the XML file and into the set (this works fine, but I am adding it for your benefit in case I missed something)
public var commaHold = new AddCommas();
localLanguage = xmlObj.localLanguage;
trace("localLanguage + " + localLanguage);
commaHold.setLanguage(localLanguage); // Set Language
//More code follows...
This is the set function istelf...
public function setLanguage(localLanguage:String){
langHold = localLanguage;
trace("Set Language = " + langHold); //This always shows a successful set
}
Now am I wrong in thinking that in AS3, once langHold in my AddCommas class has been set I should be able to use it without calling a get within the function I am using the If Statement in, right? Such as this?
var language = langHold;
if (language == "en"){
trace("Language is = " + language); // More code follows afterwards and as of now, this shows NULL
Now, I have attempted plenty of Get functions to add the language variable in the call itself to this function and it's always the same. Am I missing some fundamentals here?
Thank you very much for your time.
If you expect a string comparison you need to use quotes, unless en is a String variable since langHold is a String, like:
if (language == "en"){
Consider modifying the set function to use the as3 keyword like:
private var _language:String;
public function set language(value:String):void {
_language = value;
//do other stuff here if necessary, put a breakpoint on the line above
}
public function get language():String{
return _language;
//put a breakpoint on the line above
}
You should be able to see when any instance of your class has the property changed. The only other issue I can think of is it is not the same instance of the class and therefore doesn't share the property value you set earlier. In the debugger you can check the "hashCode" or "address" it shows for this to see if it changes when it hits the breakpoints.
Here's a sample Singleton structure in AS3 (this all goes in one file):
package com.shaunhusain.singletonExample
{
public class SingletonExample
{
private static var instance:SingletonExample;
public static function getIntance():SingletonExample
{
if( instance == null ) instance = new SingletonExample( new SingletonEnforcer() );
return instance;
}
/**
*
* #param se Blocks creation of new managers instead use static method getInstance
*/
public function SingletonExample(se:SingletonEnforcer)
{
}
}
}
internal class SingletonEnforcer {public function SingletonEnforcer(){}}
using this single shared instance from any other class would look something like this:
private var singletonInstance:SingletonExample = SingletonExample.getInstance();
ShaunHusain's theory of using a Singleton was the perfect solution I needed. However, his code gave me a bizarre 1061 error and my format and code appeared to be error free. Regardless, I looked up another way to use a Singleton as follows that worked perfectly for me. Honestly, Shaun's code should work for anyone and I have no idea why it wasn't. I am perfectly willing to admit that it was probably a typo on my end that I just did not see.
I ended up embedding the Set and Get within the Singletons class and used it as an intermediary to hold the information I needed. It worked perfectly.
package chart {
import chart.*;
//
public class StaticInstance {
private static var instance:StaticInstance;
private static var allowInstantiation:Boolean;
private var language:String;
public static function getInstance():StaticInstance {
if (instance == null) {
allowInstantiation = true;
instance = new StaticInstance();
allowInstantiation = false;
}
return instance;
}
public function StaticInstance():void {
if (!allowInstantiation) {
throw new Error("Error: Instantiation failed: Use StaticInsance.getInstance() instead of new.");
}
}
public function setLanguage(_language:String):void{
language = _language;
trace("language set = " + language);
}
public function getLanguage():String{
return language;
}
}
}
This code allowed me to hold the data and call upon it again from two different classes. It's a very hack job instead of just being able to pass on the variable from function to function, but in my case we didn't create this file, we are modifying it and attempting to do things beyond the original scope of the project.
Thanks again for your help Shaun! I hope this helps other people!
This is my code in Flash/AS3, in main class.
addEventListener(Event.ENTER_FRAME,function(e:Event){
if(findObject == true){
// I want to remove this ENTER FRAME
}
});
try this:
e.currentTarget.removeEventListener(e.type, arguments.callee)
You shouldn't be doing what you do in the code above.
The mgraph's code has a tiny chance of failing to work as advertised if the currentTarget of the event doesn't have a removeEventListener() method (possible, but very unlikely). From the compiler standpoint though you will be trying to dynamically resolve the method on a generic object which is error prone and should be handled with care. This is hazardous because it shows that the programmer "did not know" what kind of object was she expecting to handle and worked by assumption. Assumptions are great for finding a solution but are equally bad for implementing one.
If you thought of optimizing something in the way you did it, then, just FYI this actually creates a unique (redundant) name in the symbol table (in the compiled SWF file) which causes worse compression of the SWF.
If you are doing this as a matter of experiment, this is fine, but you should avoid such code in real life projects.
One more thing to be aware of: comparison to true constant is 100% useless. If such comparison makes any sense at all (i.e. findObject may evaluate to false any time), then if (findObject) { ... } is equivalent but shorter version of your code.
Last thing, hopefully, the anonymous function is missing return type declaration. It won't really change much in your example, except that you will get compiler warning. Omitting type declaration is, in general, a bad style.
EDIT
public function addEventListener(type:String, listener:Function ...):void
{
this._listeners[type].push(listener);
}
public function dispatchEvent(event:Event):void
{
for each (var listener:Function in this._listeners[event.type])
listener(event);
}
public function removeEventListener(type:String, listener:Function, ...):void
{
delete this._listeners[type][listener];
}
Suppose you actually want to implement IEventDispatcher (instead of using another EventDispatcher - you may have your reasons to do so, one such reason is that native EventDispatcher generates insane amounts of short-lived objects - events, and you may want to reduce that.) But there is no way you can replicate event.target or event.currentTurget in your code because you can't access the object owning the method, so, you would leave that out.
Another example:
public class SomeEvent extends Event
{
private var _target:NotEventDispatcher;
public function SomeEvent(type:String, someTarget:NotEventDispatcher)
{
super(type);
this._target = someTarget;
}
public override function get target():Object
{
return this._target;
}
}
This is something that I actually saw in real world, this was used in either Mate or similar framework to sort of "anonymously" connect all event dispatchers to a single static instance of some "mothership event dispatcher".
I don't necessarily justify this approach, but, technically, nothing stops you from doing either one of these. What I was saying in my post above is that in certain situations the language promises you things, like, if you did:
var dispatcher:IEventDispatcher;
try
{
dispatcher = IEventDispatcher(event.currentTarget);
// now you can be sure this object has removeEventListener
dispatcher.removeEventListener(event.type, arguments.callee);
}
catch (error:Error)
{
// but what are you going to do here?
}
But the most common case would be you subscribing to a bubbling event, in which case, you don't know whether you want to unsubscribe from event.target or event.currentTtarget - because you don't know which one is that you are listening to.
I agree with wvxvw.
Another way to approach your problem is to have a variable to control the "state" of your ENTER_FRAME event:
private var _state:String;
private function init(e:Event):void {
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
private function loop(e:Event):void {
switch(_state) {
case "play":
// do play stuff
// when you want to pause
// goToPause();
break;
}
}
// you can call the method below from a button or whatever you want
private function goToPause():void {
_state = "pause";
// do some stuff here
// when you are done, switch "_state" back to "play"
}
In this example, you keep listening for ENTER_FRAME, but it only does things when the _state variable is set to "play". You can also remove the event listener in the goToPause method:
private function goToPause():void {
_state = "pause";
removeEventListener(Event.ENTER_FRAME, loop);
}
However, the nice thing about using the "_state" to switch things is that you don't end up having a mess of addEventListeners and removeEventListeners (which is what can happen depending on how complicated your loop gets) that you have to keep track of.
You should not use anonymous function call if you would like to remove listener some time later.
public function main():void
{
//...
//some method, where you add event listener
//...
//adding enterFrame event listener
this.addEventListener(Event.ENTER_FRAME,enterFrameHandler);
//...
}
private function enterFrameHandler(e:Event)
{
if(findObject) // " == true" is not really necessary here.
{
// removing enterFrame listener:
this.removeEventlistener(Event.ENTER_FRAME,enterFrameHandler);
}
}
Just for a completeness with the other techniques mentioned here, the function you are creating is a unbound closure, so you can also leverage that concept to reference both your function and dispatcher.
var callback:Function;
var dispacher:IEventDispatcher = this;
addEventListener(Event.ENTER_FRAME, callback = function(e:Event){
if(findObject == true){
dispacher.removeEventListener(Event.ENTER_FRAME, callback);
}
});
Normal closed-over variable rules apply.
I am currently working with some code that my co-worker wrote. Here is a simplified look at it:
The People class:
package model{
public class People extends Array{ // NOTE: it is not dynamic
public function toXML():XML {
var out:XML = <people/>;
for each(var per:Person in this){
out.appendChild(per.toXML());
}
return out;
}
}
}
Which is basicly an Array of Persons:
package model{
public class Person {
public var name:String;
public var phoneNumber:String;
public function Person(name:String, phoneNumber:String){
this.name = name;
this.phoneNumber = phoneNumber;
}
public function toXML():XML {
var xml:XML = <person/>;
xml.#name = name;
xml.#phone = phoneNumber;
return xml;
}
}
}
This is basicly how my co-worker is using the code:
var people:People = new People();
people.push(new Person("Jake", "902 825-4444"));
people.push(new Person("Bob", "514 444-3333"));
return people.toXML().toXMLString();
Note: The he adds Person objects but he never looks at what is in the People Array except to print out the XML
Fast-forward (do people still know that this means?) to the present. I now need to look inside the People class and do something like this:
var people:People = ... init and fill with Person objects
for(var i:int=0; i<people.length(); i++){
doSomething(people[i]); // <-- Error thrown here.
}
Unfortionatly this throws this error:
ReferenceError: Error #1069: Property 0 not found on model.People and there is no default value.
at runner::Runner$/newUse()
at ExtendsArray/start()
at ExtendsArray/___ExtendsArray_Application1_initialize()
at flash.events::EventDispatcher/dispatchEventFunction()
What should I do?
Edit, Aside: Extending Array is not my doing this is part of our old model. We are moving away from the old model because it is full of garbage like this. I just need to grab this stuff from the old model to convert it into the new model. I would like to tear this code out of our product but the cost of doing that is probably not warranted.
What should I do?
Use only class methods to access and set items in your "array", don't use Array-specific syntax. And/or make the class dynamic.
EDIT I think you can leave everything as is and avoid making your class dynamic by defining only one additional method for item access (if it's not there for some reason). Something like:
public functon getItem(index:uint):*
{
if (index >= length) {
return null;
}
return this.slice(index, index+1)[0];
// this creates a redundant array on the fly, sorry.
}
// usage:
var people:People = ... init and fill with Person objects
for(var i:int=0; i<people.length(); i++){
doSomething(people.getItem(i));
}
And I know that is not the way it's meant to be answered on stackoverwlow, but... I can't hold it. ))
Anything extends Array -- is a heresy. If I see that in production code, I'll immediatelly proceed to initiating a "purge the unclean" sequence.
Just try googling for the subject a little bit, and you will see, that almost no one has got alive and well from an activitiy like that.
The main rational reason why this abomination is not meant to exist (aside form it being a heresy) is that you can not use array access [], you can not instantiate it like a normal array with items and you can not set items through array syntax [] and be notified of the changes somewhere in your class. But it is an Array by the right of birth, so any of your fellow developers not familiar with the subject may try to use it like a normal Array, because it's quite natural. And then they'll probably post another question on stackoverflow.
So, if you are still limited to just using class methods, what's the point in extending anyway? Whay not use neat aggregation/composition or proxy ways?
It's amazing, but there's even an article on extending Array on adobe.com. What they do not mention there is that you are likely to start burning in hell right away.
Array.length is a getter: it returns an int. people.length() is the same as calling 3(). I don't know how it worked when you tested that.
It looks like you'd be better off implementing something like IList and have addItem push into a Vector.<Person>. That will guarantee that you only have Person objects.
You should probably should not be extending Array. If you want to extend anything, extend Proxy (You can even use the ProxyArray class example with a Vector.<Person>). Extending top level classes (with the exception of Object) is often an invitation for confusion.
If you really, really want to extend Array, you have to make the class dynamic -- you are arbitrarily assigning and removing properties.
This looks like it works:
var s:String = "";
for each(var per:Person in people){
s += per.name + " ";
}
The People class has to be scripted as public dynamic class since it is extending the Array class.
From this Adobe help article: A subclass of Array should use the dynamic attribute, just as the Array class does. Otherwise, your subclass will not function properly.
You used the "push" function which apparently created an associative array.
Associative arrays can not be called by index. They can also not be reversed or have their order changed.
You need to access them by using the for..in loop
for (var key:String in people) {
trace("person : " + (people[key] as person).name);
}
// or as you found out the for each.. in
for each(var person:Person in people){
trace("person : " + person.name);
}
The arr.length() function of an associative array will always be 0 and you saw that with your error.
//Try this example you will see how an array can act like an array as we know it and an object.
var a:Array = [];
a[0] = true;
a.push(true);
a.push(true);
a["foo"] = true;
a.push(true);
a.push(true);
a.bar = true;
trace("for loop\n");
for(var i:int = 0, ilen:int = a.length ; i < ilen ; i++){
trace(i,a[int(i)]);
}
trace("\nfor...in loop\n");
for(var key:String in a){
trace(key,a[key]);
}
my question is simple, yet I couldn't find any answer of it in the net, maybe it's impossible to do...
The thing is that I have an ActionScript 3.0 application, and wanted to include a little one-line size textbox which showed all the trace() calls and such, which are shown in the console.
Has anyone got any idea of how can it be done? I would really appreciate it, as I have a full project with traces on it that I'd like to show, and it's now when I'm finishing that I'm realising I don't know how to do it :P
Of course not everything is lost, as I could just do my own class that showed there the messages, but it would be cleanier, and quicker not to have to replace all the trace() calls for my new class and method.
Regards and thanks in advance :)
I just did this last week.
There are logging frameworks for Flex out there. A shame, though, that Flex's logging only works in Debug mode. If you search SO for Flex logging you'll find various suggestions. None of them are amazing, IMO.
Finally I rolled my own by just creating a Log class with a static function that acts as a proxy for trace.
Something like:
public static myTrace(... args) : void { ... }
Then you just forward the args to trace but also to whatever other destination you want (e.g. an array of strings + dates) that you can then display in the log window.
Incidentally, I also used SwfAddress to trigger the log window whenever a certain parameter is added to the URL. Very handy.
Oh, what the heck.. here's the class. It just keeps the last 100 strings and there's also a "dump" function that you can invoke if you want to send the data to your server or just quickly print the entire history.
public class Log
{
public static var lines : ArrayList = new ArrayList();
public static const MAX_LINES : int = 100;
private static function logLine(line : String) : void
{
while (lines.length > MAX_LINES)
lines.removeItemAt(0);
lines.addItem({"line" : line, "time" : new Date()});
}
public static function logDump() : String
{
var ret : String = "";
for each (var entry : Object in lines.source)
{
ret = (entry.time as Date).toUTCString() + " " + entry.line + "\n" + ret;
}
return ret;
}
public static function debug(...args) : void
{
trace(args);
var line : String = "";
for (var i : int = 0; i < args.length; i++)
if (args[i] != null)
line += args[i].toString();
logLine(line);
}
}
Alternatively, you can use the ASDebugger
http://labs.flexperiments.nl/asdebugger-20-a-real-time-debugger-and-editor/
ASDebugger.debug( 'shallala' );
ASDebugger.debug_prop( variable );
Try to avoid using the debug display object option. The debugger can crash for complex objects (especially in flex)
You can probably do a simple replacement of 'trace(' to 'ASDebugger.debug('