public void generateNeighborLinks(OpenHeightfield field) { if( field == null ) { Logger.LogError("[OpenHeightfieldBuilder][generateNeighborLinks]field Empty"); return; } OpenHeightfield.OpenHeightFieldIterator iter = field.GetEnumerator(); while( iter.MoveNext() ) { OpenHeightSpan span = iter.Current; for(int dir = 0; dir < 4; ++dir) { //邻居的GirdIndex int nWidthIndex = (iter.widthIndex() + BoundeField.getDirOffsetWidth(dir)); int nDepthIndex = (iter.depthIndex() + BoundeField.getDirOffsetDepth(dir)); for(OpenHeightSpan nSpan = field.getData(nWidthIndex,nDepthIndex); nSpan != null; nSpan = nSpan.next()) { int maxFloor = Math.Max(span.floor(), nSpan.floor()); int minCeling = Math.Min(span.ceiling(), nSpan.ceiling()); if( (minCeling - maxFloor) >= mMinTraversableHeight //邻居之间的通道足够高,可以通过 && Math.Abs(nSpan.floor() - span.floor()) <= mMaxTraversableStep ) //两邻居之间的落差足够小 { span.setNeighbor(dir, nSpan); break; } } } } }
public bool MoveNext() { if (mOpenHeightfield == null) { Logger.LogError("[OpenHeightfield][OpenHeightFieldIterator][MoveNext]Null"); return(false); } //公有逻辑 if (mNext != null) { if (mNext.next() != null) { mNext = mNext.next(); return(true); } else { if (mIsReverseIter) { mNextWidth--; } else { mNextWidth++; } } } if (mIsReverseIter) { #region 反向遍历 for (int depthIndex = mNextDepth; depthIndex >= 0; --depthIndex) { for (int widthIndex = mNextWidth; widthIndex >= 0; --widthIndex) { OpenHeightSpan span = mOpenHeightfield.getData(widthIndex, depthIndex); if (span != null) { mNext = span; mNextWidth = widthIndex; mNextDepth = depthIndex; return(true); } } mNextWidth = 0; } mNext = null; mNextDepth = -1; mNextWidth = -1; return(false); #endregion } else { #region 正向遍历 for (int depthIndex = mNextDepth; depthIndex < mOpenHeightfield.depth(); ++depthIndex) { for (int widthIndex = mNextWidth; widthIndex < mOpenHeightfield.width(); widthIndex++) { OpenHeightSpan span = mOpenHeightfield.getData(widthIndex, depthIndex); if (span != null) { mNext = span; mNextWidth = widthIndex; mNextDepth = depthIndex; return(true); } } mNextWidth = 0; } mNext = null; mNextDepth = -1; mNextWidth = -1; return(false); #endregion } // if-else } // MoveNext
public void apply(OpenHeightfield field) { if (null == field) { Logger.LogError("[FilterOutSmallRegions][apply]field null"); return; } if (field.regionCount() < 2) { Logger.LogError("[FilterOutSmallRegions][apply]RegionCnt|{0}", field.regionCount()); return; } //PS:索引即是对应的ID Region[] regions = new Region[field.regionCount()]; for (int i = 0; i < field.regionCount(); ++i) { regions[i] = new Region(i); } #region 收集邻接信息 OpenHeightfield.OpenHeightFieldIterator iter = field.GetEnumerator(); while (iter.MoveNext()) { OpenHeightSpan span = iter.Current; if (span.regionID() <= NULL_REGION) { continue; } //索引即RegionID Region region = regions[span.regionID()]; region.spanCount++; for (OpenHeightSpan nextHigherSpan = span.next(); nextHigherSpan != null; nextHigherSpan = nextHigherSpan.next() ) { int nextHigherSpanRegionID = nextHigherSpan.regionID(); if (nextHigherSpanRegionID <= NULL_REGION) { continue; } //因为是同属一个Grid的,所以肯定是重叠的 if (!region.overlappingRegions.Contains(nextHigherSpanRegionID)) { region.overlappingRegions.Add(nextHigherSpanRegionID); } } //for if (region.connections.Count > 0) { continue; } int edgeDirection = getRegionEdgeDirection(span); if (edgeDirection != -1) { findRegionConnections(span, edgeDirection, ref region.connections); } } // while #endregion #region 清理孤岛Region for (int regionID = 1; regionID < field.regionCount(); ++regionID) { Region region = regions[regionID]; if (0 == region.spanCount) { continue; } // 有且仅有一个 Null Region 邻居 if (region.connections.Count == 1 && region.connections[0] == NULL_REGION) { if (region.spanCount < mMinUnconnectedRegionSize) { region.resetWithID(0); } } } //for #endregion #region 合并小的Region int mergeCount; do { mergeCount = 0; foreach (Region region in regions) { if (region.id <= NULL_REGION || region.spanCount == 0) { continue; } if (region.spanCount > mMergeRegionSize) { continue; } Region targetMergeRegion = null; int smallestSizeFound = int.MaxValue; foreach (int nRegionID in region.connections) { if (nRegionID <= 0) { continue; } Region nRegion = regions[nRegionID]; if (nRegion.spanCount < smallestSizeFound && canMerge(region, nRegion)) { targetMergeRegion = nRegion; smallestSizeFound = nRegion.spanCount; } } // foreach nRegionID if (targetMergeRegion != null && mergeRegions(targetMergeRegion, region)) //为啥是反过来Merge。。。 { int oldRegionID = region.id; region.resetWithID(targetMergeRegion.id); foreach (Region r in regions) { if (r.id <= NULL_REGION) { continue; } if (r.id == oldRegionID) { r.id = targetMergeRegion.id; } else { replaceNeighborRegionID(r, oldRegionID, targetMergeRegion.id); } } // foreach regions mergeCount++; } // if mergerRegion } // foreach region } while (mergeCount > 0); #endregion #region re-map 区域ID,保持ID连接 foreach (Region region in regions) { if (region.id >= NULL_REGION) { region.remap = true; } } int currRegionID = NULL_REGION; foreach (Region region in regions) { if (!region.remap) { continue; } currRegionID++; int oldID = region.id; foreach (Region r in regions) { if (r.id == oldID) { r.id = currRegionID; r.remap = false; } } //foreach } //foreach field.setRegionCount(currRegionID + 1); iter.Reset(); while (iter.MoveNext()) { OpenHeightSpan span = iter.Current; if (NULL_REGION == span.regionID()) { continue; } else { //真正re-map一下 span.setRegionID(regions[span.regionID()].id); } } #endregion } //apply