Exemplo n.º 1
0
        public bool SetPawnPosition(Pawn pawn, Point newPosition)
        {
            if (!_pawns.Contains(pawn)) {
                throw new ArgumentException("Pawn " + pawn.Name + " has not been added to this Board", "pawn");
            }

            bool moved = false;

            List<HashSet<Pawn>> toRemove = new List<HashSet<Pawn>>();
            List<HashSet<Pawn>> toAdd = new List<HashSet<Pawn>>();

            HashSet<Pawn> enterCollisions = new HashSet<Pawn>();
            HashSet<Pawn> exitCollisions = new HashSet<Pawn>();

            Point oldPoint;
            Point newPoint;
            bool walled = false;

            // Gather all pawns that were in the original and new position's footprint
            foreach (Point offset in pawn.Footprint) {
                HashSet<Pawn> oldBucket;
                HashSet<Pawn> newBucket;

                oldPoint = pawn.Position + offset;
                newPoint = newPosition + offset;

                // Check if there's a wall at the new point.  If so, early out.
                if (pawn.IsSolid) {
                    if (InBounds(newPoint) && GetTile(newPoint) == WALL_TILE) {
                        return false;
                    }
                }

                // Add all pawns in the current bucket to the exit collision set
                oldBucket = GetBucket(oldPoint, false);
                if (oldBucket != null) {
                    exitCollisions.UnionWith(oldBucket);
                    toRemove.Add(oldBucket);
                }

                // Add all pawns in the new position to the enter set
                newBucket = GetBucket(newPoint, true);
                enterCollisions.UnionWith(newBucket);
                toAdd.Add(newBucket);
            }

            // If the pawn is solid, and any of the entering collision pawns are solid, don't allow the move
            bool willMove = true;
            if (pawn.IsSolid) {
                if (walled) {
                    willMove = false;
                } else {
                    foreach (Pawn other in enterCollisions) {
                        if (other != pawn && other.IsSolid) {
                            willMove = false;
                            break;
                        }
                    }
                }
            }

            // Move the pawn between buckets
            if (willMove) {
                for (int i = 0; i < toRemove.Count; i++) {
                    toRemove[i].Remove(pawn);
                }

                for (int i = 0; i < toAdd.Count; i++) {
                    toAdd[i].Add(pawn);
                }

                pawn.SetPositionInternal(newPosition);
                moved = true;
            }

            if (pawn.IsCollidable) {
                // The stay set consists of pawns that are in both the exit and enter sets
                HashSet<Pawn> stayCollisions = new HashSet<Pawn>(exitCollisions);
                stayCollisions.IntersectWith(enterCollisions);

                // Remove the stay collisions from both the exit and enter sets
                enterCollisions.ExceptWith(stayCollisions);
                exitCollisions.ExceptWith(stayCollisions);

                // Call the collision methods
                foreach (Pawn other in enterCollisions) {
                    if (pawn != other && other.IsCollidable) {
                        pawn.OnCollisionEnter(other);
                        other.OnCollisionEnter(pawn);
                    }
                }

                foreach (Pawn other in stayCollisions) {
                    if (pawn != other && other.IsCollidable) {
                        pawn.OnCollisionStay(other);
                        other.OnCollisionStay(pawn);
                    }
                }

                foreach (Pawn other in exitCollisions) {
                    if (pawn != other && other.IsCollidable) {
                        pawn.OnCollisionExit(other);
                        other.OnCollisionExit(pawn);
                    }
                }
            }

            return moved;
        }