public void Add(ItemInWater item)
 {
     if (bucketIndex >= items.Count)
     {
         bucketIndex = 0;
     }
     items[bucketIndex].Add(item);
     bucketIndex++;
 }
        void OnTriggerEnter(Collider other)
        {
            bool      trackOnly = onlyTrackIDs.Contains(other.gameObject.GetInstanceID());
            Rigidbody r         = other.GetComponent <Rigidbody>();

            if ((r != null && !r.isKinematic) || trackOnly)
            {
                if (!r.gameObject.isStatic && !itemsInVolume.ContainsKey(r.gameObject.GetInstanceID()))
                {
                    ItemInWater item = new ItemInWater(other.gameObject);
                    item.water     = this;
                    item.id        = other.gameObject.GetInstanceID();
                    item.trackOnly = trackOnly;
                    itemsInVolume.Add(item.id, item);
                    itemsEnumerator = itemsInVolume.GetEnumerator();
                }
            }
        }
        public virtual void ForceLoop()
        {
            statistics.lastRayCount = 0;

            // Keep the total amount of force constant regardless of variability in time and raycast spacing
            dragForceMultiplier = Time.fixedDeltaTime * raycastSpacing * raycastSpacing * viscosity;

            itemsEnumerator = itemsInVolume.GetEnumerator();

            if (raycastSpacing < minimumRaycastSpacing)
            {
                Debug.LogError("Volume raycast spacing cannot be less than: " + minimumRaycastSpacing);
                raycastSpacing = 1;// minimumRaycastSpacing;
            }

            while (itemsEnumerator.MoveNext()) // using a cached enumerator saves 48B allocation
            {
                item = itemsEnumerator.Current.Value;

                if (!item.valid)
                {
                    continue;
                }



                if (!item.isNearObserver)
                {
                    item.gameObject.SetActive(false);
                    continue;
                }
                else
                {
                    if (!item.gameObject.activeInHierarchy)
                    {
                        item.gameObject.SetActive(true);
                    }
                }

                if (item.eventFlagFirstTouch)
                {
                    if (OnItemEnteredWater != null)
                    {
                        OnItemEnteredWater(item);
                    }
                    NotifyOfEntry(item.gameObject);
                }

                if (item.eventFlagFullExit)
                {
                    if (OnItemExitedWater != null)
                    {
                        OnItemExitedWater(item);
                    }
                    NotifyOfExit(item.gameObject);
                }


                if (item.eventFlagCenterTouch)
                {
                    if (OnItemCenterEnteredWater != null)
                    {
                        OnItemCenterEnteredWater(item);
                    }
                }


                if (item.eventFlagCenterExit)
                {
                    if (OnItemCenterExitedWater != null)
                    {
                        OnItemCenterExitedWater(item);
                    }
                }

                if (applyViscosityOnlyAtCenter)
                {
                    if (item.IsInside(item.underWaterCenter))
                    {
                        item.ApplyDragAtPosition(-item.forwardVelocity * dragForceMultiplier, item.position, 0);
                    }
                }

                else
                {
                    for (int i = 0; i < item.viscosityRayCount; i++)
                    {
                        findObjRayStart = item.viscosityRayStartPoints[i];
                        statistics.lastRayCount++;

                        // if (Physics.Raycast(viscoscityRay, out hit, 10.0F, layerMask)) // 35% slower!
                        // use the mask to not see the surface as a shielding obstruction when subject is moving up
                        if (Physics.Raycast(findObjRayStart, -item.forwardVelocityNormalized, out hit, item.width, layerMask))
                        {
                            if (hit.collider.gameObject.GetInstanceID() == itemsEnumerator.Current.Key)
                            {
                                if (item.IsInside(hit.point))
                                {
                                    // Drag is applied against the direction of forward motion
                                    velocityAtPoint = item.rigidbody.GetPointVelocity(hit.point);
                                    item.ApplyDragAtPosition(-velocityAtPoint * dragForceMultiplier, hit.point, i);
                                }
                            }
                        }
                    }
                }

                if (item.underWaterPointCount > 0)
                {
                    if (buoyancy > 0)
                    {
                        item.ApplyBuoyancy();
                    }
                    if (flow != Vector3.zero)
                    {
                        item.rigidbody.AddForceAtPosition(flow, item.underWaterCenter);
                    }
                }
            }


            statistics.raysPerSecondCounter += statistics.lastRayCount;
        }