public Vector3 Scan(Transform _transform, Vector3 _position, LayerMask _ground_mask, LayerMask _water_mask, float _offset) { if (ScanningRange == 0 || ScanningAngle == 0 || (!UseSlopeLimits && !AvoidWater)) { return(_position); } if (Owner == null) { SetOwner(_transform.gameObject); } RaycastHit _hit; Vector3 _pos = PositionTools.GetDirectionPosition(_transform, 0, ScanningRange); _offset += m_VerticalRaycastOffset + ScanningRange; _pos.y += _offset; if (UseSlipping && MaxSurfaceSlopeAngle > 0) { if (Physics.Raycast(_transform.position + Vector3.up, Vector3.down, out _hit, Mathf.Infinity, _ground_mask, WorldManager.TriggerInteraction)) { if (Mathf.Abs(Vector3.Angle(_hit.normal, Vector3.up)) > MaxSurfaceSlopeAngle) { m_SlopePathPosition = Vector3.zero; _transform.position += new Vector3(_hit.normal.x * 9.8f * Time.deltaTime, 0, _hit.normal.z * 9.8f * Time.deltaTime); return(_position); } } } if (m_SlopePathPosition == Vector3.zero || PositionTools.Distance(_transform.position, m_SlopePathPosition) < ScanningRange * 0.25f) { LayerMask _combined_mask = _ground_mask; if (_water_mask.value != 0) { _combined_mask |= _water_mask; } if (Physics.Raycast(_pos, Vector3.down, out _hit, Mathf.Infinity, _combined_mask, WorldManager.TriggerInteraction)) { Vector3 _dir = (_hit.point - _transform.position).normalized; float _path_angle = Vector3.Angle(_dir, Vector3.down) - 90; float _surface_angle = Vector3.Angle(_hit.normal, Vector3.up); if ((MaxSurfaceSlopeAngle > 0 && Mathf.Abs(_surface_angle) > MaxSurfaceSlopeAngle) || (MaxPathSlopeAngle > 0 && Mathf.Abs(_path_angle) > MaxPathSlopeAngle) || (AvoidWater && SystemTools.IsInLayerMask(_hit.transform.gameObject, _water_mask))) { DebugLine(_hit.point, _hit.point + (Vector3.up * 2), Color.yellow); for (int i = ScanningAngle; i <= 180; i += ScanningAngle) { Vector3 _pos_right = Vector3.zero; Vector3 _pos_left = Vector3.zero; int _right_angle = i; _pos = PositionTools.GetDirectionPosition(_transform, _right_angle, ScanningRange); _pos.y += _offset; if (Physics.Raycast(_pos, Vector3.down, out _hit, Mathf.Infinity, _combined_mask, WorldManager.TriggerInteraction)) { _dir = (_hit.point - _transform.position).normalized; _path_angle = Vector3.Angle(_dir, Vector3.down) - 90; _surface_angle = Vector3.Angle(_hit.normal, Vector3.up); bool _walkable_right = true; bool _water = false; if (MaxSurfaceSlopeAngle > 0 && Mathf.Abs(_surface_angle) > MaxSurfaceSlopeAngle) { _walkable_right = false; } if (MaxPathSlopeAngle > 0 && _walkable_right && Mathf.Abs(_path_angle) > MaxPathSlopeAngle) { _walkable_right = false; } if (AvoidWater && SystemTools.IsInLayerMask(_hit.transform.gameObject, _water_mask)) { _walkable_right = false; _water = true; } if (DebugRayIsEnabled) { float _h = (MaxPathSlopeAngle > 0 ? MathTools.Normalize(MaxPathSlopeAngle - Mathf.Abs(_path_angle), 0, MaxPathSlopeAngle) : MathTools.Normalize(MaxSurfaceSlopeAngle - _surface_angle, 0, MaxSurfaceSlopeAngle)); //DebugLine( _pos, _hit.point, ( _water ? Color.blue : ( _walkable_right ? Color.green : new HSBColor( _h * 0.3333333f, 1f, 1f ).ToColor() ) ) ); DebugLine(_hit.point, _hit.point + (Vector3.up * 2), (_water ? Color.blue : (_walkable_right ? Color.green : new HSBColor(_h * 0.3333333f, 1f, 1f).ToColor()))); } if (_walkable_right) { _pos_right = _hit.point; } } else { m_VerticalRaycastOffset += 0.25f; } int _left_angle = 360 - i; _pos = PositionTools.GetDirectionPosition(_transform, _left_angle, ScanningRange); _pos.y += _offset; if (Physics.Raycast(_pos, Vector3.down, out _hit, Mathf.Infinity, _combined_mask, WorldManager.TriggerInteraction)) { _dir = (_hit.point - _transform.position).normalized; _path_angle = Vector3.Angle(_dir, Vector3.down) - 90; _surface_angle = Vector3.Angle(_hit.normal, Vector3.up); bool _walkable_left = true; bool _water = false; if (MaxSurfaceSlopeAngle > 0 && Mathf.Abs(_surface_angle) > MaxSurfaceSlopeAngle) { _walkable_left = false; } if (MaxPathSlopeAngle > 0 && _walkable_left && Mathf.Abs(_path_angle) > MaxPathSlopeAngle) { _walkable_left = false; } if (AvoidWater && SystemTools.IsInLayerMask(_hit.transform.gameObject, _water_mask)) { _walkable_left = false; _water = true; } if (DebugRayIsEnabled) { float _h = (MaxPathSlopeAngle > 0 ? MathTools.Normalize(MaxPathSlopeAngle - Mathf.Abs(_path_angle), 0, MaxPathSlopeAngle) : MathTools.Normalize(MaxSurfaceSlopeAngle - _surface_angle, 0, MaxSurfaceSlopeAngle)); //DebugLine( _pos, _hit.point, ( _water ? Color.blue : ( _walkable_left ? Color.green : new HSBColor( _h * 0.3333333f, 1f, 0.25f ).ToColor() ) ) ); DebugLine(_hit.point, _hit.point + (Vector3.up * 2), (_water ? Color.blue : (_walkable_left ? Color.green : new HSBColor(_h * 0.3333333f, 1f, 1f).ToColor()))); } if (_walkable_left) { _pos_left = _hit.point; } } else { m_VerticalRaycastOffset += 0.25f; } if (_pos_right != Vector3.zero && _pos_left != Vector3.zero) { //if( Vector3.Distance( _position, _pos_right ) <= Vector3.Distance( _position, _pos_left ) ) if (UnityEngine.Random.Range(0, 2) == 0) { m_SlopePathPosition = _pos_right; } else { m_SlopePathPosition = _pos_left; } break; } else if (_pos_right != Vector3.zero) { m_SlopePathPosition = _pos_right; break; } else if (_pos_left != Vector3.zero) { m_SlopePathPosition = _pos_left; break; } } } else { m_SlopePathPosition = Vector3.zero; if (DebugRayIsEnabled) { float _h = (MaxPathSlopeAngle > 0 ? MathTools.Normalize(MaxPathSlopeAngle - Mathf.Abs(_path_angle), 0, MaxPathSlopeAngle) : MathTools.Normalize(MaxSurfaceSlopeAngle - _surface_angle, 0, MaxSurfaceSlopeAngle)); DebugLine(_pos, _hit.point + (Vector3.up * 2), new HSBColor(_h * 0.3333333f, 1f, 0.25f).ToColor()); DebugLine(_hit.point, _hit.point + (Vector3.up * 2), new HSBColor(_h * 0.3333333f, 1f, 1f).ToColor()); } } } else { m_VerticalRaycastOffset += 0.25f; } } if (m_SlopePathPosition != Vector3.zero) { DebugLine(m_SlopePathPosition, m_SlopePathPosition + (Vector3.up * 2), Color.green); _position = m_SlopePathPosition; } return(_position); }
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); }