How to convert PNG image to Array? - actionscript-3

I'm trying to make a tile-based AS3 game that uses PNG images as the base for maps that loads them from the library and converts the data to an array with each pixel of data being an individual tile. Essentially, if I had a 128x128 pixel PNG with say, green pixels being converted to "GRASS" in my array, I could then cycle through the array and add tiles to the map movieclip accordingly.
I've looked at the ByteArray class and I can't seem to decode the data into a usable format. If anyone has a solution to do this, please let me know.

The BitmapData class seems like what you are looking for. Make sure the images in your library have there own class name, and that it's base class is Bitmap (in properties), then create an instance of the image, and loop through its bitmap pixel data using getPixel.
Something like this:
var image:Bitmap = new MyBMP();
var bmd:BitmapData = image.bitmapData;
for(var y:int=0; y < bmd.height; ++y)
{
for(var x:int=0; x < bmd.width; ++x)
{
var pixelValue:uint = bmd.getPixel(x, y);
trace(pixelValue.toString(16));
// Test if the pixelValue matches the colour you want.
}
}
Just a note, make sure to use getPixel32 if you are use alpha channel.

Related

How to detect if the area was 100% painted in as3

I´m making a game that simulates an industry of pan, and one of the process is Painting.
What I want to do is to let the player paint the pan, but i don´t want it to be easy using FILL, i want that the player paint the pan with an brush and then the game detects if all the area was painted and let the player advance.
For the painting i intend to use that library: http://www.nocircleno.com/graffiti/
But i have no idea how to detect if all the area was painted. Can someone show me some way of doing that?
One of the ways would be - you make a shielding BitmapData that has transparency and is opaque in place which you need your player to paint. (Color it as needed, but make sure the color is fully opaque). Then gather histogram() then query alpha vector for 255th value, this will be the initial value for zero percent filled. These range from 0-255, so you can't use 100 or any other fixed value. Then, while the player is painting, you draw the brush over that BitmapData with blendMode parameter set to BlendMode.ERASE, this will net your BitmapData to gain transparency where the brush was drawn. After your player finishes drawing by any means (say, the paint is used up), you run another histogram() over the BitmapData, and query the 255th value of alpha channel vector. 0 means the bitmap is fully transparent (or at least, only a small amount of pixels is left opaque), thus you can count a zero as 100% fill, for anything greater use the proportion.
var bd:BitmapData=new BitmapData(w,h,true,0x0); // fully transparent initial bitmap
bd.draw(yourPaintBase); // a shape that designates area to be painted. Must be fully opaque
var bm:Bitmap=new Bitmap(bd);
// position it as needed, so the area which should be painted is aligned to wherever you need
addChild(bm);
addEventListener(Event.ENTER_FRAME,doPaint);
var baseValue:int=bd.histogram()[3][255]; // Vector #3 contains alpha, #255 contains
// percentage of those pixels that have alpha of 255 = fully opaque
function doPaint(e:Event):void {
if (!areWePainting) return;
var sh:Shape=getBrush(); // shuold return an existing Shape object reference for performance
sh.x=e.localX;
sh.y=e.localY; // we are drawing where the mouse is
bd.draw(sh,null,null,BlendMode.ERASE);
decreasePaint(); // we have used some paint
if (noMorePaint()) {
e.target.removeEventListener(Event.ENTER_FRAME,doPaint);
var endValue:int=Math.floor(100*(1-bd.histogram()[3][255]/baseValue));
// aligning to percentage. This is the value you seek
reportFilledPercentage(endValue);
}
}
You can iterate over the pixels on your BitmapData and use getPixel() to check if the color of all those pixels is not white. If a white one is found, the image is not fully painted.
Something like this:
function containsWhite(bitmapData:BitmapData):Boolean
{
for(var c:int = 0; c < bitmapData.width; c++)
{
for(var r:int = 0; r < bitmapData.height; r++)
{
// Check if pixel is white.
if(bitmapData.getPixel(c, r) >= 0xFFFFFF)
{
return true;
}
}
}
return false;
}
Your essentially dealing with a collision detection problem. From looking at their API you could try something like a for loop with getColorAtPoint and try to determine they have drawn at each pixel.
If all else fails look into collision between the objects the library generates using the .hitTestObject method of an object.
See this: http://sierakowski.eu/list-of-tips/39-collision-detection-methods-hittest-and-hittestobject-alternatives.html
And this to see how someone handles collision with pixels: http://www.emanueleferonato.com/2010/08/05/worms-like-destructible-terrain-in-flash-part-2/

Is there any way to reference an subobject's x position against it's x position on the stage?

I'm currently working on an actionscript game, and am trying to set stage boundaries; however, the player object is a subobject of a stage object; and when referencing player.x, I'm getting it's x position within the level object itself. In essence, what I'm trying to do is;
if (player.x < stage.x.0) {
player.x = stage.x.0
}
Is there any easy way to do this, or should I simply make sure the player object is always on the stage, rather than as a subobject?
You can use the localToGlobal() method to convert a Point (flash.geom.Point) from one object's coordinates to stage coordinates. Either by asking subobject to convert the player's location:
var playerPosition:Point = new Point(subobject.player.x, subobject.player.y);
var playerPositionOnStage:Point = subobject.localToGlobal(playerPosition);
Or, because a new Point is at 0, 0 by default, by asking the player object itself to convert that to global coordinates:
var playerPositionOnStage:Point = subobject.player.localToGlobal(new Point());

