TweenLite does not work with object - actionscript-3

I got the following problem:
I have an object called tempScore for my game.
This object is blitted to the canvas by a renderer via the copyPixels method. The object is NOT a display object. It's a Score-object (self made). The Score-object extends an object called BasicBlitArrayObject. The BasicBlitArrayObject extends an EventDispatcher (therefore no display object).
I tried to apply several different TweenLite-plugins to my tempScore-object (i.e. TransformAroundCenter, colorMatrixFilter, etc.). But nothing happens. Absolutely nothing.
Sometimes I get error messages (when a plugin requires a display object and my object is NOT a display object). So far so good.
According to Greensock (maker of Tweenlite) his engine can tween ANY numeric property of ANY object. So when a plugin like TransformAroundCenter requires a display object for tweening I have to modify the plugin to get it working for my non-display object (tempScore). Currently I can't do that because it's way too hard for me.
My game rests upon this code:
http://www.8bitrocket.com/book/ch11_blastermines.zip
Try to apply TweenLite with an object called tempMine inside the game class BlasterMines. It won't work. Any help, please?

Greensock's claim is correct, in it's exactness. You can tween any numeric property of any object. This statement does not include the application of plugin features.
The reason that the TransformAroundCenter and ColorMatrixFilter plugins don't work for you is that they each utilise some property or method of DisplayObject. In the case of transformAroundCenter that's DisplayObject.localToGlobal() and for ColorMatrixFiler it's DisplayObject.filters.
I have to ask why you're applying these plugins to something that is not a display object? In blitting (as it applies to AS3), the basic idea is that you read an area from a sprite sheet to a BitmapData object, which in turn you write to a Bitmap object on the stage. Both BitmapData and Bitmap extend DisplayObject, which is what you need. For higher compatibility you should target the Bitmap object that is actually on the stage, TransformAroundCenter will not work correctly with an object that is not on the stage.
For a better answer you will have to post some code, and possibly a screenshot from a debugger like Monster Debugger 3 which shows your expanded display tree.

Related

How to change bitmapdata in AS3

I'm building a spritesheet class. Hopefully this will be low hanging fruit to someone, but I'm stumped.
I have a spritesheet (.png) that I've loaded at runtime and placed a section of it on the stage using this code from within the Spritesheet class .as file ouside of the constructor method:
private function onLoad(e:Event):void
{
var loaderBmp:Bitmap = Bitmap(_loader.content);
_bmpData.copyPixels(loaderBmp.bitmapData, new Rectangle(0,0,80,80),new Point(0,0));
}
That works fine. I get my slice of the .png file displaying nicely. In my case, the spritesheet is meant for animating a character, so I need to update the BitmapData and I'm not having any luck. Here is what I'm trying this within my Main class in a function I use to alter the frame of the animation depending on the state of the character:
c._thisSpriteSheet._loader.content.bitmapData.copyPixels(loaderBmp.bitmapData, new Rectangle(0,20,50,30),new Point(0,0));
loaderBmp is a variable who's value is var loaderBmp: Bitmap = Bitmap(_spriteSheet._loader.content);
c is a reference to the Runner object that is the character.
_spriteSheet is a property of the Runner class of type Spritesheet.
_loader is a property of the c._spriteSheet and is the Loader object used when the spritesheet was instantiated.
It doesn't throw an error, but it also doesn't replace the original bitmapData object with the new one. I thought maybe this meant that I need to create a new BitmapData object and use that in the copyPixels method, but that returned the same results (nothing). When I step through the code in debug mode, everything looks like it is working, but my display object does not update with the new bitmapData. What am I tripping on?
Thanks for looking!
Well, probably no one will read this since I'm answering it so quickly, but I literally spent 3 days trying to figure this out. Sometimes trying to ask the question in a concise way helps one answer their own question, and moments later, voila!
So in case anyone has a similar issue, what I was doing wrong was that I was trying to access the BitmapData object via the Loader that originally loaded it. Then it dawned on me that I could simply reference the BitmapData directly via that property of the SpriteSheet class I had made. I think this will be pretty confusing for someone else to follow. If a moderator sees this and thinks it's junk, I don't mind it getting erased, but thought I'd keep it up anyway. The new code looked like this:
c._thisSpriteSheet._bmpDSheet.copyPixels(loaderBmp.bitmapData, new Rectangle(0,20,50,30),new Point(0,0));
and _bmpDSheet is the bitmapdata property of the class.

AddChild with GetChildByName

