/// <summary>
        /// Initializes a new CollisionSystem which uses a grid to speed up collision detection.
        /// Use this system for larger scenes with many objects.
        /// </summary>
        /// <param name="nx">Number of GridEntries in X Direction.</param>
        /// <param name="ny">Number of GridEntries in Y Direction.</param>
        /// <param name="nz">Number of GridEntries in Z Direction.</param>
        /// <param name="dx">Size of a single GridEntry in X Direction.</param>
        /// <param name="dy">Size of a single GridEntry in Y Direction.</param>
        /// <param name="dz">Size of a single GridEntry in Z Direction.</param>
        public CollisionSystemGrid(int nx, int ny, int nz, float dx, float dy, float dz)
        {
            this.nx = nx; this.ny = ny; this.nz = nz;
            this.dx = dx; this.dy = dy; this.dz = dz;

            this.sizeX = nx * dx;
            this.sizeY = ny * dy;
            this.sizeZ = nz * dz;
            this.minDelta = System.Math.Min(System.Math.Min(dx, dy), dz);

            int numEntries = nx * ny * nz * 2; // we allocate twice as many as need for collision skins
            gridEntries = new List<GridEntry>(numEntries);
            gridBoxes = new List<AABox>(numEntries);

            tempGridLists = new List<GridEntry>(numEntries);

            freeGrids = new Stack<GridEntry>(numEntries);
            for (int i = 0; i < numEntries; ++i)
            {
                GridEntry entry = new GridEntry();
                entry.GridIndex = -2;
                freeGrids.Push(entry);
            }

            for (int i = 0; i < (nx * ny * nz); ++i)
            {
                GridEntry gridEntry = freeGrids.Pop();
                gridEntry.GridIndex = i;
                gridEntries.Add(gridEntry);
                gridBoxes.Add(null);
            }

            overflowEntries = freeGrids.Pop();
            overflowEntries.GridIndex = -1;

            for (int iX = 0; iX < nx; ++iX)
            {
                for (int iY = 0; iY < ny; ++iY)
                {
                    for (int iZ = 0; iZ < nz; ++iZ)
                    {
                        AABox box = new AABox();
                        box.AddPoint(new Vector3(iX * dx, iY * dy, iZ + dz));
                        box.AddPoint(new Vector3(iX * dx + dx, iY * dy + dy, iZ * dz + dz));

                        int index = CalcIndex(iX, iY, iZ);
                        gridBoxes[index] = box;
                    }
                }
            }
        }
 /// <summary>
 /// Removes the entry by updating its neighbours. Also zaps the prev/next
 /// pointers in the entry, to help debugging
 /// </summary>
 /// <param name="entry"></param>
 public static void RemoveGridEntry(GridEntry entry)
 {
     // link the previous to the next (may be 0)
     entry.Previous.Next = entry.Next;
     // link the next (if it exists) to the previous.
     if (entry.Next != null)
         entry.Next.Previous = entry.Previous;
     // tidy up this entry
     entry.Previous = entry.Next = null;
     entry.GridIndex = -2;
 }
 /// <summary>
 /// Inserts an entry after prev, updating all links
 /// </summary>
 /// <param name="entry"></param>
 /// <param name="prev"></param>
 public static void InsertGridEntryAfter(GridEntry entry, GridEntry prev)
 {
     GridEntry next = prev.Next;
     prev.Next = entry;
     entry.Previous = prev;
     entry.Next = next;
     if (next != null)
         next.Previous = entry;
     entry.GridIndex = prev.GridIndex;
 }
 public GridEntry(CollisionSkin skin)
 {
     this.Skin = skin;
     this.Previous = this.Next = null;
 }
