Ejemplo n.º 1
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);
        }