Archive

Archive for November, 2013

Pixel Manipulation With AS3

November 21, 2013 Leave a comment

A bit of code that I developing for creating my level select screen involves manipulating individual pixels from an image. Here’s what my level select screen looks like right now.

Level Selection

To properly explain how I came up with these images, I should explain how I store my maps. I have a standard map sprite sheet that I use for all the levels. Each level map is stored as an array of tiles, with each tile being identified by that tile’s image position on my sprite sheet. Here’s what that sprite sheet looks like.

mapTileSheet

So what I wanted to do was come up with a color for each tile on the sprite sheet and just use that one color to represent that on the mini-map. I didn’t want to have to recalculate this color every time I changed the sprite sheet, so I created some code to average the RGB values of each sprite. Here’s the code I used to do that.

var tempBitmap:Bitmap = new LevelRegistry.Img_Map1();

for (var y:int = 0; y < tempBitmap.height; y += BaseLevel.yWidth) {
   for (var x:int = 0; x < tempBitmap.width; x += BaseLevel.xWidth) {
      var rValue:Number = 0;
      var gValue:Number = 0;
      var bValue:Number = 0;
      
      for (var altX:int = 0; altX < BaseLevel.xWidth; altX++) {
         for (var altY:int = 0; altY > 16 & 255;
            var tempPixel = tempBitmap.bitmapData.getPixel(x + altX, y + altY);
            rValue += tempPixel >> 16 & 255;
            gValue += tempPixel >> 8 & 255;
            bValue += tempPixel >> 0 & 255;
         }
      }
      
      var pixelCount:int = BaseLevel.xWidth * BaseLevel.yWidth;
      var newR:uint = uint(rValue / pixelCount) * 0x10000;
      var newG:uint = uint(gValue / pixelCount) * 0x100;
      var newB:uint = uint(bValue / pixelCount) * 0x1;
      var newColor:uint = 0xff000000 + newR + newG + newB;
      this.averageMapColorArray.push(newColor);
   }
}

So this starts with the upper-left corner of each sprite and then separately totals the R, G and B values. The >> operator is the right shift operator that shifts pixel’s RGB values by 16, 8 or 0 bits. Then the & is a bit-wise “and” operator. Doing an “& 255” gives us only the first 8 bits, which is the total length of individual RGB values in AS3. Then we average the RGB values and add them back together along with 0xff000000 which is a solid alpha channel in flixel. The last step after this is just to read the tile map data and create a new mini-map image for each level.

var output:Bitmap;

for ( var i:int = 1; i <= LevelRegistry.levelCount; i++) {
   if(LevelRegistry["CSV_Map".concat(i)]) {
      var tempMap:String = new LevelRegistry["CSV_Map".concat(i)];
      var rowArray:Array = tempMap.split("\n");
      output = new Bitmap(new BitmapData(rowArray[0].split(",").length * 3
             + 2 (rowArray.length - 1) * 3 + 2, true, 0xff000000));
      for (var rowNum:int = 0; rowNum < (rowArray.length - 1); rowNum++) {
         var pixelArray:Array = rowArray[rowNum].split(",");
         for (var colNum:int = 0; colNum < pixelArray.length; colNum++) {
            var currentColor:uint = averageMapColorArray[pixelArray[colNum]];
            var colorArray:BitmapData = 
                  new BitmapData(3, 3, true, currentColor);
            output.bitmapData.copyPixels(colorArray, new Rectangle(0, 0, 3, 3), 
                  new Point(colNum * 3 + 1, rowNum * 3 + 1));
         }
      }
      j = (i - ((i - 1) % 5) - 1) / 5;
      var tempButton:BitmapButton = new BitmapButton(40 + ((i - 1) % 5) * 70, 
            100 + j * 70, 0xff000000, output, this.startGame, i);
      add(tempButton);
   }
}

One thing to note in this is “LevelRegistry[“CSV_Map”.concat(i)]”. LevelRegistry is my class that stores all the references to level maps, enemy lists, enemy paths, level counts, etc. Calling “ClassName[variableName]” returns a reference to the static variable in ClassName that is named variableName. It’s a nice way to programmatically cycle through a list of static variable names. This way I can add or remove levels to LevelRegistry without having to reprogram the rest of the game.

Advertisements