AS3 3D-Renders slowly - actionscript-3

Good time.
As you know,3d shapes in as3 are flat surfaces and we can make polyhedrons by moving and rotating that flat surfaces in the three dimensions.
BUT......
what about Non-Polyhedra shapes(spheres,cylinders)??
One way is to make surfaces using flat shapes.
An example to make a cylinder; you can copy this code to see what happens:
import flash.display.Sprite;
const angle:Number=Math.PI/180;
var numOfSides:uint=200;
//number of sides around
var pixWidth:uint=4;
//width and height of sides
var cldHeight:uint=20;
//height of cylinder
var s:Sprite=new Sprite();
s.graphics.beginFill(0xffffff*Math.random());
s.graphics.drawRect(0,0,pixWidth,pixWidth);
addChild(s);
this.cacheAsBitmap=true;
for(var n:uint=1;n<cldHeight;n++){
for(var i:uint=1;i<numOfSides;i++){
var prevS:Sprite=s;
s=new Sprite();
s.graphics.beginFill(0xffffff*Math.random());
s.graphics.drawRect(0,0,pixWidth,pixWidth);
s.x= prevS.x + Math.cos(-prevS.rotationY*angle)*s.width;
s.y=n*pixWidth;
s.z=prevS.z+Math.sin(-prevS.rotationY*angle)*s.width;
s.rotationY=-i*(360/numOfSides);
s.cacheAsBitmap=true;
addChild(s);
}
s=new Sprite();
}
and my problems:
Flash now renders EXTREMELY slow :-(
please improve this code or suggest a better one.

A few minor notes on the code:
Don't forget to end the fill when you're done(e.g. s.graphics.endFill() after the drawRect() call)
cacheAsBitmap works well for display objects without rotation applied if I can remember
4000 (200*20) Sprites with 3D transformations applied might push the display list a bit.
Remember to also sort the sprites
I recommend checking out these resources:
Flash & Math blog Icosahedron 3D tutorial
Senocular's exhaustive FP10 Drawing API article (using drawTriangles() would be more efficient since you'll have a single Sprite on the display list)
If you want to draw the vertices, it should be pretty fast to draw the 3D points projected to 2D on a bitmap
All of the above use Flash Player 10's features, but it might be much simpler to use a 3D API like Away3D which already provides easy ways to draw cylinders (with textures) at very high speeds(especially newer versions that use hardware acceleration)

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.

ActionScript3: How to make an animation out of a series of images?

I'm new to AS3 and I'm trying to create a simple game with it.
So far, I have been able to draw images like this:
[Embed(source = 'C:/mypath/myimage.png')]
public static var myImageClass:Class;
private var myImage:Bitmap = new myImageClass();
and then render myImage.
but that draws only a picture with no animation.
What I want is to import this picture:
and then cut the image to series of subimages and draw an animation out of them, rather than a single image. How may I do this?
Thanks!
This is called "Blitting". You could accomplish it with fairly decent results, depending on your deployment target and how many animations you require, using BitmapData.copyPixels(), but it's more ideal to use the Starling Framework, which employs Stage3D hardware acceleration.
More here:
Introducing the Starling Framework (Video tutorial)
Starling documentation
What you are looking for is SpriteSheet support. You can easily write this yourself or use existing libraries (like Starling for instance).
The idea is to draw an area of the image at each frame to actually create the animation. Depending on the format of your sprite sheet, you may have to add another file to describe the positions of each rectangle to draw.
This page explains how to implement it.

Spritesheet with mask or separate image files?

