Exemple #1
0
        /// <summary>
        /// 获取Grid对应的最矮Span
        /// </summary>
        /// <param name="widthIndex"></param>
        /// <param name="depthIndex"></param>
        /// <returns></returns>
        public HeightSpan getData(int widthIndex, int depthIndex)
        {
            HeightSpan retSpan = null;

            mSpans.TryGetValue(GetGridIndex(widthIndex, depthIndex), out retSpan);
            return(retSpan);
        }
Exemple #2
0
            public bool MoveNext()
            {
                if (mNext != null)
                {
                    //下一个的下一个
                    if (mNext.next() != null)
                    {
                        mNext = mNext.next();
                        return(true);
                    }
                    else
                    {
                        //当前列已经没有下一个,移动到下一个Grid
                        mNextWidth++;  //寻找x方向的下一个
                    }
                }

                if (mSoldHeightfield != null)
                {
                    for (int depthIndex = mNextDepth; depthIndex < mSoldHeightfield.depth(); depthIndex++)
                    {
                        for (int widthIndex = mNextWidth; widthIndex < mSoldHeightfield.width(); widthIndex++)
                        {
                            int        gridIndex = mSoldHeightfield.GetGridIndex(widthIndex, depthIndex);
                            HeightSpan span      = mSoldHeightfield.mSpans[gridIndex];

                            if (span != null)
                            {
                                mNext      = span;
                                mNextWidth = widthIndex;
                                mNextDepth = depthIndex;
                                return(true);
                            }
                        }
                        mNextWidth = 0;
                    }
                }

                mNext      = null;
                mNextDepth = -1;
                mNextWidth = -1;

                return(false);
            }
        /// <summary>
        /// 确保垂直方向上两个Span之间的区域不会卡头
        /// </summary>
        /// <param name="field"></param>
        private void markLowHeightSpans(SolidHeightfield field)
        {
            SolidHeightfield.SolidHeightfieldIterator iter = field.GetEnumerator();
            while (iter.MoveNext())
            {
                HeightSpan span = iter.Current;

                if ((span.flags() & SpanFlags.WALKABLE) == 0)
                {
                    continue;
                }

                int spanFloor   = span.max(); //SolidSpan的max,其实就是OpenSpan的底部
                int spanCeiling = (span.next() != null)
                    ? span.next().min() : int.MaxValue;

                if (spanCeiling - spanFloor <= mMinTraversableHeight)
                {
                    span.setFlags(span.flags() & ~SpanFlags.WALKABLE);
                }
            }
        }
 public void setNext( HeightSpan value )
 {
     mNext = value; 
 }
        public OpenHeightfield build(SolidHeightfield sourceField ,
            bool performFullGeneration )
        {
            if( sourceField == null )
            {
                Logger.LogError("[OpenHeightfieldBuilder][build] sourceField null "); 
                return null; 
            }

            OpenHeightfield result = new OpenHeightfield(
                sourceField.boundsMin(),
                sourceField.boundsMax(),
                sourceField.cellSize(),
                sourceField.cellHeight()
                );
            
            for(int depthIndex = 0; depthIndex < sourceField.depth(); depthIndex++)
            {
                for(int widthIndex = 0; widthIndex < sourceField.width(); widthIndex++)
                {
                    OpenHeightSpan baseSpan = null;
                    OpenHeightSpan previousSpan = null;

                    for (HeightSpan span = sourceField.getData(widthIndex, depthIndex);
                         span != null;
                         span = span.next()
                        )
                    {
                        if ( span.flags() != mFilterFlags )
                        {
                            continue; 
                        }

                        //当前Solid Span的max对应的是对应OpenSpan的floor
                        int floor = span.max();  
                        //下一个Next Solid Span的min对应当前OpenSpan的Ceil。
                        int ceiling = (span.next() != null
                            ? span.next().min()
                            : int.MaxValue) ;

                        //对应的Open Span
                        OpenHeightSpan oSpan = new OpenHeightSpan(floor,
                            (ceiling - floor )
                            ); 
                        if( baseSpan == null  )
                        {
                            baseSpan = oSpan; 
                        }
                        if( previousSpan != null )
                        {
                            previousSpan.setNext(oSpan); 
                        }
                        previousSpan = oSpan;
                        result.incrementSpanCount(); 
                    } //for 
                    if( baseSpan != null )
                    {
                        result.addData(widthIndex, depthIndex, baseSpan); 
                    }
                }//for
            } //for

            if( performFullGeneration )
            {
                generateNeighborLinks(result);
                generateDistanceField(result);
                blurDistanceField(result);
                generateRegions(result);  
            }

            return result; 
        }
