public override bool collides(bMask other)
        {
            if (!(other is bMaskList))  // this call is useless for masklists, as it will delegate back on this class
            {
                // Bbox check
                if (!base.collides(other))
                    return false;
            }

            return rectMaskCollides(other);
        }
        public bMaskList(bMask[] masks, int x, int y, bool connected = true /* whether the masks are part of the same bounding box or not */)
            : base(0, 0, 0, 0)
        {
            // compute dimensions
            if (masks.Length == 0)
            {
                Console.WriteLine("Could not init bMaskList, not one mask was provided");
                return;
            }

            this.connected = connected;
            if (connected)
            {
                this.rect = new Rectangle(0, 0, 0, 0);
                this.offsetx = int.MaxValue;
                this.offsety = int.MaxValue;
                this.masks = masks;

                // compute offsets
                foreach (var mask in masks)
                {
                    offsetx = Math.Min(this.offsetx, mask.rect.X);
                    offsety = Math.Min(this.offsety, mask.rect.Y);
                    mask.x = x;
                    mask.x = y;
                }

                // compute dimensions (need minimum offsets for this)
                foreach (var mask in masks)
                {
                    // believe me on this one
                    if ((this.rect.Width + this.offsetx) < mask.rect.Width + mask.offsetx)
                        this.rect.Width = mask.rect.Width + mask.offsetx - this.offsetx;
                    if ((this.rect.Height + this.offsety) < (mask.rect.Height + mask.offsety))
                        this.rect.Height = mask.rect.Height + mask.offsety - this.offsety;
                }

                this.x = x;
                this.y = y;

                // default values
                flipped = false;
            }
            else
            {
                // Much simpler initialization, the masklist is just a wrapper in this case
                this.masks = masks;
                this.x = x;
                this.y = y;
            }
        }
        public void updateSubmask(bMask mask)
        {
            // fix internal masks offsets
            if (connected)
            {
                if (!flipped)
                {
                    // x origin is the same as the father's (added with offsetx in the x property)
                    mask.x = rect.X - offsetx;
                }
                else
                {
                    // x origin is flipped within the father's limit (a bit tricky)
                    int maskoffsetx = mask.offsetx - offsetx;
                    mask.x = rect.X + w - maskoffsetx - mask.w - mask.offsetx;
                }

                // y origin is the same as unflipped x (for now)
                mask.y = rect.Y - offsety;
            }
            else
            {
                mask.update(x,y);
            }
        }
 public virtual bool collides(bMask mask, string[] categories, Func<bEntity, bEntity, bool> condition = null)
 {
     foreach (string category in categories)
         if (entities[category] != null)
             foreach (bEntity ge in entities[category])
                 if (ge.collidable && ge.mask != null && mask.collides(ge.mask) && (condition == null || condition(null, ge)))
                     return true;
     return false;
 }
 public bEntity(int x, int y)
 {
     pos = new Vector2(x, y);
     id = -1;
     layer = 0;
     mask = new bMask(0, 0, 0, 0);
     color = Color.White;
     collidable = true;
     attributes = new List<String>();
     timer = new int[5];
     for (int i = 0; i < NTIMERS; i++)
         timer[i] = -1;
 }
        public bool rectMaskCollides(bMask other)
        {
            int tlx = Math.Max((other.x - x) / tileWidth, 0);
            int tly = Math.Max((other.y - y) / tileHeight, 0);
            int brx = Math.Min((other.x + other.w - 1 - x) / tileWidth, columns - 1);
            int bry = Math.Min((other.y + other.h - 1 - y) / tileHeight, rows - 1);

            for (int xx = tlx; xx <= brx; xx++)
                for (int yy = tly; yy <= bry; yy++)
                    if (solidData[xx, yy])
                        return true;

            return false;
        }
        public override bool collides(bMask other)
        {
            bool collided = false;

            if (connected)
            {
                // collides with outer mask?
                if (other is bSolidGrid)
                {
                    collided = other.collides(this);
                }
                else
                {
                    collided = rect.Intersects(other.rect);
                }
            }
            else
            {
                // Assume other collides with the whole list and check one by one if that's ever true
                collided = true;
            }

            // collides with any inner mask?
            if (collided)
                foreach (bMask mask in masks)
                {
                    // lazy (x,y) update
                    updateSubmask(mask);

                    if (mask.collides(other))
                        return true;
                }
            return false;
        }
 public virtual bEntity instancePlace(bMask collisionMask, String[] categories, String attr = null, Func<bEntity, bEntity, bool> condition = null)
 {
     bEntity e = world.instanceCollision(collisionMask, categories, attr, condition);
     return e;
 }
 public virtual bEntity instancePlace(bMask collisionMask, String category, String attr = null, Func<bEntity, bEntity, bool> condition = null)
 {
     return instancePlace(collisionMask, new String[] { category }, attr, condition);
 }
 public virtual bool collides(bMask other)
 {
     // is exactly bMask
     if (other.GetType() == typeof(bMask))
         return rect.Intersects(other.rect);
     else
         return other.collides(this);
 }
        public virtual List<bEntity> instancesCollision(bMask mask, string[] categories, string attr = null, Func<bEntity, bEntity, bool> condition = null)
        {
            List<bEntity> result = new List<bEntity>();

            foreach (string category in categories)
                if (entities[category] != null)
                    foreach (bEntity ge in entities[category])
                        if (ge.collidable && ge.mask != null && mask.collides(ge.mask) && (condition == null || condition(null, ge)))
                            if (attr == null || ge.hasAttribute(attr))
                                result.Add(ge);

            return result;
        }
 public virtual List<bEntity> instancesCollision(bMask mask, string category, string attr = null, Func<bEntity, bEntity, bool> condition = null)
 {
     return instancesCollision(mask, new string[] { category }, attr, condition);
 }
 public virtual bEntity instanceCollision(bMask mask, string[] categories, string attr = null, Func<bEntity, bEntity, bool> condition = null)
 {
     foreach (string category in categories)
         if (entities[category] != null)
             foreach (bEntity ge in entities[category])
                 if (ge.collidable && ge.mask != null && mask.collides(ge.mask) && (condition == null || condition(null, ge)))
                     if (attr == null || ge.hasAttribute(attr))
                         return ge;
     return null;
 }