Пример #5
0
        /// <summary>
        /// DetectAllCollisions
        /// </summary>
        /// <param name="bodies"></param>
        /// <param name="collisionFunctor"></param>
        /// <param name="collisionPredicate"></param>
        /// <param name="collTolerance"></param>
        public override void DetectAllCollisions(List <Body> bodies, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance)
        {
            int numBodies = bodies.Count;

            CollDetectInfo info = new CollDetectInfo();

            for (int iBody = 0; iBody < numBodies; ++iBody)
            {
                Body body = bodies[iBody];
                if (!body.IsActive)
                {
                    continue;
                }

                info.Skin0 = body.CollisionSkin;
                if (info.Skin0 == null)
                {
                    continue;
                }

                tempGridLists.Clear();
                GetListsToCheck(tempGridLists, info.Skin0);

                for (int iList = tempGridLists.Count; iList-- != 0;)
                {
                    // first one is a placeholder;
                    GridEntry entry = tempGridLists[iList];
                    for (entry = entry.Next; entry != null; entry = entry.Next)
                    {
                        info.Skin1 = entry.Skin;
                        if (info.Skin1 == info.Skin0)
                        {
                            continue;
                        }

                        // CHANGE
                        if (info.Skin1 == null)
                        {
                            continue;
                        }

                        bool skinSleeping = true;

                        if ((info.Skin1.Owner != null) && (info.Skin1.Owner.IsActive))
                        {
                            skinSleeping = false;
                        }

                        // only do one per pair
                        if ((skinSleeping == false) && (info.Skin1.ID < info.Skin0.ID))
                        {
                            continue;
                        }

                        if ((collisionPredicate != null) && (!collisionPredicate.ConsiderSkinPair(info.Skin0, info.Skin1)))
                        {
                            continue;
                        }

                        // basic bbox test
                        if (BoundingBoxHelper.OverlapTest(ref info.Skin1.WorldBoundingBox,
                                                          ref info.Skin0.WorldBoundingBox, collTolerance))
                        {
                            if (CheckCollidables(info.Skin0, info.Skin1))
                            {
                                int bodyPrimitives = info.Skin0.NumPrimitives;
                                int primitves      = info.Skin1.NumPrimitives;

                                for (info.IndexPrim0 = 0; info.IndexPrim0 < bodyPrimitives; ++info.IndexPrim0)
                                {
                                    for (info.IndexPrim1 = 0; info.IndexPrim1 < primitves; ++info.IndexPrim1)
                                    {
                                        DetectFunctor f = GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type,
                                                                               info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type);
                                        if (f != null)
                                        {
                                            f.CollDetect(info, collTolerance, collisionFunctor);
                                        }
                                    }
                                }
                            } // check collidables
                        }     // overlapt test
                    }         // loop over entries
                }             // loop over lists
            }                 // loop over bodies
        }
Пример #6
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="skin"></param>
 public GridEntry(CollisionSkin skin)
 {
     this.Skin     = skin;
     this.Previous = this.Next = null;
 }
Пример #7
0
        /// <summary>
        /// GetListsToCheck
        /// </summary>
        /// <param name="entries"></param>
        /// <param name="skin"></param>
        private void GetListsToCheck(List <GridEntry> entries, CollisionSkin skin)
        {
            entries.Clear();

            GridEntry entry = (GridEntry)skin.ExternalData;

            if (entry == null)
            {
                System.Diagnostics.Debug.WriteLine("Warning skin has grid entry null!");
                //TRACE("Warning = skin %s has grid entry 0!\n", skin);
                return;
            }

            // todo - work back from the mGridIndex rather than calculating it again...
            int   i, j, k;
            float fi, fj, fk;

            CalcGridForSkin(out i, out j, out k, out fi, out fj, out fk, skin);

            if (i == -1)
            {
                // oh dear - add everything
                for (i = 0; i < gridEntries.Count; ++i)
                {
                    if (gridEntries[i].Next != null)
                    {
                        entries.Add(gridEntries[i]);
                    }
                }
                //entries = gridEntries;
                entries.Add(overflowEntries);
                return;
            }

            // always add the overflow
            entries.Add(overflowEntries);

            Vector3 delta = skin.WorldBoundingBox.Max - skin.WorldBoundingBox.Min;
            int     maxI = 1, maxJ = 1, maxK = 1;

            if (fi + (delta.X / dx) < 1.0f)
            {
                maxI = 0;
            }
            if (fj + (delta.Y / dy) < 1.0f)
            {
                maxJ = 0;
            }
            if (fk + (delta.Z / dz) < 1.0f)
            {
                maxK = 0;
            }

            // now add the contents of all 18 grid boxes - their contents may extend beyond the bounds
            for (int di = -1; di <= maxI; ++di)
            {
                for (int dj = -1; dj <= maxJ; ++dj)
                {
                    for (int dk = -1; dk <= maxK; ++dk)
                    {
                        int       thisIndex = CalcIndex(nx + i + di, ny + j + dj, nz + k + dk);
                        GridEntry start     = gridEntries[thisIndex];
                        if (start.Next != null)
                        {
                            entries.Add(start);
                        }
                    }
                }
            }
        }