public Vector3 Scan(Transform _transform, Vector3 _position, LayerMask _mask, float _stopping_distance, float _speed) { if ((!UseDynamicScanningRange && ScanningRange == 0) || (UseDynamicScanningRange && _speed == 0)) { return(_position); } if (Time.time - m_StartTime <= m_ExpectedActionTime) { return(_position); } m_ActionType = ObstacleAvoidanceActionType.None; m_StoppingDistance = _stopping_distance; if (Owner != _transform.gameObject) { SetOwner(_transform.gameObject); } float _vertical_offset = 0; Vector3 _avoid_position = _position; Vector3 _transform_pos = _transform.position; Vector3 _move_pos = _position; float _distance = (UseDynamicScanningRange ? _speed * DynamicScanningRangeSpeedMultiplier : ScanningRange); _transform_pos.y = _transform_pos.y + _vertical_offset; _move_pos.y = _transform_pos.y; RaycastHit _hit; RaycastHit _hit_up = new RaycastHit(); RaycastHit _hit_down = new RaycastHit(); Vector3 _desired_dir = _position - _transform.position; Vector3 _origin = _transform.position + (_transform.up * VerticalRaycastOffset); Vector3 _origin_up = _transform.position + (_transform.up * (VerticalRaycastOffset + VerticalRaycastOffsetDifference)); // TODO : slide height Vector3 _origin_down = _transform.position + (_transform.up * (VerticalRaycastOffset - VerticalRaycastOffsetDifference)); // TODO : slide height Vector3 _forward = _transform.forward; float _cross_down_distance = (UseCrossBelowSpeed ? _speed * CrossBelowStartDistanceSpeedMultiplier : CrossBelowStartDistance); float _cross_up_distance = (UseCrossOverSpeed ? _speed * CrossOverStartDistanceSpeedMultiplier : CrossOverStartDistance); float _hit_down_distance = Mathf.Infinity; float _hit_up_distance = Mathf.Infinity; m_CrossBelowPossible = false; m_CrossOverPossible = false; if (UseOvercomeObstacles && Physics.Raycast(_origin_down, _forward, out _hit_down, _distance, _mask, WorldManager.TriggerInteraction) && !_hit_down.transform.IsChildOf(_transform)) { DebugLine(_origin_down, _hit_down.point, Color.red); DebugRay(_origin_down, _forward * _cross_down_distance, Color.blue); _hit_down_distance = _hit_down.distance; m_CrossBelowPossible = true; } else if (UseOvercomeObstacles) { DebugRay(_origin_down, _forward * _distance, Color.green); } if (UseOvercomeObstacles && Physics.Raycast(_origin_up, _forward, out _hit_up, _distance, _mask, WorldManager.TriggerInteraction) && !_hit_up.transform.IsChildOf(_transform)) { DebugLine(_origin_up, _hit_up.point, Color.red); DebugRay(_origin_up, _forward * _cross_up_distance, Color.blue); _hit_up_distance = _hit_up.distance; m_CrossOverPossible = true; } else if (UseOvercomeObstacles) { DebugRay(_origin_up, _forward * _distance, Color.green); } // CHECK POSIBLE CROSS OVER if (UseOvercomeObstacles && _hit_down_distance < _hit_up_distance) { if (_hit_down.distance < _cross_up_distance) { m_DesiredCrossOverPosition = _hit_down.point; m_DesiredCrossOverPosition.y = _hit_down.collider.bounds.center.y + 0.5f * Owner.GetComponent <Collider>().bounds.extents.y + 0.075f; m_StartTime = Time.time; m_ExpectedActionTime = _cross_up_distance * 2 / (_speed > 0 ? _speed : 1); m_ActionType = ObstacleAvoidanceActionType.CrossOver; } } // CHECK POSIBLE CROSS BELOW else if (UseOvercomeObstacles && _hit_up_distance < _hit_down_distance) { if (_hit_up.distance < _cross_down_distance) { m_DesiredCrossBelowPosition = _position + (1.25f * _hit_up.distance * _forward); m_StartTime = Time.time; m_ExpectedActionTime = _cross_down_distance * 2 / (_speed > 0 ? _speed : 1); m_ActionType = ObstacleAvoidanceActionType.CrossBelow; } } // CHECK AVOIDANCE else if (Physics.Raycast(_origin, _forward, out _hit, _distance, _mask, WorldManager.TriggerInteraction)) { if (!_hit.transform.IsChildOf(_transform)) { DebugLine(_origin, _hit.point, Color.red); if (_desired_dir.magnitude < PositionTools.Distance(_hit.point, _transform.position)) { DebugLine(_origin, _desired_dir, Color.green); m_ObstacleAvoidancePosition = Vector3.zero; m_FixDirection = PreferedDirectionType.UNDEFINED; } else { if (_distance > _hit.collider.bounds.size.magnitude * 0.5f) { _distance = _hit.collider.bounds.size.magnitude * 0.5f; } else if (_distance > new Vector2(_hit.collider.bounds.size.z, _hit.collider.bounds.size.x).magnitude) { _distance = new Vector2(_hit.collider.bounds.size.z, _hit.collider.bounds.size.x).magnitude; } DebugLine(_origin, _hit.point, Color.red); int _cost_right = 0; Vector3 _avoid_right = Vector3.zero; for (int i = ScanningAngle; i <= 360; i += ScanningAngle) { _cost_right++; Vector3 _pos = PositionTools.GetDirectionPosition(_transform, i, _distance); if (!Physics.Linecast(_origin, _pos, _mask)) { _avoid_right = _pos; DebugLine(_origin, _pos, SystemTools.ColorA(Color.blue, 0.5f)); break; } else { //TODO: if there is no free position we could determinate the best posibility DebugLine(_origin, _pos, SystemTools.ColorA(Color.red, 0.25f)); } } int _cost_left = 0; Vector3 _avoid_left = Vector3.zero; for (int i = 360 - ScanningAngle; i > 0; i -= ScanningAngle) { _cost_left++; Vector3 _pos = PositionTools.GetDirectionPosition(_transform, i, _distance); if (!Physics.Linecast(_origin, _pos, _mask)) { _avoid_left = _pos; DebugLine(_origin, _pos, SystemTools.ColorA(Color.blue, 0.5f)); break; } else { //TODO: if there is no free position we could determinate the best posibility DebugLine(_origin, _pos, SystemTools.ColorA(Color.red, 0.25f)); } } // selects the best solution according to the given costs if (_avoid_right != Vector3.zero && _avoid_left != Vector3.zero) { if (_cost_left < _cost_right) { m_ObstacleAvoidancePosition = _avoid_left; } else if (_cost_right < _cost_left) { m_ObstacleAvoidancePosition = _avoid_right; } else { m_ObstacleAvoidancePosition = (Random.Range(0, 1) == 1 ? _avoid_left : _avoid_right); } } else if (_avoid_right != Vector3.zero) { m_ObstacleAvoidancePosition = _avoid_right; } else if (_avoid_left != Vector3.zero) { m_ObstacleAvoidancePosition = _avoid_left; } // makes sure that the creature will not change the direction if not needed if (UseFixDirection) { if (m_FixDirection == PreferedDirectionType.UNDEFINED) { if (m_ObstacleAvoidancePosition == _avoid_right) { m_FixDirection = PreferedDirectionType.RIGHT; } else if (m_ObstacleAvoidancePosition == _avoid_left) { m_FixDirection = PreferedDirectionType.LEFT; } } else if (m_FixDirection == PreferedDirectionType.RIGHT && _avoid_right != Vector3.zero) { m_ObstacleAvoidancePosition = _avoid_right; } else if (m_FixDirection == PreferedDirectionType.LEFT && _avoid_left != Vector3.zero) { m_ObstacleAvoidancePosition = _avoid_left; } } } } } else { DebugRay(_origin, _forward * _distance, Color.green); m_FixDirection = PreferedDirectionType.UNDEFINED; if (Physics.Raycast(_origin, _desired_dir, out _hit, _distance, _mask, WorldManager.TriggerInteraction)) { DebugLine(_origin, _hit.point, SystemTools.ColorA(Color.red, MathTools.Normalize(_distance - PositionTools.Distance(_hit.point, _origin), 0, _distance))); if (AvoidanceMovePositionReached) { m_ObstacleAvoidancePosition = _transform.position + (_transform.forward * _distance); } } else { DebugRay(_origin, _desired_dir.normalized * _distance, Color.gray); m_ObstacleAvoidancePosition = Vector3.zero; } } if (m_ObstacleAvoidancePosition != Vector3.zero) { _avoid_position = m_ObstacleAvoidancePosition; } return(_avoid_position); }