Complete AS3 noob here - I've tried Googling this, but I can't seem to find what I'm looking for (I stumbled across this, http://ub4.underblob.com/as3-naming-elements-dynamically/, but it doesn't weem to work for me).
I'm trying to dynamically add a Movieclip inside another Movieclip through an external AS3 class
Something like this:
var bullet:Bullet = new Bullet(x, y, "right");
var stageBackground:MovieClip = (stage.getChildByName("back") as MovieClip);
stageBackground.addChild(bullet);
However, while this compiles correctly, at run time, I get error #1009 - Cannot access a property or method of a null object reference.
The debug panel tells me the problem is with this line:
stageBackground.addChild(bullet);
But I can't seem to figure out what's wrong with it. I've tried recasting stageBackground as a Sprite, but that didn't change anything. I know the MovieClip back exists - when I reference it through near identical code in my document class, it works perfectly.
You are accessing stage here to find your container, which is very likely the problem.
You are probably thinking that the stage property refers to "the stage" in Adobe Flash authoring environment.
That's not true.
If you placed a MovieClip on "the stage" in the Flash IDE, it ends up on the main time line, this however, is not the thing the stage property is referencing. stage is the topmost DisplayObjectContainer in the display list. It only exists at runtime. It more or less represents the FlashPlayer window, the runtime environment that executes your .swf file.
In short: you are simply looking for your back MovieClip in the wrong place.
The property of a container that represents the main timeline is root.
Do not use root either.
As you can see, your code becomes dependent on the display list
structure of your application. You are already struggling to find the
container that you are looking for. If you change the structure, your code breaks. Even changing the name of the container (for example to something like "background") will wreak havoc.
Instead, use Events.
You are in another class and you want to fire a bullet.
So you create that bullet same as you do now:
var bullet:Bullet = new Bullet(x, y, "right");
Next, dispatch an Event to notify the rest of your code that a bullet was created and it should be placed in the appropriate container:
dispatchEvent(new BulletEvent(BulletEvent.CREATED, bullet));
(Create a custom event class BulletEvent that extends Event, with the apropriate setter and getter for a Bullet object)
Register a listener on the object of your class that creates the bullets, you will catch this event and place the bullet in the container:
var object:YourClass = new YourClass();
object.addEventListener(BulletEvent.CREATED, addBulletToContainer);
function addBulletToContainer(e:BulletEvent):void
{
// adding the bullet to the container
back.addChild(e.bullet);
}
This code would be placed in the parent of your back MovieClip.
The Flash IDE automatically creates variables behind the scenes that have the same names as the instance names. That's why the variable back is available here.
Using events here allows you to literally fire the bullet into your code with somebody else taking care of it, where it's easy to figure out the container it belongs into.

What happens to a Movieclip when casted as a Sprite?

