Actionscript 3 - How To Check A Random Pixel Of A Sprite - actionscript-3

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()

Related

AS3 : How do I clear graphics in a specific pixel/area

I know that you use graphics.clear to clear all the graphics but that clears the graphics from the stage, I would like to clear graphics in a specific pixel(s) or between x-y value how do I do that?
There's no way to do that with graphics. I just tried, drawing transparent shapes does not create holes, alas.
You should convert the graphics you have into Bitmap instance and work with pixels:
package
{
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
public class Holey extends Sprite
{
public function Holey()
{
super();
// Lets create some example graphics.
graphics.beginFill(0x990000);
graphics.drawCircle(200, 200, 100);
graphics.endFill();
// Convert into raster and make 1 pixel transparent.
var aBit:Bitmap = rasterize(this);
aBit.bitmapData.setPixel32(50, 50, 0x00000000);
graphics.clear();
addChild(aBit);
}
private function rasterize(source:DisplayObject):Bitmap
{
// Obtain bounds of the graphics.
var aBounds:Rectangle = source.getBounds(source);
// Create raster of appropriate size.
var aRaster:BitmapData = new BitmapData(aBounds.width, aBounds.height, true, 0x00000000);
// Make an offset to capture all the graphics.
var aMatrix:Matrix = new Matrix;
aMatrix.translate(-aBounds.left, -aBounds.top);
aRaster.draw(source, aMatrix);
return new Bitmap(aRaster);
}
}
}
The way to do this would be with a mask. Using an alpha mask (both mask and maskee use cacheAsBitmap=true) you can draw transparent pixels onto the mask to erase parts. The basic approach would be:
Put all your graphics that you want to be effected by the mask in a common container (if you mean for everything to be cut, then they are already in a common container: the stage or root timeline.)
Draw a bitmap data object that has a transparent "hole" in the area you want to erase. For example:
// fill the stage with a solid rectangle
var maskBitmapData:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0xff000000);
// erase part of it by drawing transparent pixels
maskBitmapData.fillRect(new Rectangle(20, 20, 200, 100), 0);
// create the mask object
var maskBitmap:Bitmap = new Bitmap(maskBitmapData);
maskBitmap.cacheAsBitmap = true; // this makes the mask an alpha mask
addChild(maskBitmap);
Set the container's .mask property. For example, to mask the entire main timeline:
root.cacheAsBitmap = true; // this makes the mask an alpha mask
root.mask = maskBitmap;
Open stack overflow to answer some questions, think for next hour about how holes are placed in cheese... :)
You could also set blendMode property of your hole object to BlendMode.ERASE in combination with cacheAsBitmap. This works similar to masks except you would be actually drawing the wholes and not the area outside them.
Here is an example:
//make cheese
var cheese:Sprite = new Sprite();
cheese.cacheAsBitmap = true;
stage.addChild(cheese);
cheese.x = cheese.y = 10;
//define holes
var holes:Shape = new Shape();
holes.blendMode = BlendMode.ERASE;
cheese.addChild(holes);
//draw cheese
var g = cheese.graphics;
g.beginFill(0xFFCC00);
g.drawRect(0,0,200,150);
//**Attack chees with mices.
g = holes.graphics;
for (var i:int = 0; i < 10; i++){
g.beginFill(0xFF00FF);
var hx = Math.random()*(cheese.width-7)+7;
var hy = Math.random()*(cheese.height-7)+7;
var s = Math.random()*15;
g.drawCircle(hx, hy, s);
g.endFill();
}
Result would be something like that:
edit:
Turns out that you don't need to use cacheAsBitmap if you set blend mode of parent object to LAYER (doc says it should be set automatically...)
So you can use cheese.blendMode = BlendMode.LAYER; instead of cheese.cacheAsBitmap = true;. And if I remember correctly, masks also don't require cahceAsBitmap, even with NORMAL blending mode.

Drawing a bitmap based on a transformed movieclip

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)

AS3 resizing bitmapData loosing alpha channel after draw()

I'm resizing a bitmapData the usual way, using a Matrix. The bitmapData has an alpha channel (it comes from a PNG), and the alpha channel is ignored...
var m:Matrix = new Matrix();
m.scale(.5, .5);
var bmp:BitmapData = new BitmapData(bitmapData.width * .5, bitmapData.height * .5,true);
bmp.draw(bitmapData,m);
var resizedBitmap = new Bitmap(bmp);
I've added the third parameter true to the BitmapData() constructor to support alpha channel, but I'm still loosing all the transparency after the draw() call.
What's wrong?
The solution to this problem comes from adding the fourth parameter (fillColor) to the BitmapData constructor.
var bmp:BitmapData = new BitmapData(bitmapData.width * .5, bitmapData.height * .5,true,0x00000000);
From the documentation:
To create a fully transparent bitmap, set the value of the transparent parameter to true and the value of the fillColor parameter to 0x00000000 (or to 0).

drawing a bitmap with bitmapdata(with matrix) in as3

I want to draw my stage as a new bitmap.
How can I cut the top bar of the stage (height of my top bar is 100 pixels) and draw it as a new bitmap?
Well you could do this by adding everything you want in the bitmap to a sprite and then you do this:
var stageSprite:Sprite = new Sprite();
addChild(stageSprite);
//Creates the sprite you want to draw
stageSprite.addChild(objectsYouWantToDraw);
//Here you add the objects you want to draw to the sprite
var bmd:BitmapData = new BitmapData(stage.stageWidth, 100, true, 0);
var bit:Bitmap = new Bitmap(bmd);
addChild(bit);
//Create a bitmap with your size
bmd.draw(stageSprite);
//Draw the objects to a bitmap
You could optionally add a matrix if you want to get another portion of the screen.
var m:Matrix = new Matrix();
m.translate(-xOffset, -yOffset);
bmd.draw(stageSprite, m);
//Draw the objects to a bitmap with the offsets you want

change the registration point when using Bitmapdata.draw?

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/