Extending the Sprite class for convenience? - actionscript-3

I'm always tempted to extend the Sprite class just so my object can be part of the display list (and also have EventDispatcher functions), even though it has nothing to display. It will, however, contain things to be displayed. It's convenient because those contained objects need only reference their container for display list access.
Has anyone run into this temptation?
It seems like it would be common, but also seems inappropriate.
Is there a significant memory cost to needlessly extending the Sprite class?

Why do you want something to be part of the display list? You say: It will, however, contain things to be displayed.
If you mean you want to compose displayable objects, e.g. doing something like:
var container:Sprite = new Sprite();
var image:Sprite = new some_lib_image();
var image2:Sprite = new some_other_lib_image();
container.addChild(image);
container.addChild(image2);
stage.addChild(container);
Then that is totally acceptable. If you want to create a class called ImageContainer that manages the adding and removal of images and use it instead of Sprite - that too is totally acceptable. I wouldn't call it a temptation but I wouldn't do it unless you were adding something worthwhile to the above code.
Is there a significant memory cost to needlessly extending the Sprite class?
Not particularly. The size of your class will generally be something close to sizeof(Sprite) + sizeof(instanceVariables[]) where instanceVariables[] are the new variables you declare in your class. I wouldn't worry about it. Composition is more costly than inheritance; that is needlessly using too many containers. In the general case I never worry about it but if I were to create 5000 particles in a particle system I'd try and keep each particle as simple as possible.

Related

Assign integer values to movie clips in ActionScript 3

I am trying to make a card game in Flash using ActionScript 3. I'm not too familiar with the language(grew up with AS2) but I considered it to be more appropriate for this project.
Bad thing about this, though, is that I ran into a problem right away: I'm treating each individual card as a movieclip, but something that I really need is to assign some integer values to the card(It's not really the case, but as an example let's say that I am working on a Poker and I want all Aces to carry the value 1 because they are the best card, 2 for the kings, etc).
I tried looking for it but all I found is how to make arrays of movieclips. I know that this question shouldn't be too hard! Can somebody help me?
(As an aside note, should I really work with movie clips or would buttons be more convenient?)
Firstly, from my point of view, never use components unless you really need to since they take longer time to draw and they're not flexible. I've had so many issues with them in the past (this question I posted being one of those).
About MovieClip's… The MovieClip class is dynamic so you can assign any virtual property to it, no problem. So yourMcInstance.someVar = 3 is perfectly valid.
One of the major changes in AS3, I think, was the introduction of Sprite class, which is basically a MovieClip without a timeline. It is much lighter and unless you're manually creating frame animations it is the class to choose for any container that can handle mouse (and many other) events. However, it is not a dynamic class so yourSpriteInstance.someVar = 3 wouldn't be valid. And that's why using custom classes is encouraged. With custom classes you have the option to extend a class and create custom properties and methods.
because Movieclips are Objects, you can actually attach variables directly to them.
var card:MovieClip = new MovieClip(); //create a blank MC
addchild(card);
card.id = 5; //You can attach vars like this
To add MovieClips to an Array:
const clips:Array = [];
function addNewCardToCardsArray(array:Array, color:String, value:int):MovieClip {
const clip:MovieClip = new MovieClip();
clip.color = color;
clip.value = value;
return array[array.length] = clip;
}

AS3: How to supplement function calls in an existing library?

I have a semi-newbie question. I've been programming for years, but all my early experience was pre-OOP and my brain kind of settled that way. I'm also new to Actionscript. So hopefully this is an easy one for somebody.
I'm using as3svgrendererlib to import SVG. It works great, but I need to be able to serialize the graphics it outputs. But I can't serialize sprites, so I have to go all the way down to the IGraphicsData level to get something that I can. But the library doesn't give me that data. It only gives me sprites. So I need to change that.
Since there are only a handful of drawing methods that it ultimately uses (beginFill, drawRect, etc), my thinking is that if I can hook into those and supplement them with my own code to output IGraphicsData as well, then I'll be in business. Now I know I could do that by using "extends" classes, but that would require substantial modification of the library to change all of those standard calls to my custom ones.
So I'm wondering: Is there a magic OOP way to write methods that will universally intercept calls to existing methods without needing to modify the original calls?
Thanks! :)
EDIT: I need resolution-independence, so it's important that I keep the graphics in vector and not convert them to bitmap.
You cannot do this kind of thing in OOP, you either need to override the class (but that might not be possible in your case) or modify the library directly.
However, in your case, a possible solution would be to:
Draw the SVG to a sprite using the library.
Draw the sprite to a BitmapData.
Finally, get the pixel data using getPixels() and serialize it.
Something like this should work;
var sprite:Sprite = new Sprite();
// Add the child to the stage...
// Draw the SVG to the sprite...
var bmpData:BitmapData = new BitmapData(spriteWidth, spriteHeight);
bmpData.draw(sprite);
var pixelData:ByteArray = bmpData.getPixels(new Rectangle(0, 0, bmpData.width, bmpData.height));
// Here serialize the byte array
In this example, note that spriteWidth/spriteHeight are not necessarily "sprite.width" and "sprite.height" (sprites often report dimensions different from what you would expect). So you need to decide in advance the size of the rendered SVG and use this when building the BitmapData.

