user1669696
user1669696

Reputation: 53

Semi-collision using AS3's hitTest and bitmapData

So I'm working on a game using AS3, currently wherein I require 2D-collision checking. To do this I naturally resided with bitmapData and hitTest, but due to me not being able to do that properly, I decided to use freeactionscript.com's CollisionTest engine. However, even when using this I am experiencing problems, and I'll try to explain it with the help of the image I have included.

  1. The setup - I have a yellow character and a grey square.
  2. You can clearly see the yellow character being stopped by the grey square - I am unable to walk any further at this point.
  3. Going beneat the square works fine too, I can't walk any further here either.
  4. Now, here is the dilemma - the collision detection works fine in the bottom right corner. I can walk freely around in any other part of the square, and any excess collision (ie. outside the grey square) does not occur.

I am using this code:

public class CollisionTest 
{
    // vars
    private var _returnValue:Boolean;

    private var _onePoint:Point;
    private var _twoPoint:Point;

    private var _oneRectangle:Rectangle;
    private var _twoRectangle:Rectangle;

    private var _oneClipBmpData:BitmapData;
    private var _twoClipBmpData:BitmapData;

    private var _oneOffset:Matrix;
    private var _twoOffset:Matrix;

    /**
     * Complex collision test. Use this for objects that are rotated, scaled, skewed, etc
     * @param   clip1   Takes DisplayObjectContainer as argument. Can be a Sprite, MovieClip, etc.
     * @param   clip2   Takes DisplayObjectContainer as argument. Can be a Sprite, MovieClip, etc.
     * @return  Collision True/False
     */
    public function complex(clip1:DisplayObjectContainer, clip2:DisplayObjectContainer):Boolean
    {
        _returnValue = false;

        _twoRectangle = clip1.getBounds(clip1);
        _oneOffset = clip1.transform.matrix;
        _oneOffset.tx = clip1.x - clip2.x;
        _oneOffset.ty = clip1.y - clip2.y;  

        _twoClipBmpData = new BitmapData(_twoRectangle.width, _twoRectangle.height, true, 0);
        _twoClipBmpData.draw(clip1, _oneOffset);        

        _oneRectangle = clip2.getBounds(clip2);
        _oneClipBmpData = new BitmapData(_oneRectangle.width, _oneRectangle.height, true, 0);

        _twoOffset = clip2.transform.matrix;
        _twoOffset.tx = clip2.x - clip2.x;
        _twoOffset.ty = clip2.y - clip2.y;  

        _oneClipBmpData.draw(clip2, _twoOffset);

        _onePoint = new Point(_oneRectangle.x, _oneRectangle.y);
        _twoPoint = new Point(_twoRectangle.x, _twoRectangle.y);

        if(_oneClipBmpData.hitTest(_onePoint, 255, _twoClipBmpData, _twoPoint, 255))
        {
            _returnValue = true;
        }

        _twoClipBmpData.dispose();
        _oneClipBmpData.dispose();

        return _returnValue;
    }

It'd help me tremendously if anyone could be of assistance. You can try it out for yourself here if you want to.

Thanks in advance, -UPTX

tl;dr: hitTest works on 1/4 of the grey square, as shown here picture included:

Upvotes: 3

Views: 706

Answers (1)

Roman Trofimov
Roman Trofimov

Reputation: 446

As I understand your problem:

public function complex(clip1:DisplayObjectContainer, clip2:DisplayObjectContainer):Boolean
{
    _returnValue = false;

    _twoRectangle = clip1.getBounds(clip1);

At this point you get non-transformed bounds of your clip. For example, box has another bounds when it rotated. It is not big problem in your case only because your unit has more "circle" than "box" shape.

But main problem (like on the picture) you'll have, if you use centered sprites - when half content lays in "negative" space coordinates. In this case method getBounds returns you negative left-top corner. So on bitmapdata of this object you will have only part of sprite.

If you want fast fix for your method, change your matrix setup to

   _oneOffset.tx = clip1.x-clip2.x-_twoRectangle.x;
   _oneOffset.ty = clip1.y-clip2.y-_twoRectangle.x;

and

   _twoOffset.tx = clip2.x - clip2.x-_oneRectangle.x;
   _twoOffset.ty = clip2.y - clip2.y-_oneRectangle.y;

But please, note: to make this way of calculating intersection right you need:

1) Change your rendering method. For example, you can enclose your objects to some parent and draw this parent - it will give you correct bounding box.

2) You can calculate boundings manually: Calculate Bounding box coordinates from a rotated rectangle

Hope, it will help.

Upvotes: 1

Related Questions