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

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.

Related

Actionscript 3: Drawing lines and bitmaps the right way

I'm just getting started with Flash/ActionScript and it seems to be the general consensus to create Sprites, Bitmaps, MovieClips, etc for various objects in order to represent pictures and other graphics.
However, the way I'm used to writing games and whatnot in other languages is to just loop repeatedly and each frame use something similar to the Graphics object to redraw the scene on the main Sprite. Is this how it's also done in Flash, and is it good practice? I can do it this way, but I'm wondering if there's some Flash ecosystem standard instead.
Here's an example of the way I'm used to:
public class MyApp extends Sprite
{
public function MyApp()
{
var t:Timer = new Timer(20);
t.addEventListener(TimerEvent.TIMER, update);
t.start();
}
public function update(e:TimerEvent)
{
this.graphics.clear();
//Rendering code and updating of objects.
}
}
Is this acceptable?
Well, it depends.
In Flash, you have the option of relying on the Flash Player's vector rasterizer and rendering system, which will figure out all the redrawing for you. For instance, you can draw once to a Sprite then simply apply transforms to the sprite (set x, y, width, height, rotation, scaleX, scaleY, transform.matrix, transform.colorTransform, etc). Any of these objects could be a vector shape or a bitmap, and you can also use cacheAsBitmap and cacheAsBitmapMatrix for even more redraw optimization. The Flash Player will only redraw areas that change, on the frame that they change. I would consider this the traditional "Flash way".
Using the Graphics API is just a programmatic way to create vector shape data. Think of it as a code alternative to drawing in the Flash IDE. You could draw using Graphics once when the object is created, or if you needed to change the actual shape (ie not just the transform) you are correct that you would clear() and redraw it. However, ideally you would not be doing that a lot. If you find yourself redrawing the shape a lot, you might want to move to a pre-rendered sprite-sheet approach. In that case you use BitmapData to more quickly copy pre-drawn pixel data to a Bitmap object. This is generally faster than relying on the vector rasterizer to render your Graphics commands, as long as you use the fast pixel methods like copyPixels(). This is probably closer to the sort of rendering systems you are used to in other platforms that don't have a vector rasterizer built in.
Lastly, it's worth noting that the newest (and fastest) way to render objects in Flash is completely different than all that. It's called Stage3D and it uses a completely different rendering pipeline than the vector rasterizer. It's powered by GPU rendering APIs, so it's blazing fast (great for games) but has no vector rasterizing abilities. It can be used for both 3D and 2D. It's a bit more involved to work with, but there are some useful frameworks to make it easier, most notably the Starling 2D framework.
Hope that helps.
The "Flash way" is to use EnterFrame event instead of using timer to draw. You must make your calculation whenever you want but let flash draw you scene.
It works the same way in actionscript.
public class App extends Sprite // adding "my" to identifier names doesn't add any information, so there's no real point in doing it
{
public function App()
{
addEventListener(Event.ENTER_FRAME, update); // "each frame"
}
private function update(e:Event):void //not just parameters of functions have a type, but also their return value
{
graphics.clear(); // no need for "this" here
//Rendering code and updating of objects.
}
}
Keep in mind that the Graphics API is vector based and as such will only draw so many things before dropping performance.
Sprite is a general purpose container, not to be confused with what the term "sprite" stands for in a sprite sheet.
What you are probably referring to when saying "main Sprite" is some rectangular region of pixels that you can manipulate.In this case, a BitmapData is what you want, which is displayed with a Bitmap object.
BitmapData does not offer a graphics property. Essentially, drawing vectors and manipulating pixels are treated separately in As3. If you want to draw a line in a BitmapData object, you'd have to first draw the line as a vector into a Sprite (or better Shape, if all you want to do is draw on it) using its graphics property, then use draw() of BitmapData to set its pixels according to the drawn line.

How to implement camera without moving anything AS3?

I'm using physInjector and therefore cannot move clips containing my objects: The physical engine works incorrectly because of it.
I think about implementing something like a bitmap drawing a selected part of the stage on itself. How can it be done? I've read this Trying to capture stage area using BitmapData, but there the author copies its data from the stage, whereas I need the area outside it.
Besides, aren't there less resource-consuming solutions?
First, you may want to use a global Sprite to put your clips insde, like :
var a:Sprite = new Sprite();
a.addChild(myClip1);
a.addChild(myClip2);
...
Then, you should be able to move a.
If you don't, and your physic engine rely on Stage to work, you should probably try to fix it, or to understand better how it work so you can move your movieclips.
Redraw a BitmapData every frame will require a lot of CPU ressource, and you won't be able to interact with your clips. That's really not the best way to go.
x=-(player.mc.x-stage.stageWidth/2);
y=-(player.mc.y-stage.stageHeight/2);
if(canvas)
removeChild(canvas);
var bd:BitmapData=new BitmapData(stage.stageWidth,stage.stageHeight,false,0xFFFFFF);
bd.draw(stage);
trace(bd);
canvas=new Bitmap(bd);
addChild(canvas);
x=0;
y=0;
At PC it works fine. Don't know whether it is suitable for mobiles.
I also haven't tested the approach suggested by blue112 because in twitter of physinjector developer there are complaints about ANY moving of parent clip (https://twitter.com/reyco1/status/327107695670853632) and it is quite difficult to combine with my existing architecture.
Changing the globalOffsetX and globalOffsetY properties also didn't help

How do I approach rendering text in a fully sprite based game? (ActionScript 3)

I've created a Canvas class which has an Array of multiple instances of CanvasEntity. Each of these has a skin property which is a reference to a previously created instance of BitmapData, representing some graphics that can be used.
The Canvas runs through this list each frame to perform a render:
lock() the canvas
Clear the canvas using fillRect().
Loop through the aforementioned Array and use copyPixels() on each of the instances' skin properties.
unlock() the canvas.
This is all fine, but now I'm a bit unsure of the best way to approach rendering text in the same fashion.
Do I need to make a sprite sheet with all of my glyphs on it, just like I do for all the frames of any other object? Or is there a simpler way to create a piece of BitmapData that will represent these?
Making a sprite sheets seems painful as there would need to be individual objects representing each glyph to be rendered.
So far I have this as a sprite sheet:
You don't need an individual object for every character. If you want a low-cost text display, have a single class that extends CanvasEntity and accepts a string in the constructor, copies relevant data from the spritesheet to the skin.
The average game doesn't contain that many text. It's generally not a performance critical part that requires to much optimization. You could just create a normal sprite, add a TextField with the text and style you need and copy that graphic to canvas. Maybe chache the text graphics if you need them more often.
If you want some animation (character-by-character-appears-with-annoying-sound-of-typewriter-effect), you probably should go with the sprite sheet. But you can create that dynamically just once, using the same technique. Loop through every possible character of your font, draw it to your sheet.

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...

Extending the Sprite class for convenience?

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.