コード例 #1
0
 public Collision(CollisionBox mybox, CollisionBox target, CollisionComponent tgtComp)
 {
     myBox = mybox;
     targetBox = target;
     targetColl = tgtComp;
 }
コード例 #2
0
 public Collision(CollisionBox mybox, CollisionBox target, CollisionComponent tgtComp)
 {
     myBox      = mybox;
     targetBox  = target;
     targetColl = tgtComp;
 }
コード例 #3
0
        /// <summary>
        /// Get the hitboxes that the calling box can target
        /// </summary>
        private IEnumerable<CollisionBox> TargetBoxes(CollisionBox hitbox)
        {
            if (!cacheTargetBoxes.ContainsKey(hitbox.ID))
            {
                cacheTargetBoxes[hitbox.ID] = new List<CollisionBox>(hitboxes
                    .Where(box => box.Groups.Intersect(hitbox.Hits).Any()));
            }

            foreach (CollisionBox box in cacheTargetBoxes[hitbox.ID])
            {
                box.SetParent(this);
            }

            return cacheTargetBoxes[hitbox.ID].Where(box => enabledBoxes.Contains(box.ID));
        }
コード例 #4
0
        private void Touch(CollisionBox targetbox, CollisionBox mybox)
        {
            foreach (var group in targetbox.Groups)
            {
                touchedBy.Add(group);

                foreach (var mygroup in mybox.Groups)
                {
                    if (!touchedAt.ContainsKey(mygroup))
                    {
                        touchedAt[mygroup] = new HashSet<string>();
                    }
                    touchedAt[mygroup].Add(group);
                }
            }
        }
コード例 #5
0
        private void CollideWith(IEntity entity, CollisionBox myBox, CollisionBox targetBox)
        {
            float mult = targetBox.DamageMultiplier(Parent.Name);

            float damage = myBox.ContactDamage * mult;

            IGameMessage dmgmsg;
            if (damage > 0) dmgmsg = new DamageMessage(Parent, damage);
            else dmgmsg = new HealMessage(Parent, damage * -1);

            float prevhealth = damage;
            HealthComponent comp = entity.GetComponent<HealthComponent>();
            if (comp != null) prevhealth = comp.Health;

            entity.SendMessage(dmgmsg);
            DamageDealt = Math.Min(damage, prevhealth);
        }
コード例 #6
0
        private void ReactForHitbox(List<MapSquare> hitSquares, HashSet<TileProperties> hitTypes, CollisionBox hitbox)
        {
            hitbox.SetParent(this);

            RectangleF boundBox = hitbox.BoxAt(PositionSrc.Position);

            if (hitbox.Environment)
            {
                foreach (MapSquare tile in hitSquares)
                {
                    RectangleF tileBox = tile.BlockBox;
                    bool downonly = (!Parent.Container.IsGravityFlipped && tile.Tile.Properties.Climbable);
                    bool uponly = (Parent.Container.IsGravityFlipped && tile.Tile.Properties.Climbable);

                    bool hit = (tile.BlockBox != RectangleF.Empty) ? BlockByIntersection(boundBox, tileBox, uponly, downonly) : boundBox.IntersectsWith(tile.BoundBox);

                    if (hitbox.PushAway && (hit || boundBox.IntersectsWith(tile.BoundBox)))    // the environment touched me!
                    {
                        hitTypes.Add(tile.Tile.Properties);
                    }
                }
            }

            // but for entities, we can go ahead and be active aggressors -
            // inflict our effects on the target entity, not the other way around
            foreach (var entity in Parent.Entities.GetAll())
            {
                if (entity == Parent) continue;
                CollisionComponent coll = entity.GetComponent<CollisionComponent>();
                if (coll == null) continue;

                foreach (CollisionBox targetBox in coll.TargetBoxes(hitbox))
                {
                    boundBox = CheckTargetBox(hitbox, boundBox, entity, coll, targetBox);
                }
            }
        }
コード例 #7
0
 private void CheckEnvironmentTile(List<MapSquare> hitSquares, CollisionBox hitbox, RectangleF hitRect, MapSquare tile, ref PointF offset)
 {
     if (hitbox.EnvironmentCollisions(PositionSrc.Position, tile, ref offset))
     {
         hitSquares.Add(tile);
         if (hitbox.PushAway) PositionSrc.Offset(offset.X, offset.Y);
     }
     else if (hitRect.IntersectsWith(tile.BoundBox))
     {
         hitSquares.Add(tile);
     }
 }
