I have a movieclip on stage that I draw into a bitmap, how do I change the registration point, the code below produces bitmap with half chopped off:
var bitmapData:BitmapData = new BitmapData(mc.width, mc.height, true, 0x00FFFFFF);
var matrix:Matrix = new Matrix();
matrix.translate(0, -mc.height/2);
bitmapData.draw(mc, matrix);
var bitmap = new Bitmap(bitmapData);
addChild(bitmap);
I found this excellent article from Mike Chambers on bitmapData.hitTest and how to check for collisions after transformations have been made to the display objects, all sorted now:
http://www.mikechambers.com/blog/200...ion-detection/
Related
It seems that if a display object has a perspective projection applied to it, calling localToGlobal gives you the wrong coordinates. In the following code, I draw a rectangle, rotate it slightly about its X axis, then draw an oval inside it using coordinates derived from localToGlobal. It works fine, until I try to apply a perspective projection, then the coordinates are all wrong. Anyone know how to get around this problem?
var w:uint = 300, h:uint = 150;
var s:Sprite = new Sprite();
s.graphics.beginFill(0x000000);
s.graphics.drawRect(-w/2,0,w,h);
s.graphics.endFill();
s.x = 275; s.y = 200; s.z = 600;
s.rotationX = -45;
addChild(s);
var point00:Point = new Point(0,0);
var point0h:Point = new Point(0,h);
var midL:Point = new Point(-w/2,h/2);
var midR:Point = new Point(w/2,h/2);
/*var VP:PerspectiveProjection = new PerspectiveProjection();
VP.fieldOfView = 55;
var p:Point = new Point(275,100);
VP.projectionCenter = p;
s.transform.perspectiveProjection = VP;*/
var o:Shape = new Shape();
o.graphics.beginFill(0x00ff00);
o.graphics.drawEllipse(
s.localToGlobal(midL).x,
s.localToGlobal(point00).y,
s.localToGlobal(midR).x - s.localToGlobal(midL).x,
s.localToGlobal(point0h).y - s.localToGlobal(point00).y
);
addChild(o);
It seems that setting perspectiveProjection does not force the player to redraw the object, and localToGlobal depends on redraw for correct results. You can wait 1 tick like you found (setTimeout for 0ms or enterFrame for 1 frame will do it) or you can force the player to redraw using BitmapData/draw():
// ...
s.transform.perspectiveProjection = VP;
new BitmapData(1, 1).draw(s); // forces player to redraw the sprite
var o:Shape = new Shape();
o.graphics.beginFill(0x00ff00);
o.graphics.drawEllipse(
s.localToGlobal(midL).x,
s.localToGlobal(point00).y,
s.localToGlobal(midR).x - s.localToGlobal(midL).x,
s.localToGlobal(point0h).y - s.localToGlobal(point00).y
);
addChild(o);
I found a workaround that isn't terrible. All you have to do is put a slight delay before the localToGlobal calls and then they will return the right coordinates. That also fixes local3DToGlobal.
I have a sprite that is drawn in random and complicated way. Pixels would be either transparent or not. And now I need to check if pixel new Point(10, -5) is transparent or not.
How can I do that ?
This is not for collision detection.
I also draw in the negative area of the sprite graphics. It is not centered.
Solution:
The main problem was the drawing in negative area. I figured it out myself:
var bitmapData: BitmapData = new BitmapData(sprite.width, sprite.height, true, 0x0);
var rect: Rectangle = sprite.getBounds(sprite);
var mat: Matrix = new Matrix();
mat.translate(-rect.left, -rect.top);
bitmapData.draw(sprite, mat);
bitmapData.getPixel32(xCoordToTest - rect.left, yCoordToTest - rect.top);
// etc
Create new BitmapData object and draw your sprite onto it. Then check desired BitmapData pixel.
var bitmapData:BitmapData = new BitmapData(mySprite.width,mySprite.height,true,0x00000000);
bitmapData.draw(mySprite);
bitmapData.getPixel32(10,5);
Just like SzRaPnEL says, draw your sprite into a BitmapData object with the 3rd parameter set to true (enabling transparency).
Then...
var pixelValue:uint = bitmapData.getPixel32(xCoordToTest, yCoordToTest);
var alphaValue:uint = pixelValue >> 24 & 0xFF;
According to the BitmapData online docs, that should work...
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#getPixel32()
I'm drawing bitmaps of movieclips which I then feed into my hittest function to test for collisions. However, I'm not quite sure how i would add to the code below to take into account and draw bitmaps for movieclips which have been scaled and/or rotated. The below code obviously only works for non-transformed movieclips. I've included in comments code which i've already tried but to no success.
When adding the drawn bitmap to the stage, no matter whether the movieclip in question is transformed or not, the drawn bitmap is "cut off" and incorrectly drawn - it appears to only draw a section of it. However, this does not particularly affect the collision testing for the non-transformed movieclips, but has an adverse effect on transformed movieclips.
All of the movieclips I want to be drawn have been created through the graphics property.
//for example:
var mymc:MovieClip = new MovieClip();
var g:Graphics = mymc.graphics;
g.moveTo(0,0);
g.lineTo(17.5,0);
g.lineTo(8.75,17.5);
g.lineTo(-8.75,17.5);
g.lineTo(0,0);
main code:
for each(var mc:MovieClip in impassable) {
//var bMatrix:Matrix = new Matrix();
//bMatrix.scale(mc.scaleX, mc.scaleY);
//bMatrix.rotate(mc.rotation * (Math.PI/180));
var bData:BitmapData = new BitmapData(mc.width, mc.height, true, 0);
//bData.draw(mc, bMatrix);
bData.draw(mc);
var bitmap:Bitmap = new Bitmap(bData);
bitmap.x = mc.x;
bitmap.y = mc.y;
var HitTest:Number = newCollision(bitmap, centerX, centerY, 13.7);
Any thoughts? thanks
This function will create a BitmapData clone of a DisplayObject, taking into account its transform matrix, though it doesn't take into account bitmap filters. (Based on this answer.)
function createBitmapClone(target:DisplayObject):BitmapData {
var targetTransform:Matrix = target.transform.concatenatedMatrix;
var targetGlobalBounds:Rectangle = target.getBounds(target.stage);
var targetGlobalPos:Point = target.localToGlobal(new Point());
// Calculate difference between target origin and top left.
var targetOriginOffset:Point = new Point(targetGlobalPos.x - targetGlobalBounds.left, targetGlobalPos.y - targetGlobalBounds.top);
// Move transform matrix so that top left of target will be at (0, 0).
targetTransform.tx = targetOriginOffset.x;
targetTransform.ty = targetOriginOffset.y;
var cloneData:BitmapData = new BitmapData(targetGlobalBounds.width, targetGlobalBounds.height, true, 0x00000000);
cloneData.draw(target, targetTransform);
return cloneData;
}
When you call successive transforms on a Matrix, the ordering is very important and can really mess things up.
Luckily there is a helper method that allows you to specify translation, rotation and scaling in one go and avoid those issues - createBox
For your case, something like this:
var matrix:Matrix = new Matrix();
matrix.createBox(mc.scaleX, mc.scaleY, mc.rotation*Math.PI/180, 0, 0);
(the two zeros are for x and y translation)
Just a quick question:
which of the following method of create a sprite have quick rendering and less memory usage?
Add bitmap to the sprite
var sprite:Sprite = new Sprite();
var bitmap:Bitmap = new Bitmap();
sprite.addChild(bitmap);
vs
Draw rectangle and fill with bitmapData
var bitmapData:Bitmapdata = new BitmapData(100, 100);
var sprite:Sprite = new Sprite();
sprite.graphic.drawRec(0, 0, 100, 100);
sprite.graphic.beginFillBitmap(bitmapData:Bitmapdata);
sprite.graphic.endFill();
Thanks for any idea.
The first one is faster because vector rendering mathematics are required to fill your shape in the latter.
If you want noticeable (and I mean very noticeable) performance gains, you should have one Bitmap on the stage. What you do from there is store references to BitmapData to represent graphics, and sample those onto your one Bitmap via .copyPixels().
Example:
// This is the only actual DisplayObject that will hit the Stage.
var canvas:Bitmap = new Bitmap();
canvas.bitmapData = new BitmapData(500, 400);
addChild(canvas);
// Create some BitmapData and draw it to the canvas.
var rect:BitmapData = new BitmapData(40, 40, false, 0xFF0000);
canvas.bitmapData.copyPixels(rect, rect.rect, new Point(20, 20));
How do we clone a copy of an "Instance name"? Thanks guys
//The test_close is an instance name which I drew on the canvas.
var cloneMe:MovieClip = new MovieClip();
cloneMe.graphics.copyFrom(test_clone.graphics); //here is my clone codes
addChild(cloneMe);
trace(cloneMe.getBounds(cloneMe));
If you simply need a copy of the object that has been drawn, use the BitmapData draw method.
var bmd:BitmapData = new BitmapData(cloneMe.width , cloneMe.height );
bmd.draw( cloneMe);
var bm:Bitmap = new Bitmap(bmd);
// not relevant, simply shifting the new Bitmap so that it is visible
bm.x = 10;
bm.y = 10;
addChild( bm );