How to updating JLayeredPane while the JFrame is running ? java

Having read many tutorials, articles and questions, I am still have confusions about updating the GUI. Plus there are numerous related questions here on this website and still no luck - even though I think my problem is very simple.
Basically, I have a JFrame that has a JLayeredPane as its root container. And I have some layers of JPanels inside it.
The main issue is with updating a particular JPanel in this JLayeredPane. And for this particular Panel, I have implemented an update method that changes the contents inside it.
updatePanel(int para)
//doesn't remove this panel
//removes some existing labels and replaces it with new ones
Once I create the whole Frame, obviously just calling this method won't show any change displayed the frame.
private void static main (String[] args){
WindowFrame frame = new WindowFrame()//WindowFrame extends JFrame
frame.updatePanel(2);
.....
.....
}
And that's where I am stuck. I want to update the contents as the frame is displayed.
I saw these methods mentioned by people but due to nature of problems, I couldn't fully grasped the concepts. Plus the documentation on these methods isn't really helping - at least to me.
revalidate()
validate()
repaint()
How/when should these methods should be called? Or is this not the right way of what I should be doing, given these methods and the problem I am trying to solve?
Thank you for your time.
Basically you need two methods:
revalidate()
This method does the same as invalidate() but in AWT event dispatching thread (i will just call it Swing thread later on)). It updates container and all of its ancestors (parent containers in which this one is placed) layouting.
Basically if you either move something inside this container or place/remove components inside of it you should call this method (or invalidate in case you are performing it in Swing thread, for example inside any Mouse/Action listener body or just inside).
repaint()
This method forces component, all its sub-components (if it has them) and parent container (basically if this component is NOT opaque) to update what they are "painting".
Usually you don't need this method since all standard Swing components know when to repaint themselves and they do it on their own (that ofcourse depends on components UIs and some other things). This method might be useful in case you have your own specific components with some unique painting-way (for e.g. some custom selection over the components) and in some rare problematic cases with standard components.
Also the way this method acts depends on the components placement (due to some Swing painting optimizations) - if you have some massive repaints rolling you'd better optimize them to repaint only those parts (rects) that you actually need to repaint. For example if you change the component bounds inside any container the best choice is either to repaint its old bounds rect and new bounds rect OR repaint rect that contains both of those bounds, but not the whole container to avoid repainting uninvolved in the action components.
So, basically in your case after some changes with panels you should call revalidate on their container (or invalidate) followed by repaint (in case revalidate leaves some visual artefacts) again for the container.
Guess i didn't miss anything and i hope that now you know the basic meaning of those methods.
revalidate at the end of your update method like so .
updatePanel(int para){
.....
.....
this.revalidate(); //of course this refer to the panel
parent.revalidate(); // parent refer to the window
}

What is the data type from the source of an image