コード例 #8
0
        /// <summary>
        /// See return value. Fills hitBlockEntities with all/solid (see param solidOnly) entities hit
        /// </summary>
        /// <param name="box">Box for which to check collisions</param>
        /// <param name="property">Property to check for</param>
        /// <param name="solidOnly">Only checks for solid entities</param>
        /// <param name="pushAway">Solve collisions</param>
        /// <returns>True if an entity solid/not (see param solidOnly) is hit</returns>
        private bool CollisionWithAllEntities_RealTime(CollisionBox box, string property, bool solidOnly = true, bool pushAway = false)
        {
            box.SetParent(this);

            RectangleF boundbox = box.BoxAt(PositionSrc.Position); //calculate boundbox absolute coordinate
            hitBlockEntities_RealTime = new List<Collision>();

            boundbox = CheckEntityCollisions(hitBlockEntities_RealTime, box, boundbox, pushAway, solidOnly);

            return CheckIfOneEntityHitContainProperty_RealTime(property);
        }
コード例 #9
0
        private RectangleF CheckEntityCollisions(List<Collision> blockEntities, CollisionBox hitbox, RectangleF boundbox)
        {
            foreach (var entity in Parent.Entities.GetAll())
            {
                if (entity == Parent) continue;
                CollisionComponent coll = entity.GetComponent<CollisionComponent>();
                if (coll == null) continue;

                foreach (CollisionBox targetBox in coll.HitByBoxes(hitbox).Where(box => box.Properties.Blocking))
                {
                    // if he's blocking, check for collision and maybe push me away

                    RectangleF rect = targetBox.BoxAt(coll.PositionSrc.Position);
                    RectangleF adjustrect = rect;
                    adjustrect.X -= Const.PixelEpsilon;
                    adjustrect.Y -= Const.PixelEpsilon;
                    adjustrect.Width += 2 * Const.PixelEpsilon;
                    adjustrect.Height += 2 - Const.PixelEpsilon;
                    RectangleF intersection = RectangleF.Intersect(boundbox, adjustrect);
                    if (intersection.Width != 0 || intersection.Height != 0)
                    {
                        blockEntities.Add(new Collision(hitbox, targetBox, coll));

                        if (hitbox.PushAway)
                        {
                            float vx, vy;
                            MovementComponent mov = entity.GetComponent<MovementComponent>();
                            vx = MovementSrc.VelocityX;
                            vy = MovementSrc.VelocityY;
                            if (mov != null)
                            {
                                vx -= mov.VelocityX;
                                vy -= mov.VelocityY;
                            }

                            PointF offset = hitbox.GetIntersectionOffset(rect, boundbox, vx, vy, false, false);
                            if (offset.X != 0 || offset.Y != 0)
                            {
                                PositionSrc.Offset(offset.X, offset.Y);
                                boundbox.Offset(offset.X, offset.Y);
                            }
                        }
                    }
                }
            }
            return boundbox;
        }
コード例 #10
0
        private void CheckEnvironment(List<MapSquare> hitSquares, CollisionBox hitbox)
        {
            PointF offset = new PointF(0, 0);
            RectangleF hitRect = hitbox.BoxAt(PositionSrc.Position);

            // this bounds checking prevents needlessly checking collisions way too far away
            // it's a very effective optimization (brings busy time from ~60% down to 45%!)
            int size = Parent.Screen.TileSize;

            for (float y = hitRect.Top - size; y < hitRect.Bottom; y += size)
            {
                for (float x = hitRect.Left - size; x < hitRect.Right; x += size)
                {
                    var tile = Parent.Screen.SquareAt(x, y);
                    if (tile == null) continue;

                    CheckEnvironmentTile(hitSquares, hitbox, hitRect, tile, ref offset);
                }

                var rightEdge = Parent.Screen.SquareAt(hitRect.Right, y);
                if (rightEdge != null)
                {
                    CheckEnvironmentTile(hitSquares, hitbox, hitRect, rightEdge, ref offset);
                }
            }

            for (float x = hitRect.Left - size; x < hitRect.Right; x += size)
            {
                var tile = Parent.Screen.SquareAt(x, hitRect.Bottom);
                if (tile == null) continue;

                CheckEnvironmentTile(hitSquares, hitbox, hitRect, tile, ref offset);
            }

            var lastCorner = Parent.Screen.SquareAt(hitRect.Right, hitRect.Bottom);
            if (lastCorner != null)
            {
                CheckEnvironmentTile(hitSquares, hitbox, hitRect, lastCorner, ref offset);
            }
        }
