Is there arguments that work most of the time in AS3? I want a code setup that will works most of the time. Any suggestions?
Books break it down, but don't show how the programmers arrived at their conclusions. This could turn in to a discussion question, but if there's a secret I want to know.
WHAT I'M AFTER
- an argument structure
- learn a process to perform function calls
- expand variables beyond my "20 lines of code"
- manage variables, events, and functions systematically
2 examples that do the same thing, but are structured different "go figure"
//Example #1 "move the ball"
addEventListener(Event.ENTER_FRAME, onLoop, false, 0, true);
function onLoop(evt:Event):void{
ball1.x += 5;
}
//Example #1 "move the ball"
function moveBall(e:Event):void {
ball2.x += 5;
}
ball2.addEventListener(Event.ENTER_FRAME,moveBall);
The if...else argument "ball loop"
//growing collection of arguments
addEventListener(Event.ENTER_FRAME,myEnterFrame);
function myEnterFrame(event:Event) {
if (ball.x>800) {
ball.x=-160;
} else {
ball.x+=5;
}
}
DIFFERENT WAY OF DOING IT "from Adobe livedocs"
EQUIVILANT BOOLEANS
var flag:Boolean = true;
var flag:Boolean = new Boolean(true);
var flag:Boolean = Boolean(true);
EQUIVILANT STRINGS
var str:String = new String("foo");
var str:String = "foo";
var str:String = String("foo");
COMMENT
a functional style like lambda calculus would be a good example "more math less syntax and class structures"
EVENT LISTENERS
http://www.adobe.com/devnet/actionscript/articles/event_handling_as3.html
I would suggest you read up on event handlers on Adobe's site. http://www.adobe.com/livedocs/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000139.html
From the site, here is the function definition of addEventListener:
function addEventListener(eventName:String,
listener:Object,
useCapture:Boolean=false,
priority:Integer=0,
useWeakReference:Boolean=false):Boolean;
The last three arguments have default values (false, 0, false) so those can be left out when you call the function. The first two arguments are always required.
I think that the rest of your question would be best answered by learning about object oriented programming in AS3. Here is one guide: http://www.adobe.com/devnet/actionscript/articles/oop_as3.html
Actually, many developers prefer to set useWeakReference to true, which requires that you plug in all five arguments into event listeners. The reason is that that way the listener doesn't hold a reference to the target that would prevent garbage collection - it's a memory management technique. Most really good AS3 devs will tell you to always use all five arguments, just to get to that point.
Also, generally speaking it's better to use a literal when you can. "text" instead of new String("text"), true instead of new Boolean(true). Complex reasons, but there's your short answer.
The answers to a lot of these questions can be found here, which is a document that attempts to standardize AS3 coding conventions. It's worth reading over!
Related
I am working on a large Flash project.
I have tried "Goto Declaration" but that doesn't seem help.
Btw I am using FlashDevelop. And Yes I can perfectly compile and build TO 100% working source.
Here is a code sample. I know you can't do much with this but tell how I can work with this.
public function aim_(_arg_1:Vector3D, _arg_2:Vector3D, _arg_3:ProjectileProperties):Vector3D
{
var _local_4:Vector3D;
var _local_5:GameObject;
var _local_6:Vector3D;
var _local_7:Number;
var _local_8:Number;
var _local_9:int;
var _local_10:Boolean;
var _local_11:int;
var _local_12:Boolean;
var _local_13:* = undefined;
var _local_14:int = Parameters.data_.aimMode;
var _local_15:Number = (_arg_3.speed_ / 10000);
var _local_16:Number = ((_local_15 * _arg_3.lifetime_) + ((Parameters.data_.Addone) ? 1 : 0));
var _local_17:Number = 0;
var _local_18:Number = int.MAX_VALUE;
var _local_19:Number = int.MAX_VALUE;
aimAssistTarget = null;
for each (_local_5 in map_.goDict_)
{
if (_local_5.props_.isEnemy_)
{
_local_10 = false;
for each (_local_11 in Parameters.data_.AAException)
{
if (_local_11 == _local_5.props_.type_)
{
_local_10 = true;
break;
};
};
What you're trying to achieve is reverse engineering a decompiled code. With "_local" variables you need to investigate what values they are assigned, in what algorithms do they participate, and here you just need to read this single function in its entirety to be able to discern meaning of those local variables. But, you would also need to understand many of the named parameters to get some of those meanings. For example, _local_11 iterates through some Parameters.data_.AAException list of ints, and is compared with current outside loop iterator's props.type_, therefore "AAException" should mean "AA exemption" and _local_10 provides check result, whether current enemy is exempt from AA (whatever is that AA). And so on.
Same with _arg_X variables, you need to find out what's being passed into a function from wherever it's called, and retrieve the context of those parameters, also taking their type into consideration, like here _arg3 is of type "ProjectileProperties", meaning this function should relate to some projectile which properties affect its outcome somehow. Most likely it's taking two vectors of projectile (or source, this is outside of this code) and target (or speed, same here), and generates another vector of yet unknown purpose.
When you have investigated every function like this, you'll have quite a bunch of pieces to a single puzzle that you can combine by references, discovering all the algorithms that combine the code of whatever app you've decompiled. Then you will be able to do targeted modifications of whatever kind you wanted initially. But yes, it'll be better if you'd have access to actual sources from whoever created this the first time.
In short: Think. Think, think and think.
I used to work on AS2 and make games, and now I wanna learn AS3 and have all its nice features (using Flash CS IDE). Now I m trying to rewrite a function to discard it.
function something():void{
//do something
}
function something():void{}
like this. please help or just give some alternatives, thanks.
What you're trying to do is very illogical - a function should be defined once and exist always. Not only that, but it should definitely always behave the same way, especially considering AS3 does not support overloading.
AS3 introduces the OOP paradigm for you to use - this further emphasises the above - you should create classes which define a fixed collection of properties and methods. This way, the intent of each class in your application is clear, and what you expect something to be able to do won't change.
If you absolutely must be able to delete functions, you can assign them to a dynamic object and remove or redefine them with the delete keyword:
var methods:Object = {
something: function():void
{
trace('Still here.');
}
};
methods.something(); // Still here.
delete methods.something;
methods.something(); // TypeError: something is not a function.
methods.something = function():void
{
// Define new function.
}
Or assign an anonymous function to a variable of type Function, from which point you can set the reference to null:
var something:Function = function():void
{
trace("Still here.");
}
something(); // Still here.
something = null;
something(); // TypeError: value is not a function.
something = function():void
{
// Define new function.
}
I need to create a variable:
var numDots0:Number=0;
But when a button is clicked the variable numDots0 becomes numDots1, then numDots2 on a second click, and so on. I then need to be able to grab that new variable name and use it in a function.
That's a really, really weird request, but anyways:
You can use the key name of an Object to store the property and then change that:
var obj:Object = { numDots0: 0 };
And then when you want to change the name:
delete obj.numDots0;
obj.numDots1 = 1;
Or to easily increment you can use this:
var i:int = 0;
function increase():void
{
delete obj["numDots" + i];
obj["numDots" + (++i)] = i;
}
To access:
trace(obj.numDotsX); // where X is the most recent variable name.
I see absolutely no benefit or need for this, so I strongly suggest taking a look at what you're trying to do and making sure it makes sense and doesn't have a different application.
I am pretty sure you are going the wrong way about the problem you are trying to solve. Dynamic variable names are not something you read in the best practices book.
Anyway to answer your question in AS2 you could use the command eval which would evaluate a string as ActionScript, so you would use something like:
function onClicked(e:MouseEvent):void
{
counter++;
eval("var numDots" + counter +"+:Number=0;");
}
In AS3 that command has been removed (because it leads to bad coding practices - like the things you are trying to do), nevertheless someone implemented an evaluator in AS3:
http://eval.hurlant.com/
With this evaluator add the library to your project and add the following to the snippet above:
function eval(expression:String):void
{
var evaluator:com.hurlant.eval.Evaluator = new com.hurlant.eval.Evaluator();
var bytes:ByteArray = evaluator.eval(expression);
bytes = ByteLoader.wrapInSWF([bytes]);
var context:LoaderContext = null
var loader:Loader = new Loader();
loader.loadBytes(bytes, context);
}
the answer is to not do what you are trying to do and use an array, hash or vector instead. give us a bit more context, or the reason you want to achieve exactly what you want to and why you might believe you'd need a dynamic variable name like that. you shouldn't be using evals or anything that changes variable name at runtime because the gods of programming will strike you down where you stand. i.e., your program is going to break, and when it does, it's going to be harder to debug for sure.
if you are sure this is what you want to do, then i'm wrong, haha. good luck!
I'm trying to differentiate anonymous functions like:
function() { trace("WOO"); }
from the other ones ('named'?) like
var _FUNC:Dynamic = function() { trace("WOO"); }
The reason I want to do that is because I can't compare between two anonymous functions, because they are two different ones.
To help me make things clearer, consider the following quick example.
var _TEST:Dynamic = function(a:Dynamic):String {
var _TESTA:Dynamic = function() { trace("WOO"); };
var _TESTB:Dynamic = _FUNC;
return (a == _TESTA) + ", " + (a == _TESTB);
}
If I run _TEST(_FUNC);, I'll get back "false, true". Even though they are the same function, they are NOT the same object.
Is there a way to compare those such that functions that they are the same if they perform the same task?
Is there a way to serialize functions? So that maybe I can compare the serialized representations and see if they share the same 'code'.
A few clarifications:
The first two samples you have posted are virtually identical. The only difference is that you have assigned the second to a static var. You could have used a static function directly with the main difference that in that case the function is not changeable If you want to make it so you should add the dynamic modifier.
Starting from the latest version you can have local named functions:
static f() { function a() { trace("hi"); }; a() }
To properly compare methods you should use Reflect.compareMethods(). Sometimes Haxe creates closures around functions and that can break equality.
You can compare function references but not the function bodies. So the answer is no, you can't compare function that are generated in different statements but do the same thing.
You cannot serialize functions.
You can maybe find some platform specific way to deal with this situation or Macro may apply too (to create function signatures) but I think it is easier to redesign your code. Another option is to adopt a lib like hscript for those calls that need to be comparable and serializable.
when launching the following code in ADL, why does the square continue to rotate?
var square:Sprite = new Sprite();
square.graphics.beginFill(0xFF0000);
square.graphics.drawRect(-25, -25, 50, 50);
square.x = square.y = 100;
addChild(square);
addEventListener(Event.ENTER_FRAME, rotateSquare, false, 0, true);
function rotateSquare(evt:Event):void
{
square.rotation += 2;
}
System.gc();
Update
the following display object has a weak referenced ENTER_FRAME event listener. however, calling:
removeChild(testInstance);
testInstance = null;
doesn't stop the ENTER_FRAME event:
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Test extends Sprite
{
private var square:Sprite;
public function Test()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(evt:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
square = new Sprite();
square.graphics.beginFill(0xFF0000);
square.graphics.drawRect(-25, -25, 50, 50);
square.x = square.y = 100;
addChild(square);
addEventListener(Event.ENTER_FRAME, rotateSquare, false, 0, true);
// //Current Solution - only works on display objects
// addEventListener(Event.REMOVED_FROM_STAGE, removeHandler);
}
private function rotateSquare(evt:Event):void
{
trace("square is rotating");
square.rotation += 2;
}
// private function removeHandler(evt:Event):void
// {
// removeEventListener(Event.REMOVED_FROM_STAGE, removeHandler);
// removeEventListener(Event.ENTER_FRAME, rotateSquare);
// }
}
}
i have added a REMOVED_FROM_STAGE event listener, but this will only work on display objects.
is this problem specific to ENTER_FRAME event?
Regarding your update, I think you are misunderstanding how GC works. The basic idea is rather simple.
When you create an object, flash allocates some memory in a storage called the heap. A reference to this object is returned. This reference is what you store in a variable. What is a reference? A means to access this object. Think of it as link to the object.
var foo:Bar = new Bar();
Now, in some languages, at some point you have to release the memory allocated for this object when you're done with it, or you have a memory leak.
In a GC environment, this is done automatically. Of course, you need some rules. This rules vary depending on the concrete GC, but in general terms, you could say the GC determines that an object is collectable if it's no longer reachable. This makes sense, because if you can't reach an object, you can't use it. You've lost your link to it. So, it's considered garbage and will be eventually collected.
The specifics on how reachability is determined vary, but in flash it's a mix of reference counting and a mark and sweep algorithm.
(The following is just a high level overview, the details might not be exact)
One method is reference counting: it's easy and fast but it doesn't work in all situations. Basically, each object has a reference count. Each time you assign this object to a variable (i.e. you store a reference to the object), the reference count is incremented. Each time you lost this reference (for instance, you null out your var), this count is decremented. If the count reaches 0, it means the object is unreachable and so it's collectable.
This works fine in some cases, but no others. Specially when there are crossed references.
var foo1:Bar = new Bar(); // let's call this object Bar_1
var foo2:Bar = new Bar(); // let's call this one Bar_2
// at this point, Bar_1 has reference count of 1 (foo1) and Bar_2 has a reference of 1 (foo2)
foo1.theOtherFoo = foo2;
// now Bar_2 has a RC of 2: foo2 and foo1.theOtherFoo
foo2.theOtherFoo = foo1;
// now Bar_1 has a RC of 2: foo1 and foo2.theOtherFoo
foo1 = null;
// foo1 no longer references Bar_1, so its RC is decremented.
foo2 = null;
// foo2 no longer references Bar_2, so its RC is decremented.
// but still both Bar_1 and Bar_2 have a RC of 1.
As you can see, both Bar_1 and Bar_2 have a RC of 1, but are unreachable. This is one of the cases where reference counting doesn't work. Because for all intents and purposes, both objects are unreachable and yet won't be collected.
That's why there's a mark/sweep algorithm. From a high level point of view, what it does is traversing your objects graph, starting from some root objects and analize its relationships to determine whether an object is reachable or not. This algorithm will determine that even though Bar_1 and Bar_2 have a RC of 1, they're not reachable and thus should be considered garbage and be collected at some point.
Events, listeners and dispatchers work the same way. They're not a special case. When you do:
function test():void {
foo1.addEventListener("someEvent",someHandler);
}
function someHandler(e:Event):void {
}
It's the same as doing:
function test():void {
foo1.someProperty = this;
}
The effect is that foo1 now has a reference to this. You'd normally call removeEventListener when you're done for 2 reasons:
1) You no longer want foo1 to have a reference to this.
2) You no longer want to listener for "someEvent" events.
Lots of people insist on using weak references, because they think that then you can pretend you don't have to call removeEventListener (which is apparently too hard...). This is wrong. removeEventListener does two things and both are important. If you want to stop receiving notifications for some event, you have to tell the dispatcher. It's really that simple. In my opinion, weak references are innecesary in most cases. Some advocate to use them by default; but in my experience, in practice this is a bad service to them, as it confuses people further, encourages them to write sloppy code and gives them the impression that you can ignore how this very basic feature of the language (which is not that hard to graps) works.
Now, after this rather long (but hopefuly constructive) rant, let's look at your code:
Your sprite is not going to be collected, because it has 2 references:
1) the square variable
2) the stage.
The first follows the rules outline above. The second too, but it might not be so obvious at first sight. But it makes sense if you think about it for a second. When you did this:
addChild(square);
square got added to the Test instance, which is in turn added to the stage. The stage is always alive, so if something can be reached from the stage, it's reachable. As long as square remains added to the stage, you can be sure it won't be collected.
So, if you at some point do what Sean Thayne suggested:
removeChild(square)
square = null;
your Sprite will be collectable. That doesn't affect the fact that you told your Test object that you wanted to be called whenever a frame is entered. And that's exactly what's happening. Until you don't tell it you don't want to receive this event anymore (calling removeEventListener), it will call you back.
Flash's garbage collection only clears out elements/objects/variables that have either a zero reference count or have only weak references.
This means you would need to do this. For it to truly be gc'd.
removeChild(square)
square = null;
System.gc()