(Note that there is nothing really 'wrong' here with my code (in the sense that it works), but more wondering on how it is working and what is happening under the hood)
Currently I have two libraries, each with one object. One is set with the class "Apple" and the other is "Pear", They are located in separate external swfs.
Apple's base class is MovieClip as content-wise it is a movieclip: has frames + animation
And here is the code I used to create and display an Apple movieclip object:
function getClip(inputName, spriteLibrary:Loader):MovieClip {
var aClass:Class = spriteLibrary.contentLoaderInfo.applicationDomain.getDefinition(inputName) as Class;
return (MovieClip) (new aClass());
}
this.addChild(getClip("Apple", referenceToTheLoadedSwfThatHasAppleInIt));
The above works just fine and Apple appears on the stage and plays.
However, Pear's base class is a Sprite (has no animation, frames, etc). So the above fails, since the method is supposed to return a MovieClip.
this.addChild(getClip("Pear", referenceToTheLoadedSwfThatHasPearInIt));
I thought for a moment I would have to have two versions of the above method, one for Sprite and one for MovieClip. But just to see, I changed it to Sprite and tried to create Apple:
function getClip(inputName, spriteLibrary:Loader):Sprite {
var aClass:Class = spriteLibrary.contentLoaderInfo.applicationDomain.getDefinition(inputName) as Class;
return (Sprite) (new aClass());
}
this.addChild(getClip("Apple"), referenceToTheLoadedSwfThatHasAppleInIt);
this.addChild(getClip("Pear"), referenceToTheLoadedSwfThatHasPearInIt);
Now both will work, but interestingly, I found that even though the method returns a Sprite, Apple still seems to work fine and plays it's animation on the stage. I can cast this to a MovieClip and access all the MovieClip related properties and so forth.
My question is then, when Apple "existed" as a Sprite, what happened to all of it MovieClip related "stuff" and is this actually a normal thing to do when having to work with MovieClips and Sprites (by pretending you only have Sprites and cast to MovieClip only when you need it?)
A Sprite class provides more basic functionality than a MovieClip, but everything that's a MovieClip can be manipulated by using the functionality of a Sprite class. In fact, your method can return as low a class as DisplayObject if your only intention is to do an addChild(). The typecast will not strip the typecasted object of any functionality, it will instead restrict the available calls for its properties. Say, a DisplayObject has x and y properties, a Sprite can be used to add objects to itself (the addChild() method) which the DisplayObject does not have, and a MovieClip has internal animation and a say gotoAndStop() method which a Sprite does not have. So, if you typecast an Apple to a Sprite, you cannot make a call to the reference's gotoAndStop(), because you've told the program that the reference is just Sprite. If you typecast the Apple or the Pear object to DisplayObject, you cannot call its addChild() method to say add a health bar (weird thing for apples to have health bars, but why not?), because the reference does not know that the underlying object supports this functionality. But actually nothing will happen to either object, no matter how you typecast them, you will just restrict yourself from applying more advanced actions via received reference.
Actually it's good practice to limit the functionality for yourself via typecasts, because you are then protected from making "crutches" over working code which can probably spoil its purpose. Say, your code will not be surprised in case you would decide to turn Apple into an advanced Sprite class (say, public class Apple extends Sprite {...}) with tailored properties, embedded event listeners, color-changing maybe, but if you typecast the newly created Apple to Sprite or DisplayObject, you are abstracting from any extra abilities of the instance and only use its basic interface (properties and methods of a typecasted class) to perform the actions the Sprite or DisplayObject are intended for. If you have some overridden properties in the advanced Apple, they will work as you have intended while making the Apple class, even if addressed from the superclass description - this is actually what override is for.
In short, don't worry about losing functionality, but try typecasting to least possible class with used functionality.
About "what happens under the hood": Each class has its own table of properties and methods, if a class is extending another class, that class's table is identical to the superclass's up to its end, and the extra space is occupied with information on properties and methods implemented by the class. If there is an override, the overridden method's info replaces the info of the corresponding method in the table for the class, not for the superclass though. Each instance has a memory block allocated to it, there is a reference to the class's properties and methods table, which is then used to execute correct code, if a method is called via instance reference. So, when you call a method, or a property with a getter or setter assigned to it, out of an instance, the following happens:
The correct set of parameters, including "this" pointer to that instance, is pushed into the stack. The correctness of the order and the type of parameters is ensured by Flash compiler.
Then, the class that's actually the proper class of that instance is referenced via prototype property of the instance. Every class in AS3 has this property. The instance is accessed via "this" pointer previously pushed into the stack. (Technically it's stored in more than just stack, so the reference is just the same that's put in the stack)
Then, the correct offset (determined by the compiler) is returned from that table, that is the address of the called method of the class. Overridden or not, no matter here, because an improper override is detected at the compile time, and will not happen here.
Then, code execution is transferred to the returned address. The method's code then parses the parameters in stack, does some more data protection and proceeds with its implementation.
The most important thing to understand here is that nothing happens to the object itself, but the way the compiler treats the object will differ.
For example, the compiler will treat the object returned by this function as a Sprite, even if we actually return a MovieClip:
function makeSprite():Sprite
{
return new MovieClip();
}
var test:MovieClip = makeSprite();
// 1118: Implicit coercion of a value with static type flash.display:Sprite
// to a possibly unrelated type flash.display:MovieClip.
So what we need to do here (as you understand currently) is tell the compiler that the result is actually a MovieClip via typecasting:
var test:MovieClip = makeSprite() as MovieClip;
Another thing to take notice of is that if you were to trace() the result, you would get [object MovieClip] rather than [object Sprite]:
trace( makeSprite() ); // [object MovieClip]
And using is to check if it's a MovieClip will return true:
trace( makeSprite() is MovieClip ); // true
Even if you used a more primitive type for test, your object would truly be a MovieClip:
var test:Object = makeSprite();
trace(test); // [object MovieClip]
Casting a MovieClip to a Sprite doesn't strip it of its MovieClip implementation; it simply tells the calling code (in this case, this.addChild()) that "this object is a Sprite; please treat it as such." The calling code doesn't know — or care — that it's really a MovieClip, because as long as it's a DisplayObject (which a Sprite, and in turn a MovieClip, derives from), the addChild() method will happily accept it.
Since a MovieClip is a Sprite anyway, it doesn't make any difference to the calling code. As for the Apple object itself, though, it's still a MovieClip at heart, and so will continue to function on its own like one.
As an analogy, think of going to the grocery store, buying some goods, and paying at the counter. You're a person with many different roles in various aspects of life, but as far as the cashier is concerned, you're just a customer making a purchase. That doesn't make you any less of a person, but the cashier doesn't have to be interested in who you are or what you do, beyond just a customer making a purchase.
TL;DR:
Your MovieClip will stay a MovieClip, but the reference that is down casted to a Sprite will be able to access only methods and variables that are available to Sprite.