How can I resize bitmap data without having to edit the transform matrix and maintain good quality

I am trying to resize a bitmap for a project we are working on at work in as 3.0. Basically we have a bunch of sprites that get drawn on a bitmapData and then are stored in a vector. The data in the vector eventually gets stored in a bitmap object. Now I want to make the BitmapData sprites smaller but don't want to have to update 100 matrix to do it. Is there another way?
I had some success by scaling the bitmap that gets displayed but the image is a bit jagged looking and the models don't turn around just moon walk.
I have also tired Matrix.a = 0.4 and matrix.d = 0.4 but that did nothing.
When I did bitmap.scalex = 0.7 and the same for scaleY it made it smaller but now they are in the air as the x and y aren't right and the code for them to go in reverse was just doing scalX *= -1 which now doesn't seem to work either. Also I figured out how to get them out of the air but they are as said before jagged and moon walking. Please help as I am attempting to fix code that was written before I got here.
Bascially here is some code, I got approval from the CEO:
we have this:
var b:BitmapData = new BitmapData(CustomerRenderer.BLIT_WIDTH,
CustomerRenderer.BLIT_HEIGHT, true, 0x00000000);
for(var i:int=0; i<WRAPPER.numChildren; i++)
{
b.draw(Sprite(WRAPPER.getChildAt(i)),
WRAPPER.getChildAt(i).transform.matrix, null, null, b.rect, true);
}
_spriteSheet[_currentFrame] = b;
Then we use that data in
BAKED_BITMAP.bitmapData = _spriteSheet[_currentFrame];
to display it where BAKED_BITMAP is a Bitmap
then to flip all the person was doing was:
BAKED_BITMAP.scaleX *= -1;
BAKED_BITMAP.x = (BAKED_BITMAP.scaleX >= 0) ? 0 : BLIT_WIDTH;
thanks
You can try setting the smoothing property of the Bitmap object to see if it gives you the desired effect.

AS3: How can I construct this Linkage problem?

I want to do something like this with AS3, but I'm new to AS3 and I'm not sure how to go about the coding.
What I need to do is I have 1 x blank MC called all_mc, inside that I need to have 200 x empty_mc all lined up one after another on the x axis.
Each empty_mc is 100px wide and load from a Linkage in the library called panelClass (which is a MovieClip).
The empty_mc itself is called emptyClass in the library.
I need the all_mc to display on the stage from start. It should look like this image. The I need 200 of these red squares.
I know instead of adding all 200 MCs manually, I should be making a loop? But I can not get my head around it for the life of me. Can someone please kindly help me out?
Just make a loop and dynamically create your MovieClips:
var mcWidth:Number = 100; // Using hardcoded value because MovieClip.width is not always reliable (if the MovieClip contains shapes with strokes, etc.)
for (var i:int = 0; i < 200; i++) {
var mc:panelClass = new panelClass();
all_mc.addChild(mc);
mc.name = "empty_mc" + i; // set a name so that it can be accessed later on
mc.x = mcWidth * i;
}

Bitmap conversion - Creating a transparent + black image from a B&W source

I have a whole bunch of jpg files that I need to use in a project, that for one reason or another cannot be altered. Each file is similar (handwriting), black pen on white BG. However I need to use these assets against a non-white background in my flash project, so I'm trying to do some client-side processing to get rid of the backgrounds using getPixel and setPixel32.
The code I am currently using currently uses a linear comparison, and while it works, the results are less than expected, as the shades of grey are getting lost in the mix. Moreso than just tweaking my parameters to get things looking proper, I get the feeling that my method for computing the RGBa value is weak.
Can anyone recommend a better solution than what I'm using below? Much appreciated!
private function transparify(data:BitmapData) : Bitmap {
// Create a new BitmapData with transparency to return
var newData:BitmapData = new BitmapData(data.width, data.height, true);
var orig_color:uint;
var alpha:Number;
var percent:Number;
// Iterate through each pixel using nested for loop
for(var x:int = 0; x < data.width; x++){
for (var y:int = 0; y < data.height; y++){
orig_color = data.getPixel(x,y);
// percent is the opacity percentage, white should be 0,
// black would be 1, greys somewhere in the middle
percent = (0xFFFFFF - orig_color)/0xFFFFFF;
// To get the alpha value, I multiply 256 possible values by
// my percentage, which gets multiplied by 0xFFFFFF to fit in the right
// value for the alpha channel
alpha = Math.round(( percent )*256)*0xFFFFFF;
// Adding the alpha value to the original color should give me the same
// color with an alpha channel added
var newCol = orig_color+alpha;
newData.setPixel32(x,y,newCol);
}
}
var newImg:Bitmap = new Bitmap(newData);
return newImg;
}
Since it's a white background, blendMode may give you a better result.