another flashbuilder brainbreaker for me...
I have a class with a contstructor that should only change the source of an image.
[Bindable]
[Embed(source='../pictures/test.jpg')]
private var _picture:Class;
public function Test(newSource:*****)
{
_picture.source = newSource;
}
(the image is not an image, but a class, I am aware of this, it is meant to be so :-) )
The problem is that when I call the constructor, let's say:
var test:Test = new Test(pictureAtStage.source);
Flashbuilder will give an error, becouse I can't tell the compiler what data type "newSource" at the constructor will have...
*edit:
When i use _picture.source, the embedded source does not seem to be changed...?
Anyone knows an answer?
Are we talking about mx.controls.Image? if so, then the source of an image can be: a Class, a Bitmap (not a BitmapData), a String (in which case it is assumed that you wanted to load it instead of using an embedded one). If you want to find a common denominator for all these, then Object is that class, however, I would rather limit it to something particular to your use case.
However, if I may advise anything... don't use mx.controls.Image, it's too bloated, even for Flex framework. If it must be a UIComponent - extend UIComponent and let the source be of type BitmapData - this way you will be able to manage resources better - you could reuse the same actual image for example. You could then use graphics property of the control to display the image.
Another advise, if you are still here :) Don't use [Bindable], especially the short version of it, especially not on a private variable - you will save yourself the frustration of countless hours of debugging it... Besides, in your case you aren't going to change the value of that variable anyway...
Are you still here? Well, don't use [Embed] on variables, use it on class definition - slightly more work for you, but this will, potentially, make your code more portable. If you embed on class the compiler will not generate a silly "something-something-Asset" class, it will use Bitmap or BitmapData - whichever your class extends. Thus, you will not introduce a dependency on Flex framework, and, in general, you will have more control over your code.
EDIT: the above was written assuming that _picture (class) variable and _picture (some variable used in a function) are not the same thing. But if they are the same thing, then Class class is dynamic, which means that you can add to it properties at runtime (don't know why, it's a design decision by Adobe...), however, the compiler will act as if it's not possible, so you would work around that by adding the property through reflection:
var _picture:Class = Sprite;
_picture["source"] = whatever;
trace(Sprite["source"]);
This is indeed slightly confusing, It will be of the type BitmapAsset which extends Bitmap. So any of those will work.
Since I'm very new to flashbuilder I didn't see the obvious solutions...
The solution for the first part of my question (before the edit):
Setting the data type to Object did the trick:
[Bindable]
[Embed(source='../pictures/test.jpg')]
private var _picture:Class;
public function Test(newSource:Object)
{
_pucture.source = newSource;
}

How to add RichEditableText of TextArea using only ActionScript

My head is spinning from two days of trying to find an answer to this seemingly simple question.
I'm developing a Flex/AIR application built entirely in ActionScript -- there's no MXML beyond what was originally auto-created.
I need to dynamically generate some kind of editable text-field with high control over formatting. The TLF text fields all seem great, except that I can't get any of them to render on the screen. Due to the nature of the application, they have to be inside a MovieClip, but since I've read that everything must be a descendant of UIComponent, I use UIMovieClip, which is AddChild'ed to the stage.
I'm about to go crazy here, the whole application is in jeopardy over this. I CAN NOT use MXML, and all the 10,000 examples on the internet are MXML. I need to generate these dynamically. I need to generate upwards of 50 fields under one movieclip based on database data. There's no way to hardcode that with MXML. Please don't suggest to change this. The GUI is very specific about this, and it's the right GUI.
In two days of searching, I can't find a single example in ActionScript, only MXML. I've tried everything that smelled like an example.
Is there some obvious general pointer I'm missing? I'll be happy to post code, but it doesn't make sense because I've been through so many examples.
Does anyone have the simplest possible code for creating any kind of TLF text editing field in ActionScript only (zero MXML), which is then added to a MovieClip or UIMovieClip, which is added to the stage of a desktop AIR application?
I will greatly cherish any help here.
Best,
Per
This should get you started:
//create your TextFlow component
var textFlow:TextFlow = new TextFlow();
var p:ParagraphElement = new ParagraphElement();
var span:SpanElement = new SpanElement();
span.text = "hello world";
p.addChild(span);
textFlow.addChild(p);
//create a Sprite that will contain the text
var textBlock:Sprite = new Sprite();
//create a controller for compositing
var controller:ContainerController = new ContainerController(textBlock);
//set the size of the composition
controller.setCompositionSize(100, 200);
//make the controller control the TextFlow object
textFlow.flowComposer.addController(controller);
//update the composition
textFlow.flowComposer.updateAllControllers();
//add to the stage
addChild(textBlock);
About the size: it is important you use setCompositionSize() instead of the Sprite's width and height properties.
Using addController() you could spread the text over several Sprites. Each Sprite would have its own ContainerController, but all would share the same FlowComposer which would calculate the composition.
warning : using TLF like this can be pretty complicated. Above code is the bare minimum to get things running. I do not know your requirements, but you'll probably hit a few other roadblocks along the way. You have to ask yourself this question: are you really willing to drop all the built-in features of TextArea? It might cost you months of development to get things right, depending on the requirements. You still may want to reconsider your architecture...