I'm making an animation of a 2D character that can walk, run, jump, bend,...
Would it be better to load one big 'spritesheet' with all the animations and just use a mask, or would loading separate files (walk, run,...) be better because you're not using a mask on such a big image every frame?
I'm not using the Stage3D features with a framework like Starling because I think the normal flash display API is fast enough and has much less bugs than the relatively new GPU frameworks.
Blitting just the character (using lock(),copyPixels(),unlock()) works pretty well.
private function updatePixels():void{
//update sprite sheet copy position based on the frame placements ons prite sheet
position.x = spriteSourceData[currentFrame].x + offset.x;
position.y = spriteSourceData[currentFrame].y + offset.y;
//draw into the bitmap displayed
displayData.lock();
displayData.fillRect(displayData.rect, 0x00FFFFFF);//clear
displayData.copyPixels(sourceData, spriteData[currentFrame], position);//copy new frame pixels
displayData.unlock();
}
//a bit about vars:
position:Point
spriteSourceData:Vector.<Rectangle> - from parsed Texture Packer data
offset:Point - front view and side view animations weren't always centred, so an offset was needed
displayData:BitmapData - pluging into a Bitmap object displayed
sourceData:BitmapData - the large sprite sheet
currentFrame:int - image index on the sprite sheet
I've done this on an older project writing a custom class loosely following what I've learned from Lee Brimelow's tutorial series Sprite Sheets and Blitting (Part 1,Part 2, Part 3)
In short, you'd use two BitmapData objects:
a large sprite sheet
a small image to display just the character (size of the largest character bounding box) to copy pixels into
In my project I had a character with front and side animations and for the sides I've used one set of animations and used the Matrix class to flip(scale and translate) the side animation accordingly. I've used TexturePacker to export the image sequence as a sprite sheet and the frame data as well as a JSON object. There is native JSON support now, so that's handy. Texture Packer isn't free but it's really worth the money (affordable, fast and does the job perfectly). I haven't used Flash CS6 yet but I imagine it's also possible to import your image sequence and export a spritesheet with the new feature.
In my experience the rule "the simpler the display list the better the performance" generally applies. Which means you should use the most specific display object that will do the job (don't use a Sprite when a Shape would be sufficient or favor Bitmaps over vectors where it makes sense).
The most extreme version of this is to only have one Bitmap display object on the stage and use copyPixels to draw all game objects into it every time you want to update the screen. It doesn't really matter what the source in the copyPixel call is, it could either be a large BitmapData acting as a sprite sheet or a small BitmapData objects representing a single frame in an animation. This method is really fast and you could easily have many hundreds of objects on screen at the same time. But using copyPixels means you can't scale or rotate a game object, so for those cases you would have to fall back to the much slower draw() method. Of course this single Bitmap method is not suitable for games where you need to attach mouse events to specfic objects in the game, but works well for shoot'em ups or platform games.
To answer your question, I think you will get better performance by using a single Bitmap display object to represent the player and a collection of BitmapData objects for all the animation frames. Then you can just change the Bitmap's bitmapData property to the frame you want to display. You can still load a large spritesheet png and then plit it up into a series of BitmapData objects during the initialization of the game.

AS3 Is it possible to duplicate a Shape object?

I'm trying to make a shape available for duplicating. Here's an explanation of what I've done, what I'm trying to do, and where I'm stuck:
Drew a shape manually in the Flash IDE (paintbrush).
Created a new movieclip containing the shape; exports as a class.
Instantiate the class (var mc:MovieClip = new shapeMovieClip()).
Add a reference to the shape in mc that I want (var myShape:Shape = mc.getChildAt(0) as Shape;
This works perfect and I now have my shape, but how can I duplicate it without instantiating the parent MovieClip class - is it possible?
I've tried creating a new shape and using the copyFrom() graphics method with no avail, I believe this method just copies draw calls when they're made on the referenced graphics and instead I just have a reference of a shape that's already been drawn.
Right now I'm extending the movieclip as a sprite instead, instantiating, pulling the shape from the parent and saving its reference, and then nulling the sprite. Does anyone know of a better, more lightweight, strategy for duplicating Shapes in this manner?
Basically depends on whether you need to scale your shapes. If you don't, and you can work it out with a fixed sized bitmap representation of the shape, then you will get much better performance drawing your shape to a BitmapData (it's called rasterisation) and instanciating Bitmap objects (as other commenters have pointed out). The code would go something like this:
var base:Sprite = new shapeMovieClip();
var bmd:BitmapData = new BitmapData(base.width, base.height, true, 0);
bmd.draw(base);
var clip1:Bitmap = new Bitmap(bmd);
var clip2:Bitmap = new Bitmap(bmd);
If you do need to scale the clips, you will get pixelation using bitmaps. When scaling down Bitmap.smoothing can help to some extent (also when rotating), but if you need to scale up, you will probably have to use some kind of mip-mapping. This is basically creating a few bitmaps of the shape at different scale levels, and then swap them depending on the current scale. Coding this has some complexity (using a helper parent to adjust the scale can help) but it will definitely perform better than using many shape symbols (with or without a sprite parent).
This is very old, but it still comes up high in Google, so I just wanted to share a true shape duplicating method:
var shapeonstage:Shape = shapeMadeInIDE;
var g:Vector.<IGraphicsData> = shapeonstage.graphics.readGraphicsData();
var shapecopy:Shape = new Shape();
shapecopy.graphics.drawGraphicsData(g)
And boom. It works. Had to share this because it would have helped me a looooong time ago and in so many ways.
UPDATE:
There is some clarification I'd like to add why you would want to use this method, for duplicating AND for storing references to Shapes that are within an swf.
If you target a Shape object on the stage or in a movie clip, the Flash Rendering engine does something strange. It will RECYCLE Shape objects to render new graphics thus making your Shape reference point to a COMPLETELY different rendering.
For example:
Create an fla with a movieclip.
Inside the movie clip make 10 frames.
On each frame, draw a different shape
In your code, get a reference to the shape (The Shape on Frame 1)
Draw and verify your shape (draw to a bitmap then put the bmp on stage)
Now let the flash engine play for 5 frames
Draw and verify your shape again
The second time you draw your shape without EVER reassigning your shape reference, will SOMETIMES yield a completely different shape.
Just know, this little quirk can leave you pulling your hair out if you don't know what you're looking for :)