as3 how can i prevent that a new instance is created by entering a frame?

i am working with several nested movieclip objects in a project. but i get into trouble with the buttons i created and implemented in the nested movieclips:
to describe it in a simple way:
I have a main movieclip with five frames, including two buttons with listeners to browse between the frames. Then inside of one Frame I have another movieclip with its own buttons. i instanciated it by hand not through code and gave it a specific name like "nestedMc".
Now I dont want to build the Listeners for those buttons inside the class of the nested movieclip class but in its parent class, which works fine until i then goto another frame in the main movieclips timeline and come back.
obviously every time flash enters a frame its contents get created anew (and therefore get new instance names). I could now try solve this through filling the frames via code.
But maybe there is another way to make sure the frame contains the same instance everytime i enter?
Timeline scripting is a dirty business, and really, a carry-over compatibility layer for Actionscript 2 projects. Whenever possible, I highly recommend not doing it, and simply keeping all of your code in your document class. As you're experiencing, timeline code causes headaches.
Consider instead just creating both states of your Stage (it sounds like that's what your two buttons are jumping between) and simply hiding them offstage or setting their alpha to zero and their mouseEnabled state to false. Furthermore, if the purpose of your frames is to play animation (a tween), consider instead switching to a much more powerful suite such as TweenLite. Moving an object over a hundred pixels (smoothly) can be as easy as:
TweenLite.to(redBall, 3, {x:100});
Now, if you're manually adding these items to the stage, as long as the object is a dynamic one, you can assign an instance name to it which will be saved between frame loads. Be aware the object name is not the same as the instanced name. For example:
var redBall:Ball = new Ball();
redBall.name = "bubbles";
The object's name is Ball, but it's represented as a variable called redBall. Its actual DisplayList name will likely be ambiguous (such as "Instance71"), and I can manually define it as "bubbles". 3 different names for the same object, all very different and necessary.
Even if you give the object a displayList name, you may not be able to reference it through code unless you enable Automatically declare stage instances, which basically creates on each object a pointer to the displayList object.
That said, you can always fetch the object by other means. Obviously, your buttons are always appearing, but you're trying to find a very specific object on the stage. At this point, we can use getChildByName() or getChildAt().
Hope that helps.
-Cheers

Is it possible to create a MovieClip using ActionScript 3 code or MXML?

I'm using the Flex 3 SDK and the free FlashDevelop IDE.
As I don't have FlexBuilder or Flash CS4 Professional I cannot make MovieClips graphically.
So instead I want to create a simple MovieClip using code or MXML. For example, lets say I want to create a MovieClip with 3 frames, and load a bitmap into each frame to create a simple animation.
Is this possible? I've had a good google around and the only examples I can find are of loading existing MovieClips and adding them to a stage.
You can create a movieclip with this simple code:
var mc:MovieClip = new MovieClip();
stage.addChild(mc);
That is of cause just and empty movieclip, you can draw on it with graphics property (see here).
As far as I know there is no way to create frame with actionscript. Though there might be some undocumented methods. There are some functions that do not appear in the documentation (like the addFrameScript method).
I would say the best way (if you absolutly can not use the Flash CS4), would be to have a series of Loader objects, and the hide and show them on every in sequence.
Just put them in an array and listen for the enterFrame event.
You can load in the bitmaps in the Loader objects.
If you use the links and checkout the examples in the documentation, I think you should be able to figure it out.
As far as I've seen, there is no easy way to create a MovieClip in Flex which behaves in a way one might see as comparable to Flash's implementation MovieClip. But I don't think you really want a MovieClip to begin with. Flex does not really play well with non-flex objects. Yes, it is possible to add something to a UIComponent, but you are much better off working withing the Flex framework than doing workarounds.
I would use the mx:Image tag to load your images. It is generally the cleanest way to load an image into Flex. It will let you embed the object into the SWF at compile time, which means that you will not have to point to an outside file. I will caution about having too many embedded graphics -- that will kill your download time and possibly your performance.
If you are only interested in having an animation move or re-size, then I would use the Move and Resize objects which are native Flex Tweens.
Your best option might be to extend the UIComponent class, add a MovieClip as a child-component, and apply the settings from MXML via proxy. e.g.,
public function set movieFrames(value:Array):void {
for each(var b:Bitmap in value) {
//add bitmap to _movieclip object.
}
}
You want a Sprite not a MovieClip. And use time instead of frames. There's a Timer class and a getTimer() function. Use them.
create a class that extends/implements Sprite.
Add a Loader class.
Google it exactly how it's done. (flashtuts.com or sth like that).