コード例 #11
0
        public override void LoadXml(XElement xml)
        {
            foreach (XElement boxnode in xml.Elements("Hitbox"))
            {
                CollisionBox box = new CollisionBox(boxnode);
                box.SetParent(this);
                AddBox(box);
            }

            Enabled = xml.TryAttribute<bool>("Enabled");
        }
コード例 #12
0
 public void AddBox(CollisionBox box)
 {
     hitboxes.Add(box);
     if (box.Name != null) boxIDsByName.Add(box.Name, box.ID);
 }
コード例 #13
0
        /// <summary>
        /// See return value. Fills hitSquaresForFunctionThatChecksCollisions with blocks hit
        /// </summary>
        /// <param name="box">Box for which to check collisions</param>
        /// <param name="property">Property to check for</param>
        /// <param name="pushAway">Solve collisions</param>
        /// <returns>True if a solid block is hit</returns>
        private bool CollisionWithTiles_RealTime(CollisionBox box, string property, bool pushAway = false)
        {
            hitSquares_RealTime = new List<MapSquare>(); // hitSquares: those touching
            box.SetParent(this);
            CheckEnvironment(hitSquares_RealTime, box, pushAway);

            return CheckIfOneTileHitContainProperty_RealTime(property);
        }
コード例 #14
0
        private void ReactForHitbox(List <MapSquare> hitSquares, HashSet <TileProperties> hitTypes, CollisionBox hitbox)
        {
            hitbox.SetParent(this);

            var boundBox = hitbox.BoxAt(PositionSrc.Position);

            if (hitbox.Environment)
            {
                foreach (MapSquare tile in hitSquares)
                {
                    var  tileBox  = tile.BlockBox;
                    bool downonly = (!Parent.Container.IsGravityFlipped && tile.Tile.Properties.Climbable);
                    bool uponly   = (Parent.Container.IsGravityFlipped && tile.Tile.Properties.Climbable);

                    bool hit = (tile.BlockBox != Rectangle.Empty) ? BlockByIntersection(boundBox, tileBox, uponly, downonly) : boundBox.IntersectsWith(tile.BoundBox);

                    if (hitbox.PushAway && (hit || boundBox.IntersectsWith(tile.BoundBox)))    // the environment touched me!
                    {
                        hitTypes.Add(tile.Tile.Properties);
                    }
                }
            }

            // but for entities, we can go ahead and be active aggressors -
            // inflict our effects on the target entity, not the other way around
            foreach (var entity in Parent.Entities.GetAll())
            {
                if (entity == Parent)
                {
                    continue;
                }
                CollisionComponent coll = entity.GetComponent <CollisionComponent>();
                if (coll == null)
                {
                    continue;
                }

                foreach (CollisionBox targetBox in coll.TargetBoxes(hitbox))
                {
                    boundBox = CheckTargetBox(hitbox, boundBox, entity, coll, targetBox);
                }
            }
        }
コード例 #15
0
 private RectangleF CheckTargetBox(CollisionBox hitbox, RectangleF boundBox, IEntity entity, CollisionComponent coll, CollisionBox targetBox)
 {
     RectangleF rect = targetBox.BoxAt(coll.PositionSrc.Position);
     if (boundBox.IntersectsWith(rect))
     {
         coll.Touch(hitbox, targetBox);
         Touch(targetBox, hitbox);
         CollideWith(entity, hitbox, targetBox);
     }
     return boundBox;
 }
コード例 #16
0
        private Rectangle CheckTargetBox(CollisionBox hitbox, Rectangle boundBox, IEntity entity, CollisionComponent coll, CollisionBox targetBox)
        {
            var rect = targetBox.BoxAt(coll.PositionSrc.Position);

            if (boundBox.IntersectsWith(rect))
            {
                coll.Touch(hitbox, targetBox);
                Touch(targetBox, hitbox);
                CollideWith(entity, hitbox, targetBox);
            }
            return(boundBox);
        }
コード例 #17
0
        internal void Loadinfo(CollisionComponentInfo info)
        {
            Enabled = info.Enabled;

            foreach (var box in info.HitBoxes)
            {
                var coll = new CollisionBox(box);
                coll.SetParent(this);
                AddBox(coll);
            }
        }