Actionscript 3 pixel perfect collision. How to? (learning purposes)

I know that there are people out there creating classes for this (ie http://coreyoneil.com/portfolio/index.php?project=5). But I want to learn how to do it myself so I can create everything I need the way I need.
I've read about BitMap and BitMapData. I should be able to .draw the MovieClips onto a BitMap so I could then cycle the pixels looking for the collisions. However, It's weird and confusing dealing with the offsets.. And it seams like the MyBitMap.rect has always x = 0 and y = 0... and I can't seam to find the original position of the things...
I'm thinking of doing a hitTestObject first, then if this was positive, I would investigate the intersection betwen the movieclips rectangles for the pixel collisions.
But then there is also another problem (the rotation of movieclips)...
...I need some enlightment here on how to do it.
Please, any help would be appreciated..
If you're using BitmapData objects with transparency you can use BitmapData.hitTest(firstPoint:Point, firstAlphaThreshold:uint, secondObject:Object, secondBitmapDataPoint:Point = null, secondAlphaThreshold:uint = 1):Boolean.
You'll have to change from global coords to the local BitmapData coords which will require a bit of math if it is rotated. That's easily achieved (look up affine transform for more info on wiki):
var coordTransform:Matrix = new Matrix();
coordTransform.rotate(rotationRadians);
coordTransform.translate(x, y);
coordTransform.transformPoint(/* your point */);
A classic reference for pixel perfect collision detection in flash is this Grant Skinner's article. It's AS2, but the logic is the same for AS3 (there are ports available if you google a bit).
If I recall correctly, this particular implementation worked as long as both tested objects had the same parent, but that can be fixed.
About BitmapData x and y values, I understand it could be confusing; however, the way it works makes sense to me. A BitmapData is just what the name implies: pixel data. It's not a display object, and cannot be in the display list; so having x or y different than 0 doesn't really make sense, if you think about it. The easiest way to deal with this is probably storing the (x,y) offset of the source object (the display object you have drawn from) and translate it to the global coordinate space so you can compare any objects, no matter what's their position in the display list (using something like var globalPoint:Point = source.parent.localToGlobal(new Point(source.x,source.y)).
I've previously used Troy Gilbert's pixel perfect collision detection class (adapted from Andre Michelle, Grant Skinner and Boulevart) which works really well (handles rotation, different parents, etc.):
http://troygilbert.com/2007/06/pixel-perfect-collision-detection-in-actionscript3/
http://troygilbert.com/2009/08/pixel-perfect-collision-detection-revisited/
and from there he has also linked to this project (which I've not used, but looks really impressive):
http://www.coreyoneil.com/portfolio/index.php?project=5
I managed to do it after all, and I already wrote my class for collision detections,/collisions angle and other extras.
The most confusing process is maybe to align the bitmaps correctly for comparing. When whe draw() a movieclip into a a BitmapData, if we addChild() the corresponding Bitmap we can see that part of it is not visible. it appears to be drawn from the center to right and down only, leaving the top and left parts away from beeing drawn. The solution is giving a transform matrix in the second argument of the draw method that aligns the bitmap and makes it all be drawn.
this is an example of a function in my class to create a bitmap for comparing:
static public function createAlignedBitmap(mc: MovieClip, mc_rect: Rectangle): BitmapData{
var mc_offset: Matrix;
var mc_bmd: BitmapData;
mc_offset = mc.transform.matrix;
mc_offset.tx = mc.x - mc_rect.x;
mc_offset.ty = mc.y - mc_rect.y;
mc_bmd = new BitmapData(mc_rect.width, mc_rect.height, true, 0);
mc_bmd.draw(mc, mc_offset);
return mc_bmd;
}
in order to use it, if you are on the timeline, you do:
className.createAlignedBitmap(myMovieClip, myMovieClip.getBounds(this))
Notice the use of getBounds which return the rectangle in which the movie clip is embedded. This allows the calculation of the offset matrix.
This method is quite similar to the on shown here http://www.mikechambers.com/blog/2009/06/24/using-bitmapdata-hittest-for-collision-detection/
By the ways, if this is an interesting matter for you, check my other question which I'll post in a few moments.