views:

30

answers:

1

Hello,

I've run into an issue where the BitmapData.draw() method isn't accurately subtracting image data from a .png that uses transparency.

I've put together a test file that shows this behavior, it's located here: http://www.filedropper.com/shield_1

In a nutshell, a sprite drops from the top of the screen and when it intersects with a sprite at the bottom of the screen, the sprite that was dropping takes out a chunk of the sprite at the bottom. I've got all of this working except that when i reset the x and y position of the sprite after its intersected the bottom sprite and it intersects with the bottom sprite again, it doesn't take the same size chunk out of the sprite at the bottom.

I apologize if I'm not explaining this well enough. If you a moment to look at the file I posted it will make sense.

Here's the code which requires two png files within the library with Linkage values of ShieldBase and SnowBall.

package 
{

 import flash.display.Sprite;
 import flash.display.Bitmap;
 import flash.display.BitmapData;
 import flash.display.BlendMode;
 import flash.geom.Point;
 import flash.geom.Matrix;
 import flash.geom.Rectangle;
 import flash.events.Event;

 public class Shield extends Sprite
 {

  public var baseBmpData:BitmapData = new ShieldBase(0,0);
  public var baseBmp:Bitmap = new Bitmap(baseBmpData);
  public var missileBitmapData:BitmapData = new SnowBall(0,0);
  public var missileBitmap:Bitmap = new Bitmap(missileBitmapData);

  public var missileMatrix:Matrix = new Matrix();

  public function Shield()
  {

   baseBmp.y = 300;
   baseBmp.x = 40;
   stage.addChild(baseBmp);

   missileBitmap.x = 85;
   missileBitmap.y = 0;
   stage.addChild(missileBitmap);

   stage.addEventListener(Event.ENTER_FRAME, dropFromSky);

  }

  public function dropFromSky(e:Event)
  {

   for (var i:int=0; i<10; i++)
   {

    if (baseBmpData.hitTest(new Point(baseBmp.x,baseBmp.y),0x00,new Point(missileBitmap.x,missileBitmap.y)))
    {

     missileBitmap.y++;

     missileMatrix = new Matrix();
     missileMatrix.translate(baseBmp.x,baseBmp.y);
     missileMatrix.tx = (missileBitmap.x - baseBmp.x);
     missileMatrix.ty = (missileBitmap.y - baseBmp.y);

     // public function draw(source:IBitmapDrawable, matrix:Matrix = null, colorTransform:flash.geom:ColorTransform = null, blendMode:String = null, clipRect:Rectangle = null, smoothing:Boolean = false):void
     baseBmpData.draw(missileBitmap, missileMatrix, null, BlendMode.ERASE, null, true);

     missileBitmap.x = rand(60, 140);
     missileBitmap.y = 0;
    }
    else
    {
     missileBitmap.y++;
    }

   }

  }

  public function rand(low:Number=0, high:Number=1):Number
  {
   return Math.floor(Math.random() * (1+high-low)) + low;
  }


 }

}

I think the issue is with either the hitTest and/or BitmapData.draw() not working as expected.

many thanks,

devin

A: 

There are two problems.

1) The position that you test for the collision; if you use the center of the ball instead of the top-left then it works properly.

2) The drop shadow on your shield :
What happens is that the pixels on the edge of the shadow that are barely visible are causing the hitTest to succeed; I would suggest you remove the drop shadow from the image and apply it using an actual drop-shadow filter in flash. To get it to work with the drop shadow I changed the alpha threshold in the hitTest to 128 so that the semi-transparent pixels of the drop shadow are ignored. You could leave the threshold at 0 but it looks odd at the beginning when the ball seemingly hits nothing.

Change this:

baseBmpData.hitTest(new Point(baseBmp.x,baseBmp.y),0x00,new Point(missileBitmap.x,missileBitmap.y))

to this:

baseBmpData.hitTest(new Point(baseBmp.x,baseBmp.y),128,new Point(missileBitmap.x+missileBitmap.width*0.5,missileBitmap.y+missileBitmap.height*0.5))
cmann