Advertisement
Guest User

PerfectCollisionSprite

a guest
May 11th, 2012
976
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package  
  2. {
  3.     import flash.display.BitmapData;
  4.     import flash.geom.Matrix;
  5.     import org.flixel.FlxRect;
  6.     import org.flixel.FlxState;
  7.     import org.flixel.FlxG;
  8.     import org.flixel.FlxObject;
  9.     import org.flixel.FlxCamera;
  10.     import org.flixel.FlxSprite;
  11.     import org.flixel.plugin.photonstorm.FlxCollision;
  12.     import flash.display.BitmapData;
  13.     import flash.display.Sprite;
  14.     import flash.geom.ColorTransform;
  15.     import flash.geom.Matrix;
  16.     import flash.geom.Point;
  17.     import flash.geom.Rectangle;
  18.     import flash.display.BlendMode;
  19.    
  20.     /* PerfectCollisionSprite
  21.      * This class is an extension of FlxSprite which fills a crucial gap in Flixel's feature-set: you can't do pixel-perfect
  22.      * collision with a rotated sprite.
  23.      */
  24.    
  25.     public class PerfectCollisionSprite extends FlxSprite
  26.     {
  27.        
  28.         public var rotatedFrame:BitmapData;
  29.        
  30.         // The offset between the top-left-hand corner of the bounding box of the rotated frame and the origin.
  31.         // Necessary for collision detection. Stored rather than calculated each time for performance reasons (calls
  32.         // to trig functions and stuff).
  33.         public var dx:Number = 0;
  34.         public var dy:Number = 0;
  35.        
  36.         public function PerfectCollisionSprite(X:int, Y:int)
  37.         {
  38.             super(X, Y);
  39.             rotatedFrame = framePixels;
  40.             dx = origin.x;
  41.             dy = origin.y;
  42.         }
  43.        
  44.         override public function draw():void
  45.         {
  46.             // Execute the regular rendering code.
  47.             super.draw();
  48.            
  49.             // Destroy the previous bitap to avoid memory leaks.
  50.             rotatedFrame.dispose();
  51.            
  52.             // This if condition is identical to the main one from the default draw() function in FlxSprite. The if code
  53.             // is executed if there are no rotations, the else code if there are. You don't want to run the rotation logic
  54.             // if you don't have to for performance issues.
  55.             if (((angle == 0) || (_bakedRotation > 0)) && (scale.x == 1) && (scale.y == 1) && (blend == null))
  56.             {
  57.                 rotatedFrame = new BitmapData(width, height, true, 0x00F556FF);
  58.                 rotatedFrame.draw(framePixels, null, null, null, null, false);
  59.                 dx = origin.x;
  60.                 dy = origin.y;
  61.             }
  62.             else
  63.             {
  64.                 // There's a rotation! We need to create and store the rotated bitmap.
  65.                
  66.                 var sin:Number = Math.abs( Math.sin( -angle * 0.017453293) );
  67.                 var cos:Number = Math.abs( Math.cos( -angle * 0.017453293) );
  68.                
  69.                 //
  70.                 var rotatedWidth:Number =
  71.                     Math.ceil(
  72.                         cos * width + sin * height
  73.                     )
  74.                 ;
  75.                 var rotatedHeight:Number =
  76.                     Math.ceil(
  77.                         cos * height + sin * width
  78.                     )
  79.                 ;
  80.                 rotatedFrame = new BitmapData(rotatedWidth, rotatedHeight, true, 0x00F556FF);
  81.                
  82.                 // Distances between the origin and the top left corner of the new bounding box.
  83.                 // I dislike the fact that this uses an if statement. Ideally I would have a single mathematical formula for doing this,
  84.                 // but I just can't figure out the math.
  85.                 if (angle > 0)
  86.                 {
  87.                     dy = origin.x * sin + origin.y * cos;
  88.                     dx = (height - origin.y) * sin + origin.x * cos;
  89.                 }
  90.                 else
  91.                 {
  92.                     dy = rotatedHeight - ((height - origin.y) * cos + origin.x * sin);
  93.                     dx = rotatedWidth - (cos * (width - origin.x) + sin * (height - origin.y) * sin);
  94.                 }
  95.                 // We subtract _point so as to cancel out the fact that super.draw() is acting within the absolute coordinate
  96.                 // system. We subtract 'origin' so that the origin is positioned at the top-left corner of the bounding box;
  97.                 // that way we just have to add (dx, dy) to get the bitmap positioned correctly.
  98.                 _matrix.translate(dx - _point.x - origin.x, dy - _point.y - origin.y);
  99.                 rotatedFrame.draw(framePixels, _matrix, null, null, null, false);
  100.             }
  101.         }
  102.        
  103.        
  104.         /*
  105.          * This function is a slightly modified verion of the pixelPerfectCheck in FlxCollision.
  106.          */
  107.         public static function pixelPerfectCheck(contact:PerfectCollisionSprite, target:PerfectCollisionSprite, alphaTolerance:int = 255, camera:FlxCamera = null):Boolean
  108.         {
  109.             var debug:BitmapData = new BitmapData(1, 1, false);
  110.             var pointA:Point = new Point;
  111.             var pointB:Point = new Point;
  112.  
  113.            
  114.             if (camera)
  115.             {
  116.                 pointA.x = contact.X - int(camera.scroll.x * contact.scrollFactor.x) - contact.offset.x - contact.dx;
  117.                 pointA.y = contact.Y - int(camera.scroll.y * contact.scrollFactor.y) - contact.offset.y - contact.dy;
  118.                
  119.                 pointB.x = target.X - int(camera.scroll.x * target.scrollFactor.x) - target.offset.x - target.dx;
  120.                 pointB.y = target.Y - int(camera.scroll.y * target.scrollFactor.y) - target.offset.y - target.dy;
  121.             }
  122.             else
  123.             {
  124.                 pointA.x = contact.X - int(FlxG.camera.scroll.x * contact.scrollFactor.x) - contact.offset.x - contact.dx;
  125.                 pointA.y = contact.Y - int(FlxG.camera.scroll.y * contact.scrollFactor.y) - contact.offset.y - contact.dy;
  126.                
  127.                 pointB.x = target.X - int(FlxG.camera.scroll.x * target.scrollFactor.x) - target.offset.x - target.dx;
  128.                 pointB.y = target.Y - int(FlxG.camera.scroll.y * target.scrollFactor.y) - target.offset.y - target.dy;
  129.             }
  130.            
  131.             var boundsA:Rectangle = new Rectangle(pointA.x, pointA.y, contact.rotatedFrame.width, contact.rotatedFrame.height);
  132.             var boundsB:Rectangle = new Rectangle(pointB.x, pointB.y, target.rotatedFrame.width, target.rotatedFrame.height);
  133.            
  134.             var intersect:Rectangle = boundsA.intersection(boundsB);
  135.            
  136.             if (intersect.isEmpty() || intersect.width == 0 || intersect.height == 0)
  137.             {
  138.                 return false;
  139.             }
  140.            
  141.             //  Normalise the values or it'll break the BitmapData creation below
  142.             intersect.x = Math.floor(intersect.x);
  143.             intersect.y = Math.floor(intersect.y);
  144.             intersect.width = Math.ceil(intersect.width);
  145.             intersect.height = Math.ceil(intersect.height);
  146.            
  147.             if (intersect.isEmpty())
  148.             {
  149.                 return false;
  150.             }
  151.            
  152.             //  Thanks to Chris Underwood for helping with the translate logic :)
  153.            
  154.             var matrixA:Matrix = new Matrix;
  155.             matrixA.translate(-(intersect.x - boundsA.x), -(intersect.y - boundsA.y));
  156.            
  157.             var matrixB:Matrix = new Matrix;
  158.             matrixB.translate(-(intersect.x - boundsB.x), -(intersect.y - boundsB.y));
  159.            
  160.             var testA:BitmapData = contact.rotatedFrame;
  161.             var testB:BitmapData = target.rotatedFrame;
  162.             var overlapArea:BitmapData = new BitmapData(intersect.width, intersect.height, false);
  163.            
  164.             overlapArea.draw(testA, matrixA, new ColorTransform(1, 1, 1, 1, 255, -255, -255, alphaTolerance), BlendMode.NORMAL);
  165.             overlapArea.draw(testB, matrixB, new ColorTransform(1, 1, 1, 1, 255, 255, 255, alphaTolerance), BlendMode.DIFFERENCE);
  166.            
  167.             //  Developers: If you'd like to see how this works, display it in your game somewhere. Or you can comment it out to save a tiny bit of performance
  168.             debug = overlapArea;
  169.             //(FlxG.state as PlayState).drawBMP(debug, intersect.x, intersect.y, 0);
  170.             //drawPoint(pointA, 0xFFFF00FF, -1);
  171.             //drawPoint(pointB, 0xFF00FF00, 2);
  172.             //drawRect(boundsA, 0xFFFF00FF, 3);
  173.             //drawRect(boundsB, 0x8800FF00, 4);
  174.             //(FlxG.state as PlayState).drawRect(intersect, 0xFFFFFFFF, 5);
  175.            
  176.             var overlap:Rectangle = overlapArea.getColorBoundsRect(0xffffffff, 0xff00ffff);
  177.             overlap.offset(intersect.x, intersect.y);
  178.            
  179.             if (overlap.isEmpty())
  180.             {
  181.                 return false;
  182.             }
  183.             else
  184.             {
  185.                 return true;
  186.             }
  187.         }
  188.        
  189.         // Due to all the rotation logic, we frequently have to work with the coordinates of the pivot point, which
  190.         // is 'origin'. So we implement the variables X and Y to stand in for the absolute coordinates of that point.
  191.        
  192.         public function get X():Number
  193.         {
  194.             return x + origin.x;
  195.         }
  196.        
  197.         public function set X(arg:Number):void
  198.         {
  199.             x = arg - origin.x;
  200.         }
  201.        
  202.         public function get Y():Number
  203.         {
  204.             return y + origin.y;
  205.         }
  206.        
  207.         public function set Y(arg:Number):void
  208.         {
  209.             y = arg - origin.y;
  210.         }
  211.        
  212.     }
  213.  
  214. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement