Пример #1
0
        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);
        }
Пример #2
0
        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);
        }