Exemple #6
0
        /// <summary>
        /// 注意这个添加Span的参数,heightIndexMin和heightIndexMax貌似
        /// 都变成了Span的闭区间
        /// </summary>
        /// <param name="widthIndex"></param>
        /// <param name="depthIndex"></param>
        /// <param name="heightIndexMin"></param>
        /// <param name="heightIndexMax"></param>
        /// <param name="flags"></param>
        /// <returns></returns>
        public bool addData(int widthIndex,
                            int depthIndex,
                            int heightIndexMin,
                            int heightIndexMax,
                            int flags
                            )
        {
            if (widthIndex < 0 ||
                widthIndex >= width() ||
                depthIndex < 0 ||
                depthIndex >= depth())
            {
                Logger.LogWarning("[SolidHeightfield][addData]width|depth|{0}|{1}|{2}|{3}", widthIndex, depthIndex, heightIndexMin, heightIndexMax);
                return(false);
            }


            if (heightIndexMin < 0 ||
                heightIndexMax < 0 ||
                heightIndexMin > heightIndexMax)
            {
                Logger.LogWarning("[SolidHeightfield][addData]heightMin|heightMax|{0}|{1}|{2}|{3}", widthIndex, depthIndex, heightIndexMin, heightIndexMax);
                return(false);
            }


            if (mSpans == null)
            {
                return(false);
            }

            int        gridIndex = GetGridIndex(widthIndex, depthIndex);
            HeightSpan currentSpan;

            if (!mSpans.TryGetValue(gridIndex, out currentSpan))
            {
                mSpans.Add(gridIndex,
                           new HeightSpan(heightIndexMin, heightIndexMax, flags));

                return(true);
            }

            //各种情况的合并
            HeightSpan previousSpan = null;

            while (currentSpan != null)
            {
                //最小比最大还大,不重叠
                //

                /*
                 *
                 *     -  currentMin
                 *     -  heigtMax
                 *     -
                 *     -
                 *     -
                 *     -  heightMin
                 *
                 */
                if (currentSpan.min() > heightIndexMax + 1)   //加1的理由看上图,低闭高开
                {
                    HeightSpan newSpan = new HeightSpan(heightIndexMin, heightIndexMax, flags);
                    newSpan.setNext(currentSpan);   //newSpan更加矮

                    //没有更加矮的了
                    if (previousSpan == null)
                    {
                        //更新最矮的Span
                        mSpans[gridIndex] = newSpan;
                    }
                    else
                    {
                        previousSpan.setNext(newSpan);
                    }
                    return(true);
                }
                //当前Gird对应的最高,比新的最矮还要矮
                else if (currentSpan.max() < heightIndexMin - 1)
                {
                    //这一列只有一个Span
                    if (currentSpan.next() == null)
                    {
                        currentSpan.setNext(
                            new HeightSpan(heightIndexMin, heightIndexMax, flags));
                        return(true);
                    }

                    //这一列还有其它Span,所以要找到插入的点
                    previousSpan = currentSpan;
                    currentSpan  = currentSpan.next();
                }
                //重叠或者刚好邻接
                else
                {
                    /* Case 1:
                     * 新的比当前矮,更新最矮点
                     * 最高点相同,合并可走的标志位
                     */
                    if (heightIndexMin < currentSpan.min())
                    {
                        currentSpan.setMin(heightIndexMin);
                    }

                    if (heightIndexMax == currentSpan.max())
                    {
                        currentSpan.setFlags(currentSpan.flags() | flags);
                        return(true);
                    }

                    /* Case 2:
                     * 最高点没有更新
                     *
                     */
                    if (currentSpan.max() > heightIndexMax)
                    {
                        return(true);
                    }

                    //最高点更高了
                    HeightSpan nextSpan = currentSpan.next();
                    while (true)
                    {
                        //找到第一个刚好比新的最高点高的
                        if (nextSpan == null ||
                            nextSpan.min() > heightIndexMax + 1)
                        {
                            currentSpan.setMax(heightIndexMax);
                            currentSpan.setFlags(flags);

                            if (nextSpan == null)
                            {
                                currentSpan.setNext(null);
                            }
                            else
                            {
                                currentSpan.setNext(nextSpan);
                            }

                            return(true);
                        }

                        //刚好邻接,或者旧的高度更加高
                        if (nextSpan.min() == heightIndexMax + 1 ||
                            heightIndexMax <= nextSpan.max())
                        {
                            //吞并旧的
                            currentSpan.setMax(nextSpan.max());
                            currentSpan.setNext(nextSpan.next());
                            currentSpan.setFlags(nextSpan.flags());

                            if (heightIndexMax == currentSpan.max())
                            {
                                currentSpan.setFlags(currentSpan.flags() | flags);
                                return(true);
                            }
                            return(true);
                        }

                        nextSpan = nextSpan.next();
                    }
                }
            }

            return(false);
        }
