private void startSearch() { _isSearching = true; _hasPoint = false; _blocks.Clear(); ToClearSearchHistory(); for (int i = 0; i < _investigatedBlocks.Count; i++) { _blockCache.Give(_investigatedBlocks[i]); } _investigatedBlocks.Clear(); _hasPreviousPoint = false; _points.Clear(); GlobalSearchCache.GeneratedPoints.WriteTo(_points); for (int i = 0; i < GlobalSearchCache.GeneratedBlocks.Count; i++) { var block = _blockCache.Take(); GlobalSearchCache.GeneratedBlocks[i].WriteTo(ref block); _blocks.Add(block); } }
/// <summary> /// Rebuilds the search point database. /// </summary> public static void Rebuild() { const float searchRadius = 1000; _isGenerating = true; _currentMergedGeneratedBlockId = 0; _timeAtGenerationStart = Time.timeSinceLevelLoad; for (int i = 0; i < _blocks.Count; i++) { _blockCache.Give(_blocks[i]); } _blocks.Clear(); _usedCovers.Clear(); _points.Clear(); _coverCache.Items.Clear(); _coverCache.Reset(Vector3.zero, searchRadius, false); for (int i = 0; i < _coverCache.Items.Count; i++) { var item = _coverCache.Items[i]; if (_usedCovers.Contains(item.Cover)) { continue; } var cover = item.Cover; var starting = item.Cover; while (cover.LeftAdjacent != null && !_usedCovers.Contains(cover.LeftAdjacent)) { if (cover.LeftAdjacent == starting) { break; } cover = cover.LeftAdjacent; } var index = -1; while (cover != null) { _usedCovers.Add(cover); var left = cover.LeftCorner(cover.Bottom) - cover.Forward * 0.25f; var right = cover.RightCorner(cover.Bottom) - cover.Forward * 0.25f; var vector = right - left; var length = vector.magnitude; var leftApproach = left; var rightApproach = right; { NavMeshHit hit; var position = left + cover.Left * AISearch.CoverOffset; if (NavMesh.Raycast(left, position, out hit, 1)) { leftApproach = left; } else { leftApproach = position; } } { NavMeshHit hit; var position = right + cover.Right * AISearch.CoverOffset; if (NavMesh.Raycast(right, position, out hit, 1)) { rightApproach = right; } else { rightApproach = position; } } if (cover.LeftAdjacent != null && cover.RightAdjacent != null) { leftApproach = left; rightApproach = right; } else if (cover.LeftAdjacent != null) { leftApproach = rightApproach; } else if (cover.RightAdjacent != null) { rightApproach = leftApproach; } possiblyAddRightPoint(ref index, new SearchPoint(left, leftApproach, -cover.Forward, false)); if (length > AISearch.BlockThreshold * 2) { possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.2f, leftApproach, -cover.Forward, false)); possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.4f, leftApproach, -cover.Forward, false)); possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.6f, rightApproach, -cover.Forward, false)); possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.8f, rightApproach, -cover.Forward, false)); } else if (length > AISearch.BlockThreshold) { possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.33f, leftApproach, -cover.Forward, false)); possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.66f, rightApproach, -cover.Forward, false)); } possiblyAddRightPoint(ref index, new SearchPoint(right, rightApproach, -cover.Forward, false)); if (cover.RightAdjacent != null && !_usedCovers.Contains(cover.RightAdjacent)) { cover = cover.RightAdjacent; } else { cover = null; } } } _zoneCache.Reset(Vector3.zero, searchRadius); for (int i = 0; i < _zoneCache.Items.Count; i++) { var block = _zoneCache.Items[i]; foreach (var position in block.Points(AISearch.BlockThreshold)) { addPoint(new SearchPoint(position, false)); } } }
private void Update() { for (int i = _investigated.Count - 1; i >= 0; i--) { if (_investigated[i].Time < Time.timeSinceLevelLoad - MaxInvestigationAge) { _investigated.RemoveAt(i); } } if (!_isSearching) { return; } if (_blocks.Count == 0 && !_hasPoint) { ToClearSearchHistory(); _hasPreviousPoint = false; _points.Clear(); foreach (var block in _investigatedBlocks) { _blockCache.Give(block); } _investigatedBlocks.Clear(); _usedCovers.Clear(); _coverCache.Reset(transform.position, MaxDistance, false); foreach (var item in _coverCache.Items) { if (_usedCovers.Contains(item.Cover)) { continue; } var cover = item.Cover; while (cover.LeftAdjacent != null && !_usedCovers.Contains(cover.LeftAdjacent)) { cover = cover.LeftAdjacent; } var index = -1; while (cover != null) { _usedCovers.Add(cover); var left = cover.LeftCorner(cover.Bottom) - cover.Forward * 0.25f; var right = cover.RightCorner(cover.Bottom) - cover.Forward * 0.25f; var vector = right - left; var length = vector.magnitude; var leftApproach = left; var rightApproach = right; { NavMeshHit hit; var position = left + cover.Left * CoverOffset; if (NavMesh.Raycast(left, position, out hit, 1)) { leftApproach = left; } else { leftApproach = position; } } { NavMeshHit hit; var position = right + cover.Right * CoverOffset; if (NavMesh.Raycast(right, position, out hit, 1)) { rightApproach = right; } else { rightApproach = position; } } if (cover.LeftAdjacent != null && cover.RightAdjacent != null) { leftApproach = left; rightApproach = right; } else if (cover.LeftAdjacent != null) { leftApproach = rightApproach; } else if (cover.RightAdjacent != null) { rightApproach = leftApproach; } possiblyAddRightPoint(ref index, new SearchPoint(left, leftApproach, -cover.Forward, false)); if (length > Advanced.BlockThreshold * 2) { possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.2f, leftApproach, -cover.Forward, false)); possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.4f, leftApproach, -cover.Forward, false)); possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.6f, rightApproach, -cover.Forward, false)); possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.8f, rightApproach, -cover.Forward, false)); } else if (length > Advanced.BlockThreshold) { possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.33f, leftApproach, -cover.Forward, false)); possiblyAddRightPoint(ref index, new SearchPoint(left + vector * 0.66f, rightApproach, -cover.Forward, false)); } possiblyAddRightPoint(ref index, new SearchPoint(right, rightApproach, -cover.Forward, false)); if (cover.RightAdjacent != null && !_usedCovers.Contains(cover.RightAdjacent)) { cover = cover.RightAdjacent; } else { cover = null; } } } _zoneCache.Reset(transform.position, MaxDistance); foreach (var block in _zoneCache.Items) { foreach (var position in block.Points(Advanced.BlockThreshold)) { addPoint(new SearchPoint(position, false)); } } mergeBlocks(); } if (DebugPoints) { foreach (var block in _blocks) { debugBlock(block); } foreach (var block in _investigatedBlocks) { debugBlock(block); } } if (_blocks.Count == 0 && !_hasPoint) { return; } if (_block.Empty && !_hasPoint) { var pickedIndex = -1; var previousValue = 0f; for (int i = 0; i < _blocks.Count; i++) { var vector = _searchPosition - _blocks[i].Center; var distance = vector.magnitude; var direction = vector / distance; var value = distance; if (_hasBlockDirection) { value *= -Vector3.Dot(direction, _blockDirection) * 0.5f + 1.5f; } else { value *= -Vector3.Dot(direction, _actor.HeadDirection) * 0.5f + 1.5f; } if (pickedIndex < 0 || value < previousValue) { pickedIndex = i; previousValue = value; } } if (pickedIndex != -1) { _block = _blocks[pickedIndex]; _blocks.RemoveAt(pickedIndex); _investigatedBlocks.Add(_block); _hasBlockDirection = true; _blockDirection = (_block.Center - _searchPosition).normalized; } } if (!_hasPoint) { int index; float value; findBestPoint(_block, out index, out value); setPoint(_block.Indices[index]); _block.Investigate(index); } if (!_hasApproached && !shouldApproach(_point)) { _hasApproached = true; if (_wasRunning) { run(); } else { walk(); } } if (_wasRunning && !shouldRunTo(_point.Position)) { walk(); } _checkWait -= Time.deltaTime; if (_checkWait <= float.Epsilon) { glimpse(_block); for (int b = _blocks.Count - 1; b >= 0; b--) { glimpse(_blocks[b]); if (_blocks[b].Empty) { _investigatedBlocks.Add(_blocks[b]); _blocks.RemoveAt(b); } } _checkWait = 0.25f; } if (DebugTarget) { Debug.DrawLine(transform.position, _point.Position, Color.yellow); } if (canBeInvestigated(_point)) { var point = new InvestigatedPoint(_point.Position); _hasPoint = false; markInvestigated(point); foreach (var friend in _friends) { friend.considerPoint(point); } } }