protected override Vector3 CalculateEndPosition(ref Vector3 anchorPosition, ref Vector3 start, bool intense)
        {
            Vector3 dir = (start + UnityEngine.Random.insideUnitSphere).normalized;

            dir.y = -Mathf.Abs(dir.y);
            dir.z = 0.0f;

            RaycastHit2D h;

            if (UnityEngine.Random.Range(0.0f, 1.0f) >= GroundLightningChance ||
                ((h = Physics2D.Raycast(start, dir)).collider == null))
            {
                Vector3 visibleMin, visibleMax;
                float   width, height;
                CalculateVisibleBounds(out visibleMin, out visibleMax, out width, out height);
                float   maxDimen = Mathf.Max(width, height);
                float   variance = Mathf.Max(maxDimen * 0.25f, maxDimen * UnityEngine.Random.Range(EndYVariance.Minimum, EndYVariance.Maximum));
                Vector3 end      = start + (dir * variance);
                end.x += (width * EndXVariance.Random());
                end.y += (height * EndYVariance.Random());
                end.z  = 0.0f;

                return(end);
            }

            return(h.point);
        }
        /// <summary>
        /// Compute end position
        /// </summary>
        /// <param name="anchorPosition">Anchor position</param>
        /// <param name="start">Start position</param>
        /// <param name="visibleInCamera">Camera to show in, can be null</param>
        /// <param name="intense">Intense (close) or normal (far)</param>
        /// <returns>End position</returns>
        protected override Vector3 CalculateEndPosition(ref Vector3 anchorPosition, ref Vector3 start, Camera visibleInCamera, bool intense)
        {
            Vector3 dir;

            dir.x = EndXVariance.Random();
            dir.y = -1.0f;
            dir.z = EndZVariance.Random();
            dir   = dir.normalized;

            RaycastHit2D h;

            if (UnityEngine.Random.Range(0.0f, 1.0f) <= GroundLightningChance ||
                ((h = Physics2D.Raycast(start, dir)).collider == null))
            {
                Vector3 visibleMin, visibleMax;
                float   width, height;
                CalculateVisibleBounds(out visibleMin, out visibleMax, out width, out height);
                float   maxDimen = Mathf.Max(width, height);
                float   variance = maxDimen * EndYVariance.Random();
                Vector3 end      = start + (dir * variance);
                return(end);
            }
            else
            {
                // lightning hit the ground
                return(h.point);
            }
        }
        /// <summary>
        /// Compute end position
        /// </summary>
        /// <param name="anchorPosition">Anchor position</param>
        /// <param name="start">Start position</param>
        /// <param name="visibleInCamera">Camera to show in, can be null</param>
        /// <param name="intense">Intense (close) or normal (far)</param>
        /// <returns>End position</returns>
        protected override Vector3 CalculateEndPosition(ref Vector3 anchorPosition, ref Vector3 start, Camera visibleInCamera, bool intense)
        {
            Vector3    end = start;
            Vector3    dir;
            bool       noGround    = UnityEngine.Random.Range(0.0f, 1.0f) > GroundLightningChance;
            float      minDistance = (intense ? IntenseDistance.Minimum : NormalDistance.Minimum);
            RaycastHit hit;

            // determine if we should strike the ground
            if (noGround)
            {
                end.y += EndYVariance.Random();
            }
            else if (Physics.Raycast(start, Vector3.down, out hit))
            {
                end.y = Mathf.Max(-10.0f, hit.point.y - 10.0f);
            }
            else
            {
                // strike ground, raycast will get actual ground point
                end.y = -10.0f;
            }

            if (visibleInCamera == null)
            {
                end.x = start.x + EndXVariance.Random();
                end.z = start.z + EndZVariance.Random();
            }
            else
            {
                end += (visibleInCamera.transform.right * EndXVariance.Random());
                end += (visibleInCamera.transform.forward * EndZVariance.Random());
            }

            dir = (end - start).normalized;

            // if the end is too close to the anchor point, push it back
            if (Vector3.Distance(anchorPosition, end) < minDistance || (visibleInCamera != null && Vector3.Dot(dir, visibleInCamera.transform.forward) > 0.1f))
            {
                if (visibleInCamera == null)
                {
                    dir = (end - anchorPosition).normalized;
                }
                else
                {
                    dir = visibleInCamera.transform.forward;
                }
                dir = dir.normalized;
                end = anchorPosition + (dir * minDistance);
            }

            // see if the bolt hit anything on it's way to the ground - if so, change the end point
            if (Physics.Raycast(start, dir, out hit, Vector3.Distance(start, end) * 1.05f))
            {
                end = hit.point;
            }

            return(end);
        }
        protected override Vector3 CalculateEndPosition(ref Vector3 anchorPosition, ref Vector3 start, bool intense)
        {
            Vector3 end;

            // determine if we should strike the ground
            if (UnityEngine.Random.Range(0.0f, 1.0f) > GroundLightningChance)
            {
                end.y = start.y + EndYVariance.Random();
            }
            else
            {
                end.y = -100.0f;
            }

            end.x = start.x + EndXVariance.Random();
            end.z = start.z + EndZVariance.Random();

            // see if the bolt hit anything on it's way to the ground - if so, change the end point
            RaycastHit hit;

            if (Physics.Raycast(start, (start - end).normalized, out hit, float.MaxValue))
            {
                end = hit.point;
            }

            // if the end is too close to the anchor point, push it back
            float minDistance = (intense ? IntenseDistance.Minimum : NormalDistance.Minimum);

            if (Vector3.Distance(anchorPosition, end) < minDistance)
            {
                Vector3 endDir = (end - anchorPosition).normalized;
                end = anchorPosition + (endDir * minDistance);
            }

            return(end);
        }