Exemple #7
0
 public void Reset()
 {
     mNextWidth = 0;
     mNextDepth = 0;
     mNext      = null;
 }
        /// <summary>
        /// 边缘裁剪,那种像断崖式的Span也不可走的
        /// </summary>
        /// <param name="field"></param>
        private void markLedgeSpans(SolidHeightfield field)
        {
            SolidHeightfield.SolidHeightfieldIterator iter = field.GetEnumerator();
            while (iter.MoveNext())
            {
                HeightSpan span = iter.Current;

                if ((span.flags() & SpanFlags.WALKABLE) == 0)
                {
                    continue;
                }

                int widthIndex = iter.widthIndex();
                int depthIndex = iter.depthIndex();

                int currFloor   = span.max();
                int currCeiling = (span.next() != null)
                    ? span.next().min() : int.MaxValue;


                int minDistanceToNeighbor = int.MaxValue;

                for (int dir = 0; dir < 4; dir++)
                {
                    int nWidthIndex = widthIndex
                                      + BoundeField.getDirOffsetWidth(dir);
                    int nDepthIndex = depthIndex
                                      + BoundeField.getDirOffsetDepth(dir);


                    HeightSpan nSpan = field.getData(nWidthIndex, nDepthIndex);
                    if (null == nSpan)
                    {
                        //TODO 这里没有搞懂为啥是 -mMaxTraversableStep - currFloor,是为了比-mMaxTraversableStep更小,以便直接判断不能行走吗?
                        // 用大可行的距离,再减去currFloor,得到的肯定是一个更小的值。
                        // currFloor - mMaxTraversableStep 是一个最大允许的落差地板距离。注意这里只考虑下落的情况
                        minDistanceToNeighbor = Math.Min(minDistanceToNeighbor, -mMaxTraversableStep - currFloor);
                        continue;
                    }


                    /*
                     *  先考虑一种特殊情况 ,那就是
                     *  那就是nSpan.min也比currFloor要高,那么对应的
                     *  的邻居相当于也是没有Floor的,所以默认取-mMaxTraversableStep吧。
                     */

                    int nFloor   = -mMaxTraversableStep;
                    int nCeiling = nSpan.min();

                    //当前Span所处列的currCeiling和邻居的nCeiling相比,取最低的
                    if (Math.Min(currCeiling, nCeiling) - currFloor > mMinTraversableHeight)
                    {
                        minDistanceToNeighbor = Math.Min(minDistanceToNeighbor, (nFloor - currFloor));
                    }

                    for (nSpan = field.getData(nWidthIndex, nDepthIndex); nSpan != null; nSpan = nSpan.next())
                    {
                        nFloor   = nSpan.max(); //现在才开始用max考虑真正存在的Floor
                        nCeiling = (nSpan.next() != null)
                            ? nSpan.next().min() : int.MaxValue;

                        if (Math.Min(currCeiling, nCeiling) - Math.Max(currFloor, nFloor) > mMinTraversableHeight)
                        {
                            minDistanceToNeighbor = Math.Min(minDistanceToNeighbor, (nFloor - currFloor));
                        }
                    }
                }

                //如果最近的距离比较最大掉落还小的放在,那么就是不可行走的
                if (minDistanceToNeighbor < -mMaxTraversableStep)
                {
                    span.setFlags(span.flags() & ~SpanFlags.WALKABLE);
                }
            }
        }