Max() public static method

public static Max ( ) : float
return float
コード例 #1
0
        static Bounds GetBounds(PF.Vector3[] points, Vector3 right, Vector3 up, Vector3 forward, Vector3 origin, float minimumHeight)
        {
            if (points == null || points.Length == 0)
            {
                return(new Bounds());
            }
            float miny = points[0].y, maxy = points[0].y;

            for (int i = 0; i < points.Length; i++)
            {
                miny = Mathf.Min(miny, points[i].y);
                maxy = Mathf.Max(maxy, points[i].y);
            }
            var extraHeight = Mathf.Max(minimumHeight - (maxy - miny), 0) * 0.5f;

            miny -= extraHeight;
            maxy += extraHeight;

            Vector3 min = right * points[0].x + up * points[0].y + forward * points[0].z;
            Vector3 max = min;

            for (int i = 0; i < points.Length; i++)
            {
                var p  = right * points[i].x + forward * points[i].z;
                var p1 = p + up * miny;
                var p2 = p + up * maxy;
                min = Vector3.Min(min, p1);
                min = Vector3.Min(min, p2);
                max = Vector3.Max(max, p1);
                max = Vector3.Max(max, p2);
            }
            return(new Bounds((min + max) * 0.5F + origin, max - min));
        }
コード例 #2
0
        /** Bias towards the right side of agents.
         * Rotate desiredVelocity at most [value] number of radians. 1 radian ≈ 57°
         * This breaks up symmetries.
         *
         * The desired velocity will only be rotated if it is inside a velocity obstacle (VO).
         * If it is inside one, it will not be rotated further than to the edge of it
         *
         * The targetPointInVelocitySpace will be rotated by the same amount as the desired velocity
         *
         * \returns True if the desired velocity was inside any VO
         */
        static bool BiasDesiredVelocity(VOBuffer vos, ref Vector2 desiredVelocity, ref Vector2 targetPointInVelocitySpace, float maxBiasRadians)
        {
            var desiredVelocityMagn = desiredVelocity.magnitude;
            var maxValue            = 0f;

            for (int i = 0; i < vos.length; i++)
            {
                float value;
                // The value is approximately the distance to the edge of the VO
                // so taking the maximum will give us the distance to the edge of the VO
                // which the desired velocity is furthest inside
                vos.buffer[i].Gradient(desiredVelocity, out value);
                maxValue = Mathf.Max(maxValue, value);
            }

            // Check if the agent was inside any VO
            var inside = maxValue > 0;

            // Avoid division by zero below
            if (desiredVelocityMagn < 0.001f)
            {
                return(inside);
            }

            // Rotate the desired velocity clockwise (to the right) at most maxBiasRadians number of radians
            // Assuming maxBiasRadians is small, we can just move it instead and it will give approximately the same effect
            // See https://en.wikipedia.org/wiki/Small-angle_approximation
            var angle = Mathf.Min(maxBiasRadians, maxValue / desiredVelocityMagn);

            desiredVelocity            += new Vector2(desiredVelocity.y, -desiredVelocity.x) * angle;
            targetPointInVelocitySpace += new Vector2(targetPointInVelocitySpace.y, -targetPointInVelocitySpace.x) * angle;
            return(inside);
        }
コード例 #3
0
#pragma warning restore 414

    KMSelectable[] ProcessTwitchCommand(string command)
    {
        command = command.ToLowerInvariant().Trim();

        if (Regex.IsMatch(command, @"^press +[0-9^, |&]+$"))
        {
            command = command.Substring(6).Trim();

            var presses   = command.Split(new[] { ',', ' ', '|', '&' }, StringSplitOptions.RemoveEmptyEntries);
            var pressList = new List <KMSelectable>();

            for (var i = 0; i < presses.Length; i++)
            {
                if (Regex.IsMatch(presses[i], @"^[0-9]{1,2}$"))
                {
                    pressList.Add(ModuleButtons[Math.Clamp(Math.Max(1, int.Parse(presses[i].ToString())) - 1, 0, ModuleButtons.Length - 1)]);
                }
            }

            return(pressList.ToArray());
        }

        if (Regex.IsMatch(command, @"^(submit|sub|s)$"))
        {
            return new[] { SubmitButton }
        }
        ;

        return(null);
    }
}
コード例 #4
0
        protected virtual void CalculateNextRotation(float slowdown, out Quaternion nextRotation)
        {
            if (lastDeltaTime > 0.00001f)
            {
                Vector2 desiredRotationDirection;
                if (rvoController != null && rvoController.enabled)
                {
                    // When using local avoidance, use the actual velocity we are moving with if that velocity
                    // is high enough, otherwise fall back to the velocity that we want to move with (velocity2D).
                    // The local avoidance velocity can be very jittery when the character is close to standing still
                    // as it constantly makes small corrections. We do not want the rotation of the character to be jittery.
                    var actualVelocity = lastDeltaPosition / lastDeltaTime;
                    desiredRotationDirection = Vector2.Lerp(velocity2D, actualVelocity, 4 * actualVelocity.magnitude / (maxSpeed + 0.0001f));
                }
                else
                {
                    desiredRotationDirection = velocity2D;
                }

                // Rotate towards the direction we are moving in.
                // Don't rotate when we are very close to the target.
                var currentRotationSpeed = rotationSpeed * Mathf.Max(0, (slowdown - 0.3f) / 0.7f);
                nextRotation = SimulateRotationTowards(desiredRotationDirection, currentRotationSpeed * lastDeltaTime);
            }
            else
            {
                // TODO: simulatedRotation
                nextRotation = rotation;
            }
        }
コード例 #5
0
ファイル: AILerp.cs プロジェクト: pinzeweifen/DCET
        /** Finds the closest point on the current path and configures the #interpolator */
        protected virtual void ConfigureNewPath()
        {
            var hadValidPath = interpolator.valid;
            var prevTangent  = hadValidPath ? interpolator.tangent : Vector3.zero;

            interpolator.SetPath(path.vectorPath);
            interpolator.MoveToClosestPoint(GetFeetPosition());

            if (interpolatePathSwitches && switchPathInterpolationSpeed > 0.01f && hadValidPath)
            {
                var correctionFactor = Mathf.Max(-Vector3.Dot(prevTangent.normalized, interpolator.tangent.normalized), 0);
                interpolator.distance -= speed * correctionFactor * (1f / switchPathInterpolationSpeed);
            }
        }
コード例 #6
0
        public void Validate()
        {
            if (surfaceDefinition == null)
            {
                surfaceDefinition = new ChiselSurfaceDefinition();
            }

            curveSegments   = Mathf.Max(curveSegments, 2);
            revolveSegments = Mathf.Max(revolveSegments, 1);

            totalAngle = Mathf.Clamp(totalAngle, 1, 360);                  // TODO: constants

            surfaceDefinition.EnsureSize(6);
        }
コード例 #7
0
        /** Traces the vector field constructed out of the velocity obstacles.
         * Returns the position which gives the minimum score (approximately).
         *
         * \see https://en.wikipedia.org/wiki/Gradient_descent
         */
        Vector2 Trace(VOBuffer vos, Vector2 p, out float score)
        {
            // Pick a reasonable initial step size
            float stepSize = Mathf.Max(radius, 0.2f * desiredSpeed);

            float   bestScore = float.PositiveInfinity;
            Vector2 bestP     = p;

            // TODO: Add momentum to speed up convergence?

            const int MaxIterations = 50;

            for (int s = 0; s < MaxIterations; s++)
            {
                float step = 1.0f - (s / (float)MaxIterations);
                step = Sqr(step) * stepSize;

                float value;
                var   gradient = EvaluateGradient(vos, p, out value);

                if (value < bestScore)
                {
                    bestScore = value;
                    bestP     = p;
                }

                // TODO: Add cutoff for performance

                gradient.Normalize();

                gradient *= step;
                Vector2 prev = p;
                p += gradient;

                if (DebugDraw)
                {
                    Debug.DrawLine(FromXZ(prev + position), FromXZ(p + position), Rainbow(s * 0.1f) * new Color(1, 1, 1, 1f));
                }
            }

            score = bestScore;
            return(bestP);
        }
コード例 #8
0
        void Tick()
        {
            if (Event.current.type == EventType.Repaint)
            {
                float deltaTime = Time.realtimeSinceStartup - lastUpdate;

                // Right at the start of a transition the deltaTime will
                // not be reliable, so use a very small value instead
                // until the next repaint
                if (value == 0f || value == 1f)
                {
                    deltaTime = 0.001f;
                }
                deltaTime = Mathf.Clamp(deltaTime, 0.00001F, 0.1F);

                // Larger regions fade slightly slower
                deltaTime /= Mathf.Sqrt(Mathf.Max(lastRect.height, 100));

                lastUpdate = Time.realtimeSinceStartup;


                float targetValue = open ? 1F : 0F;
                if (!Mathf.Approximately(targetValue, value))
                {
                    value += deltaTime * animationSpeed * Mathf.Sign(targetValue - value);
                    value  = Mathf.Clamp01(value);
                    editor.Repaint();

                    if (!fancyEffects)
                    {
                        value = targetValue;
                    }
                }
                else
                {
                    value = targetValue;
                }
            }
        }
コード例 #9
0
        /** Calculates the bounds for this component.
         * This is a relatively expensive operation, it needs to go through all points and
         * run matrix multiplications.
         */
        public Bounds GetBounds()
        {
            if (points == null || points.Length == 0)
            {
                Bounds bounds;
                var    coll   = GetComponent <Collider>();
                var    coll2D = GetComponent <Collider2D>();
                var    rend   = GetComponent <Renderer>();

                if (coll != null)
                {
                    bounds = coll.bounds;
                }
                else if (coll2D != null)
                {
                    bounds      = coll2D.bounds;
                    bounds.size = new Vector3(bounds.size.x, bounds.size.y, Mathf.Max(bounds.size.z, 1f));
                }
                else if (rend != null)
                {
                    bounds = rend.bounds;
                }
                else
                {
                    return(new Bounds(Vector3.zero, Vector3.zero));
                }

                if (legacyMode && bounds.size.y < minBoundsHeight)
                {
                    bounds.size = new Vector3(bounds.size.x, minBoundsHeight, bounds.size.z);
                }
                return(bounds);
            }
            else
            {
                return(GraphUpdateShape.GetBounds(convex ? convexPoints : points, legacyMode && legacyUseWorldSpace ? Matrix4x4.identity : transform.localToWorldMatrix, minBoundsHeight));
            }
        }
コード例 #10
0
        /** Checks if the character is grounded and prevents ground penetration.
         * \param position Position of the character in the world.
         * \param lastElevation Elevation coordinate before the agent was moved. This is along the 'up' axis of the #movementPlane.
         *
         * Sets #verticalVelocity to zero if the character is grounded.
         *
         * \returns The new position of the character.
         */
        protected Vector3 RaycastPosition(Vector3 position, float lastElevation)
        {
            RaycastHit hit;
            float      elevation;

            movementPlane.ToPlane(position, out elevation);
            float   rayLength = centerOffset + Mathf.Max(0, lastElevation - elevation);
            Vector3 rayOffset = movementPlane.ToWorld(Vector2.zero.ToPFV2(), rayLength).ToUnityV3();

            if (Physics.Raycast(position + rayOffset, -rayOffset, out hit, rayLength, groundMask, QueryTriggerInteraction.Ignore))
            {
                // Grounded
                // Make the vertical velocity fall off exponentially. This is reasonable from a physical standpoint as characters
                // are not completely stiff and touching the ground will not immediately negate all velocity downwards. The AI will
                // stop moving completely due to the raycast penetration test but it will still *try* to move downwards. This helps
                // significantly when moving down along slopes as if the vertical velocity would be set to zero when the character
                // was grounded it would lead to a kind of 'bouncing' behavior (try it, it's hard to explain). Ideally this should
                // use a more physically correct formula but this is a good approximation and is much more performant. The constant
                // '5' in the expression below determines how quickly it converges but high values can lead to too much noise.
                verticalVelocity *= System.Math.Max(0, 1 - 5 * lastDeltaTime);
                return(hit.point);
            }
            return(position);
        }
コード例 #11
0
        private ItemEffect GenerateEffect(Item item)
        {
            Random rnd          = new Random();
            float  itemPriceMax = 2 * PriceMax - item.Class.Price;
            float  manaMax      = item.Class.Material.MagicVolume * item.Class.Class.MagicVolume - item.ManaUsage;
            // note: this will not work correctly if SlotsWarrior or SlotsMage values for a slot are not sorted by ascending order.
            //       parameters that appear first will "override" parameters with the same weight appearing later.
            int lastValue;

            Templates.TplModifier lastModifier = TemplateLoader.Templates.Modifiers[TemplateLoader.Templates.Modifiers.Count - 1];
            if ((item.Class.Option.SuitableFor & 1) != 0)
            {
                lastValue = lastModifier.SlotsFighter[item.Class.Option.Slot - 1];
            }
            else
            {
                lastValue = lastModifier.SlotsMage[item.Class.Option.Slot - 1];
            }
            int randomValue = rnd.Next(0, lastValue) + 1;

            Templates.TplModifier matchingModifier = null;
            if (item.Class.Option.SuitableFor == 2 && item.Class.Option.Slot == 1)
            {
                matchingModifier = TemplateLoader.Templates.Modifiers[(int)ItemEffect.Effects.CastSpell];
            }
            else
            {
                for (int i = 1; i < TemplateLoader.Templates.Modifiers.Count; i++)
                {
                    Templates.TplModifier prevModifier = TemplateLoader.Templates.Modifiers[i - 1];
                    Templates.TplModifier modifier     = TemplateLoader.Templates.Modifiers[i];
                    int prevValue;
                    int value;
                    if ((item.Class.Option.SuitableFor & 1) != 0)
                    {
                        prevValue = prevModifier.SlotsFighter[item.Class.Option.Slot - 1];
                        value     = modifier.SlotsFighter[item.Class.Option.Slot - 1];
                    }
                    else
                    {
                        prevValue = prevModifier.SlotsMage[item.Class.Option.Slot - 1];
                        value     = modifier.SlotsMage[item.Class.Option.Slot - 1];
                    }
                    if (prevValue < randomValue && randomValue <= value)
                    {
                        matchingModifier = modifier;
                        break;
                    }
                }
            }
            if (matchingModifier == null)
            {
                // parameter not found. weird, but happens.
                return(null);
            }
            if ((matchingModifier.UsableBy & item.Class.Option.SuitableFor) == 0)
            {
                // parameter for class not found in the item.
                return(null);
            }
            // parameter found. calculate max possible power
            ItemEffect effect = new ItemEffect();

            effect.Type1 = (ItemEffect.Effects)matchingModifier.Index;
            float maxPower;
            float absoluteMax = manaMax / matchingModifier.ManaCost;

            if (matchingModifier.Index == (int)ItemEffect.Effects.CastSpell)
            {
                // select spell to cast.
                // if for fighter, choose between fighter-specific spells.
                // if for mage, choose between mage-specific spells.
                Spell.Spells[] spells;
                if ((item.Class.Option.SuitableFor & 1) != 0)
                {
                    spells = new Spell.Spells[] { Spell.Spells.Stone_Curse, Spell.Spells.Drain_Life }
                }
                ;
                else
                {
                    spells = new Spell.Spells[] { Spell.Spells.Fire_Arrow, Spell.Spells.Lightning, Spell.Spells.Prismatic_Spray, Spell.Spells.Stone_Curse, Spell.Spells.Drain_Life, Spell.Spells.Ice_Missile, Spell.Spells.Diamond_Dust }
                };
                // choose random spell
                Spell.Spells spell = spells[rnd.Next(0, spells.Length)];
                effect.Value1 = (int)spell;
                // calculate max power
                Templates.TplSpell spellTemplate = TemplateLoader.Templates.Spells[effect.Value1];
                maxPower = Mathf.Log(itemPriceMax / (spellTemplate.ScrollCost * 10f)) / Mathf.Log(2);
                if (!float.IsNaN(maxPower) && maxPower > 0)
                {
                    maxPower = (Mathf.Pow(1.2f, maxPower) - 1) * 30;
                }
                else
                {
                    return(null);
                }
                maxPower = Mathf.Min(maxPower, absoluteMax);
                maxPower = Mathf.Min(maxPower, 100);
            }
            else
            {
                maxPower = Mathf.Log(itemPriceMax / (manaMax * 50) - 1) / Mathf.Log(1.5f) * 70f / matchingModifier.ManaCost;
                if (float.IsNaN(maxPower))
                {
                    return(null);
                }
                maxPower = Mathf.Min(maxPower, absoluteMax);
                maxPower = Mathf.Min(maxPower, matchingModifier.AffectMax);
                if (maxPower < matchingModifier.AffectMin)
                {
                    return(null);
                }
            }

            if (maxPower <= 1)
            {
                // either some limit hit, or something else
                return(null);
            }

            // max parameter power found. randomize values
            switch (effect.Type1)
            {
            case ItemEffect.Effects.CastSpell:
                effect.Value2 = rnd.Next(1, (int)maxPower + 1);
                break;

            case ItemEffect.Effects.DamageFire:
            case ItemEffect.Effects.DamageWater:
            case ItemEffect.Effects.DamageAir:
            case ItemEffect.Effects.DamageEarth:
            case ItemEffect.Effects.DamageAstral:
                effect.Value1 = rnd.Next(1, (int)maxPower + 1);
                effect.Value2 = rnd.Next(1, (int)(maxPower / 2) + 1);
                break;

            default:
                effect.Value1 = (int)Mathf.Max(matchingModifier.AffectMin, rnd.Next(1, (int)maxPower + 1));
                break;
            }

            return(effect);
        }
コード例 #12
0
 public static Vector2 Max(Vector2 lhs, Vector2 rhs)
 {
     return(new Vector2(Mathf.Max(lhs.x, rhs.x), Mathf.Max(lhs.y, rhs.y)));
 }
コード例 #13
0
        /** Will calculate a number of points around \a center which are on the graph and are separated by \a clearance from each other.
         * The maximum distance from \a center to any point will be \a radius.
         * Points will first be tried to be laid out as \a previousPoints and if that fails, random points will be selected.
         * This is great if you want to pick a number of target points for group movement. If you pass all current agent points from e.g the group's average position
         * this method will return target points so that the units move very little within the group, this is often aesthetically pleasing and reduces jitter if using
         * some kind of local avoidance.
         *
         * \param center The point to generate points around
         * \param g The graph to use for linecasting. If you are only using one graph, you can get this by AstarPath.active.graphs[0] as IRaycastableGraph.
         * Note that not all graphs are raycastable, recast, navmesh and grid graphs are raycastable. On recast and navmesh it works the best.
         * \param previousPoints The points to use for reference. Note that these should not be in world space. They are treated as relative to \a center.
         *      The new points will overwrite the existing points in the list. The result will be in world space, not relative to \a center.
         * \param radius The final points will be at most this distance from \a center.
         * \param clearanceRadius The points will if possible be at least this distance from each other.
         *
         * \todo Write unit tests
         */
        public static void GetPointsAroundPoint(Vector3 center, IRaycastableGraph g, List <Vector3> previousPoints, float radius, float clearanceRadius)
        {
            if (g == null)
            {
                throw new System.ArgumentNullException("g");
            }

            var graph = g as NavGraph;

            if (graph == null)
            {
                throw new System.ArgumentException("g is not a NavGraph");
            }

            NNInfoInternal nn = graph.GetNearestForce(center, NNConstraint.Default);

            center = nn.clampedPosition;

            if (nn.node == null)
            {
                // No valid point to start from
                return;
            }


            // Make sure the enclosing circle has a radius which can pack circles with packing density 0.5
            radius           = Mathf.Max(radius, 1.4142f * clearanceRadius * Mathf.Sqrt(previousPoints.Count)); //Mathf.Sqrt(previousPoints.Count*clearanceRadius*2));
            clearanceRadius *= clearanceRadius;

            for (int i = 0; i < previousPoints.Count; i++)
            {
                Vector3 dir  = previousPoints[i];
                float   magn = dir.magnitude;

                if (magn > 0)
                {
                    dir /= magn;
                }

                float newMagn = radius;                //magn > radius ? radius : magn;
                dir *= newMagn;

                GraphHitInfo hit;

                int tests = 0;
                while (true)
                {
                    Vector3 pt = center + dir;

                    if (g.Linecast(center, pt, nn.node, out hit))
                    {
                        if (hit.point == PF.Vector3.zero)
                        {
                            // Oops, linecast actually failed completely
                            // try again unless we have tried lots of times
                            // then we just continue anyway
                            tests++;
                            if (tests > 8)
                            {
                                previousPoints[i] = pt;
                                break;
                            }
                        }
                        else
                        {
                            pt = hit.point;
                        }
                    }

                    bool worked = false;

                    for (float q = 0.1f; q <= 1.0f; q += 0.05f)
                    {
                        Vector3 qt = Vector3.Lerp(center, pt, q);
                        worked = true;
                        for (int j = 0; j < i; j++)
                        {
                            if ((previousPoints[j] - qt).sqrMagnitude < clearanceRadius)
                            {
                                worked = false;
                                break;
                            }
                        }

                        // Abort after 8 tests or when we have found a valid point
                        if (worked || tests > 8)
                        {
                            worked            = true;
                            previousPoints[i] = qt;
                            break;
                        }
                    }

                    // Break out of nested loop
                    if (worked)
                    {
                        break;
                    }

                    // If we could not find a valid point, reduce the clearance radius slightly to improve
                    // the chances next time
                    clearanceRadius *= 0.9f;
                    // This will pick points in 2D closer to the edge of the circle with a higher probability
                    dir   = Random.onUnitSphere * Mathf.Lerp(newMagn, radius, tests / 5);
                    dir.y = 0;
                    tests++;
                }
            }
        }
コード例 #14
0
ファイル: AutoPupil.cs プロジェクト: lfe999/VamAutoPupil
        private void Update()
        {
            if (!_initCompleted)
            {
                return;
            }
            if (SuperController.singleton.freezeAnimation)
            {
                return;
            }
#if LFE_DEBUG
            if (Input.GetKey("up"))
            {
                CameraTarget.centerTarget.targetCamera.enabled = false;
                _detector.Detector.enabled = true;
            }
            else
            {
                CameraTarget.centerTarget.targetCamera.enabled = true;
                _detector.Detector.enabled = true;
            }
#endif

            try
            {
                _brightnessChangeCountdown -= Time.deltaTime;
                // run the scheduled animation
                if (_currentAnimation != null)
                {
                    _pupilMorph.morphValueAdjustLimits = Math.Clamp(_currentAnimation.Update(), -1.5f, 2.0f);
                    if (_currentAnimation.IsFinished)
                    {
                        _currentAnimation = null;

                        // schedule a new idle
                        _idleCountDown = UnityEngine.Random.Range(0.01f, Math.Max(IdleMaxDelayStorable.val, 0.01f));
                    }
                }

                var brightness   = CalculateBrightness();
                var currentValue = _pupilMorph.morphValue;
                var targetValue  = BrightnessToMorphValue(brightness);
                var duration     = 0f;

                if (_lastBrightness == brightness)
                {
                    // maybe schedule an idle animation - but do not interrupt an animation in progress just for idle
                    if (_currentAnimation == null && _idleCountDown < 0)
                    {
                        duration    = Math.Max(IdleAdjustSpeedStorable.val, 0.01f);
                        _idleSign   = _idleSign * -1;
                        targetValue = targetValue + (_idleSign * UnityEngine.Random.Range(0.01f, IdleStrengthStorable.val));

                        _currentAnimation = new EyeDialationAnimation(currentValue, targetValue, duration, (p) => Easings.BackEaseOut(p));
                    }
                    else
                    {
                        _idleCountDown -= Time.deltaTime;
                    }
                }
                else
                {
                    if (_brightnessChangeCountdown <= 0)
                    {
                        // schedule brightness adjustment animation - override any currently running animation for this one. light always wins
                        duration = targetValue > currentValue
                            ? DarkAdjustSpeedStorable.val
                            : LightAdjustSpeedStorable.val;
                        _currentAnimation          = new EyeDialationAnimation(currentValue, targetValue, duration, (p) => Easings.ElasticEaseOut(p));
                        _brightnessChangeCountdown = _brightnessChangeThrottle;
                    }
                }

                _lastBrightness = brightness;
            }
            catch (Exception ex)
            {
                SuperController.LogError(ex.ToString());
            }
        }
コード例 #15
0
        public List <Vector3> SmoothSimple(List <Vector3> path)
        {
            if (path.Count < 2)
            {
                return(path);
            }

            List <Vector3> subdivided;

            if (uniformLength)
            {
                // Clamp to a small value to avoid the path being divided into a huge number of segments
                maxSegmentLength = Mathf.Max(maxSegmentLength, 0.005f);

                float pathLength = 0;
                for (int i = 0; i < path.Count - 1; i++)
                {
                    pathLength += Vector3.Distance(path[i], path[i + 1]);
                }

                int estimatedNumberOfSegments = Mathf.FloorToInt(pathLength / maxSegmentLength);
                // Get a list with an initial capacity high enough so that we can add all points
                subdivided = ListPool <Vector3> .Claim(estimatedNumberOfSegments + 2);

                float distanceAlong = 0;

                // Sample points every [maxSegmentLength] world units along the path
                for (int i = 0; i < path.Count - 1; i++)
                {
                    var start = path[i];
                    var end   = path[i + 1];

                    float length = Vector3.Distance(start, end);

                    while (distanceAlong < length)
                    {
                        subdivided.Add(Vector3.Lerp(start, end, distanceAlong / length));
                        distanceAlong += maxSegmentLength;
                    }

                    distanceAlong -= length;
                }

                // Make sure we get the exact position of the last point
                subdivided.Add(path[path.Count - 1]);
            }
            else
            {
                subdivisions = Mathf.Max(subdivisions, 0);

                if (subdivisions > 10)
                {
                    Debug.LogWarning("Very large number of subdivisions. Cowardly refusing to subdivide every segment into more than " + (1 << subdivisions) + " subsegments");
                    subdivisions = 10;
                }

                int steps = 1 << subdivisions;
                subdivided = ListPool <Vector3> .Claim((path.Count - 1) *steps + 1);

                Polygon.Subdivide(path, subdivided, steps);
            }

            if (strength > 0)
            {
                for (int it = 0; it < iterations; it++)
                {
                    Vector3 prev = subdivided[0];

                    for (int i = 1; i < subdivided.Count - 1; i++)
                    {
                        Vector3 tmp = subdivided[i];

                        // prev is at this point set to the value that subdivided[i-1] had before this loop started
                        // Move the point closer to the average of the adjacent points
                        subdivided[i] = Vector3.Lerp(tmp, (prev + subdivided[i + 1].ToUnityV3()) / 2F, strength);

                        prev = tmp;
                    }
                }
            }

            return(subdivided);
        }
コード例 #16
0
        public override void OnInspectorGUI(NavGraph target)
        {
            var graph = target as RecastGraph;

            bool preEnabled = GUI.enabled;

            System.Int64 estWidth = Mathf.RoundToInt(Mathf.Ceil(graph.forcedBoundsSize.x / graph.cellSize));
            System.Int64 estDepth = Mathf.RoundToInt(Mathf.Ceil(graph.forcedBoundsSize.z / graph.cellSize));

            // Show a warning if the number of voxels is too large
            if (estWidth * estDepth >= 1024 * 1024 || estDepth >= 1024 * 1024 || estWidth >= 1024 * 1024)
            {
                GUIStyle helpBox = GUI.skin.FindStyle("HelpBox") ?? GUI.skin.FindStyle("Box");

                Color preColor = GUI.color;
                if (estWidth * estDepth >= 2048 * 2048 || estDepth >= 2048 * 2048 || estWidth >= 2048 * 2048)
                {
                    GUI.color = Color.red;
                }
                else
                {
                    GUI.color = Color.yellow;
                }

                GUILayout.Label("Warning : Might take some time to calculate", helpBox);
                GUI.color = preColor;
            }

            GUI.enabled = false;
            EditorGUILayout.LabelField(new GUIContent("Width (voxels)", "Based on the cell size and the bounding box"), new GUIContent(estWidth.ToString()));

            EditorGUILayout.LabelField(new GUIContent("Depth (voxels)", "Based on the cell size and the bounding box"), new GUIContent(estDepth.ToString()));
            GUI.enabled = preEnabled;

            graph.cellSize = EditorGUILayout.FloatField(new GUIContent("Cell Size", "Size of one voxel in world units"), graph.cellSize);
            if (graph.cellSize < 0.001F)
            {
                graph.cellSize = 0.001F;
            }

            graph.useTiles = (UseTiles)EditorGUILayout.EnumPopup("Use Tiles", graph.useTiles ? UseTiles.UseTiles : UseTiles.DontUseTiles) == UseTiles.UseTiles;

            if (graph.useTiles)
            {
                EditorGUI.indentLevel++;
                graph.editorTileSize = EditorGUILayout.IntField(new GUIContent("Tile Size", "Size in voxels of a single tile.\n" +
                                                                               "This is the width of the tile.\n" +
                                                                               "\n" +
                                                                               "A large tile size can be faster to initially scan (but beware of out of memory issues if you try with a too large tile size in a large world)\n" +
                                                                               "smaller tile sizes are (much) faster to update.\n" +
                                                                               "\n" +
                                                                               "Different tile sizes can affect the quality of paths. It is often good to split up huge open areas into several tiles for\n" +
                                                                               "better quality paths, but too small tiles can lead to effects looking like invisible obstacles."), graph.editorTileSize);
                EditorGUI.indentLevel--;
            }

            graph.minRegionSize = EditorGUILayout.FloatField(new GUIContent("Min Region Size", "Small regions will be removed. In square world units"), graph.minRegionSize);

            graph.walkableHeight = EditorGUILayout.FloatField(new GUIContent("Walkable Height", "Minimum distance to the roof for an area to be walkable"), graph.walkableHeight);
            graph.walkableHeight = Mathf.Max(graph.walkableHeight, 0);

            graph.walkableClimb = EditorGUILayout.FloatField(new GUIContent("Walkable Climb", "How high can the character climb"), graph.walkableClimb);

            // A walkableClimb higher than this can cause issues when generating the navmesh since then it can in some cases
            // Both be valid for a character to walk under an obstacle and climb up on top of it (and that cannot be handled with a navmesh without links)
            if (graph.walkableClimb >= graph.walkableHeight)
            {
                graph.walkableClimb = graph.walkableHeight;
                EditorGUILayout.HelpBox("Walkable climb should be less than walkable height. Clamping to " + graph.walkableHeight + ".", MessageType.Warning);
            }
            else if (graph.walkableClimb < 0)
            {
                graph.walkableClimb = 0;
            }

            graph.characterRadius = EditorGUILayout.FloatField(new GUIContent("Character Radius", "Radius of the character. It's good to add some margin.\nIn world units."), graph.characterRadius);
            graph.characterRadius = Mathf.Max(graph.characterRadius, 0);

            if (graph.characterRadius < graph.cellSize * 2)
            {
                EditorGUILayout.HelpBox("For best navmesh quality, it is recommended to keep the character radius at least 2 times as large as the cell size. Smaller cell sizes will give you higher quality navmeshes, but it will take more time to scan the graph.", MessageType.Warning);
            }

            graph.maxSlope      = EditorGUILayout.Slider(new GUIContent("Max Slope", "Approximate maximum slope"), graph.maxSlope, 0F, 90F);
            graph.maxEdgeLength = EditorGUILayout.FloatField(new GUIContent("Max Border Edge Length", "Maximum length of one border edge in the completed navmesh before it is split. A lower value can often yield better quality graphs, but don't use so low values so that you get a lot of thin triangles."), graph.maxEdgeLength);
            graph.maxEdgeLength = graph.maxEdgeLength < graph.cellSize ? graph.cellSize : graph.maxEdgeLength;

            graph.contourMaxError = EditorGUILayout.FloatField(new GUIContent("Max Edge Error", "Amount of simplification to apply to edges.\nIn world units."), graph.contourMaxError);

            graph.rasterizeTerrain = EditorGUILayout.Toggle(new GUIContent("Rasterize Terrain", "Should a rasterized terrain be included"), graph.rasterizeTerrain);
            if (graph.rasterizeTerrain)
            {
                EditorGUI.indentLevel++;
                graph.rasterizeTrees = EditorGUILayout.Toggle(new GUIContent("Rasterize Trees", "Rasterize tree colliders on terrains. " +
                                                                             "If the tree prefab has a collider, that collider will be rasterized. " +
                                                                             "Otherwise a simple box collider will be used and the script will " +
                                                                             "try to adjust it to the tree's scale, it might not do a very good job though so " +
                                                                             "an attached collider is preferable."), graph.rasterizeTrees);
                if (graph.rasterizeTrees)
                {
                    EditorGUI.indentLevel++;
                    graph.colliderRasterizeDetail = EditorGUILayout.FloatField(new GUIContent("Collider Detail", "Controls the detail of the generated collider meshes. " +
                                                                                              "Increasing does not necessarily yield better navmeshes, but lowering will speed up scan.\n" +
                                                                                              "Spheres and capsule colliders will be converted to meshes in order to be able to rasterize them, a higher value will increase the number of triangles in those meshes."), graph.colliderRasterizeDetail);
                    EditorGUI.indentLevel--;
                }

                graph.terrainSampleSize = EditorGUILayout.IntField(new GUIContent("Terrain Sample Size", "Size of terrain samples. A lower value is better, but slower"), graph.terrainSampleSize);
                graph.terrainSampleSize = graph.terrainSampleSize < 1 ? 1 : graph.terrainSampleSize;                //Clamp to at least 1
                EditorGUI.indentLevel--;
            }

            graph.rasterizeMeshes    = EditorGUILayout.Toggle(new GUIContent("Rasterize Meshes", "Should meshes be rasterized and used for building the navmesh"), graph.rasterizeMeshes);
            graph.rasterizeColliders = EditorGUILayout.Toggle(new GUIContent("Rasterize Colliders", "Should colliders be rasterized and used for building the navmesh"), graph.rasterizeColliders);
            if (graph.rasterizeColliders)
            {
                EditorGUI.indentLevel++;
                graph.colliderRasterizeDetail = EditorGUILayout.FloatField(new GUIContent("Collider Detail", "Controls the detail of the generated collider meshes. " +
                                                                                          "Increasing does not necessarily yield better navmeshes, but lowering will speed up scan.\n" +
                                                                                          "Spheres and capsule colliders will be converted to meshes in order to be able to rasterize them, a higher value will increase the number of triangles in those meshes."), graph.colliderRasterizeDetail);
                EditorGUI.indentLevel--;
            }

            if (graph.rasterizeMeshes && graph.rasterizeColliders)
            {
                EditorGUILayout.HelpBox("You are rasterizing both meshes and colliders, this might just be duplicating the work that is done if the colliders and meshes are similar in shape. You can use the RecastMeshObj component" +
                                        " to always include some specific objects regardless of what the above settings are set to.", MessageType.Info);
            }

            Separator();

            graph.forcedBoundsCenter = EditorGUILayout.Vector3Field("Center", graph.forcedBoundsCenter);
            graph.forcedBoundsSize   = EditorGUILayout.Vector3Field("Size", graph.forcedBoundsSize);
            // Make sure the bounding box is not infinitely thin along any axis
            graph.forcedBoundsSize = Vector3.Max(graph.forcedBoundsSize, Vector3.one * 0.001f);
            graph.rotation         = EditorGUILayout.Vector3Field("Rotation", graph.rotation);

            if (GUILayout.Button(new GUIContent("Snap bounds to scene", "Will snap the bounds of the graph to exactly contain all meshes that the bounds currently touches")))
            {
                graph.SnapForceBoundsToScene();
                GUI.changed = true;
            }

            Separator();

            EditorGUILayout.HelpBox("Objects contained in any of these masks will be rasterized", MessageType.None);
            graph.mask     = EditorGUILayoutx.LayerMaskField("Layer Mask", graph.mask);
            tagMaskFoldout = EditorGUILayoutx.UnityTagMaskList(new GUIContent("Tag Mask"), tagMaskFoldout, graph.tagMask);

            Separator();

            GUILayout.BeginHorizontal();
            GUILayout.Space(18);
            graph.showMeshSurface     = GUILayout.Toggle(graph.showMeshSurface, new GUIContent("Show surface", "Toggles gizmos for drawing the surface of the mesh"), EditorStyles.miniButtonLeft);
            graph.showMeshOutline     = GUILayout.Toggle(graph.showMeshOutline, new GUIContent("Show outline", "Toggles gizmos for drawing an outline of the nodes"), EditorStyles.miniButtonMid);
            graph.showNodeConnections = GUILayout.Toggle(graph.showNodeConnections, new GUIContent("Show connections", "Toggles gizmos for drawing node connections"), EditorStyles.miniButtonRight);
            GUILayout.EndHorizontal();


            Separator();
            GUILayout.Label(new GUIContent("Advanced"), EditorStyles.boldLabel);

            if (GUILayout.Button("Export to .obj file"))
            {
                ExportToFile(graph);
            }

            graph.relevantGraphSurfaceMode = (RecastGraph.RelevantGraphSurfaceMode)EditorGUILayout.EnumPopup(new GUIContent("Relevant Graph Surface Mode",
                                                                                                                            "Require every region to have a RelevantGraphSurface component inside it.\n" +
                                                                                                                            "A RelevantGraphSurface component placed in the scene specifies that\n" +
                                                                                                                            "the navmesh region it is inside should be included in the navmesh.\n\n" +
                                                                                                                            "If this is set to OnlyForCompletelyInsideTile\n" +
                                                                                                                            "a navmesh region is included in the navmesh if it\n" +
                                                                                                                            "has a RelevantGraphSurface inside it, or if it\n" +
                                                                                                                            "is adjacent to a tile border. This can leave some small regions\n" +
                                                                                                                            "which you didn't want to have included because they are adjacent\n" +
                                                                                                                            "to tile borders, but it removes the need to place a component\n" +
                                                                                                                            "in every single tile, which can be tedious (see below).\n\n" +
                                                                                                                            "If this is set to RequireForAll\n" +
                                                                                                                            "a navmesh region is included only if it has a RelevantGraphSurface\n" +
                                                                                                                            "inside it. Note that even though the navmesh\n" +
                                                                                                                            "looks continous between tiles, the tiles are computed individually\n" +
                                                                                                                            "and therefore you need a RelevantGraphSurface component for each\n" +
                                                                                                                            "region and for each tile."),
                                                                                                             graph.relevantGraphSurfaceMode);

            graph.nearestSearchOnlyXZ = EditorGUILayout.Toggle(new GUIContent("Nearest node queries in XZ space",
                                                                              "Recomended for single-layered environments.\nFaster but can be inacurate esp. in multilayered contexts."), graph.nearestSearchOnlyXZ);

            if (graph.nearestSearchOnlyXZ && (Mathf.Abs(graph.rotation.x) > 1 || Mathf.Abs(graph.rotation.z) > 1))
            {
                EditorGUILayout.HelpBox("Nearest node queries in XZ space is not recommended for rotated graphs since XZ space no longer corresponds to the ground plane", MessageType.Warning);
            }
        }
コード例 #17
0
        /** Called during either Update or FixedUpdate depending on if rigidbodies are used for movement or not */
        protected override void MovementUpdateInternal(float deltaTime, out Vector3 nextPosition, out Quaternion nextRotation)
        {
            float currentAcceleration = maxAcceleration;

            // If negative, calculate the acceleration from the max speed
            if (currentAcceleration < 0)
            {
                currentAcceleration *= -maxSpeed;
            }

            if (updatePosition)
            {
                // Get our current position. We read from transform.position as few times as possible as it is relatively slow
                // (at least compared to a local variable)
                simulatedPosition = tr.position;
            }
            if (updateRotation)
            {
                simulatedRotation = tr.rotation;
            }

            var currentPosition = simulatedPosition;

            // Update which point we are moving towards
            interpolator.MoveToCircleIntersection2D(currentPosition, pickNextWaypointDist, movementPlane);
            var dir = movementPlane.ToPlane(steeringTarget - currentPosition);

            // Calculate the distance to the end of the path
            float distanceToEnd = dir.magnitude + Mathf.Max(0, interpolator.remainingDistance);

            // Check if we have reached the target
            var prevTargetReached = reachedEndOfPath;

            reachedEndOfPath = distanceToEnd <= endReachedDistance && interpolator.valid;
            if (!prevTargetReached && reachedEndOfPath)
            {
                OnTargetReached();
            }
            float slowdown;

            // Normalized direction of where the agent is looking
            var forwards = movementPlane.ToPlane(simulatedRotation * (rotationIn2D ? Vector3.up : Vector3.forward));

            // Check if we have a valid path to follow and some other script has not stopped the character
            if (interpolator.valid && !isStopped)
            {
                // How fast to move depending on the distance to the destination.
                // Move slower as the character gets closer to the destination.
                // This is always a value between 0 and 1.
                slowdown = distanceToEnd < slowdownDistance?Mathf.Sqrt(distanceToEnd / slowdownDistance) : 1;

                if (reachedEndOfPath && whenCloseToDestination == CloseToDestinationMode.Stop)
                {
                    // Slow down as quickly as possible
                    velocity2D -= Vector2.ClampMagnitude(velocity2D, currentAcceleration * deltaTime);
                }
                else
                {
                    velocity2D += MovementUtilities.CalculateAccelerationToReachPoint(dir.ToUnityV2(), dir.normalized * maxSpeed, velocity2D, currentAcceleration, rotationSpeed, maxSpeed, forwards) * deltaTime;
                }
            }
            else
            {
                slowdown = 1;
                // Slow down as quickly as possible
                velocity2D -= Vector2.ClampMagnitude(velocity2D, currentAcceleration * deltaTime);
            }

            velocity2D = MovementUtilities.ClampVelocity(velocity2D, maxSpeed, slowdown, slowWhenNotFacingTarget, forwards.ToUnityV2());

            ApplyGravity(deltaTime);

            if (rvoController != null && rvoController.enabled)
            {
                // Send a message to the RVOController that we want to move
                // with this velocity. In the next simulation step, this
                // velocity will be processed and it will be fed back to the
                // rvo controller and finally it will be used by this script
                // when calling the CalculateMovementDelta method below

                // Make sure that we don't move further than to the end point
                // of the path. If the RVO simulation FPS is low and we did
                // not do this, the agent might overshoot the target a lot.
                var rvoTarget = currentPosition.ToPFV3() + movementPlane.ToWorld(Vector2.ClampMagnitude(velocity2D, distanceToEnd), 0f);
                rvoController.SetTarget(rvoTarget, velocity2D.magnitude, maxSpeed);
            }

            // Set how much the agent wants to move during this frame
            var delta2D = lastDeltaPosition = CalculateDeltaToMoveThisFrame(movementPlane.ToPlane(currentPosition), distanceToEnd, deltaTime);

            nextPosition = currentPosition + movementPlane.ToWorld(delta2D.ToPFV2(), verticalVelocity * lastDeltaTime).ToUnityV3();
            CalculateNextRotation(slowdown, out nextRotation);
        }
コード例 #18
0
        void GenerateTerrainChunks(Terrain terrain, Bounds bounds, float desiredChunkSize, List <RasterizationMesh> result)
        {
            var terrainData = terrain.terrainData;

            if (terrainData == null)
            {
                throw new System.ArgumentException("Terrain contains no terrain data");
            }

            Vector3 offset = terrain.GetPosition();
            Vector3 center = offset + terrainData.size * 0.5F;

            // Figure out the bounds of the terrain in world space
            var terrainBounds = new Bounds(center, terrainData.size);

            // Only include terrains which intersects the graph
            if (!terrainBounds.Intersects(bounds))
            {
                return;
            }

            // Original heightmap size
            int heightmapWidth = terrainData.heightmapWidth;
            int heightmapDepth = terrainData.heightmapHeight;

            // Sample the terrain heightmap
            float[, ] heights = terrainData.GetHeights(0, 0, heightmapWidth, heightmapDepth);

            Vector3 sampleSize = terrainData.heightmapScale;

            sampleSize.y = terrainData.size.y;

            // Make chunks at least 12 quads wide
            // since too small chunks just decreases performance due
            // to the overhead of checking for bounds and similar things
            const int MinChunkSize = 12;

            // Find the number of samples along each edge that corresponds to a world size of desiredChunkSize
            // Then round up to the nearest multiple of terrainSampleSize
            var chunkSizeAlongX = Mathf.CeilToInt(Mathf.Max(desiredChunkSize / (sampleSize.x * terrainSampleSize), MinChunkSize)) * terrainSampleSize;
            var chunkSizeAlongZ = Mathf.CeilToInt(Mathf.Max(desiredChunkSize / (sampleSize.z * terrainSampleSize), MinChunkSize)) * terrainSampleSize;

            for (int z = 0; z < heightmapDepth; z += chunkSizeAlongZ)
            {
                for (int x = 0; x < heightmapWidth; x += chunkSizeAlongX)
                {
                    var width       = Mathf.Min(chunkSizeAlongX, heightmapWidth - x);
                    var depth       = Mathf.Min(chunkSizeAlongZ, heightmapDepth - z);
                    var chunkMin    = offset + new Vector3(z * sampleSize.x, 0, x * sampleSize.z);
                    var chunkMax    = offset + new Vector3((z + depth) * sampleSize.x, sampleSize.y, (x + width) * sampleSize.z);
                    var chunkBounds = new Bounds();
                    chunkBounds.SetMinMax(chunkMin, chunkMax);

                    // Skip chunks that are not inside the desired bounds
                    if (chunkBounds.Intersects(bounds))
                    {
                        var chunk = GenerateHeightmapChunk(heights, sampleSize, offset, x, z, width, depth, terrainSampleSize);
                        result.Add(chunk);
                    }
                }
            }
        }
コード例 #19
0
    void Start()
    {
        moduleId = moduleIdCounter++;
        var serialNum = BombInfo.GetSerialNumber();

        rnd = RuleSeedable.GetRNG();
        Debug.LogFormat(@"[Colorful Madness #{0}] Using rule seed: {1}", moduleId, rnd.Seed);
        var grabSerial    = new[] { 0, 2, 4 };
        var firstColor    = 0;
        var secondColor   = 1;
        var modSteps      = new[] { 4, 0, 5, 6, 7 };
        var firstPattern  = 4;
        var secondPattern = 3;
        var firstUnique   = 1;
        var secondUnique  = 1;

        if (rnd.Seed != 1)
        {
            firstColor  = rnd.Next(5);
            secondColor = rnd.Next(firstColor + 1, 6);
            grabSerial  = new[] { ChooseUnique(6), ChooseUnique(6), ChooseUnique(6) };
            pickedValues.Clear();
            modSteps = new[] { ChooseUnique(10), ChooseUnique(10), ChooseUnique(10), ChooseUnique(10), ChooseUnique(10) };
            pickedValues.Clear();
            firstPattern  = ChooseUnique(7);
            secondPattern = ChooseUnique(7);
            pickedValues.Clear();
            firstUnique  = rnd.Next(1, 5);
            secondUnique = rnd.Next(1, 5);
        }

        var subCols = new[] { 0, 0, 1, 3, 6, 10 };
        var initCol = (7 * ((5 * firstColor) - subCols[firstColor])) + (7 * (secondColor - (firstColor + 1)));

        ColScreen.SetActive(ColorblindMode.ColorblindModeActive);

        for (int i = 0; i < 3; i++)
        {
            digits[i] = serialNum[grabSerial[i]];

            if (digits[i] >= 'A')
            {
                digits[i] -= 'A';
            }
            else
            {
                digits[i] -= '0';
            }
        }

        Debug.LogFormat(@"[Colorful Madness #{0}] The 3 characters of the serial number are: {1}", moduleId, Enumerable.Range(0, 3).Select(x => serialNum[grabSerial[x]]).Join(", "));
        Debug.LogFormat(@"[Colorful Madness #{0}] The 3 main digits are: {1}", moduleId, digits.Join(", "));
        var hasButtonCC = 0;
        var hasButtonA  = 0;
        var hasButtonB  = 0;

        for (int i = 0; i < 10; i++)
        {
            do
            {
                topHalfTextures[i] = Random.Range(0, 105);
            } while (bottomHalfTextures.Contains(topHalfTextures[i]));

            if (topHalfTextures[i] >= initCol && topHalfTextures[i] <= initCol + 6)
            {
                hasButtonCC++;
            }

            if ((topHalfTextures[i] % 7) == firstPattern)
            {
                hasButtonA++;
            }

            if ((topHalfTextures[i] % 7) == secondPattern)
            {
                hasButtonB++;
            }

            ModuleButtons[i].transform.GetChild(1).GetComponent <Renderer>().material.SetTexture("_MainTex", ColTexturesA[topHalfTextures[i]]);
            bottomHalfTextures[i] = topHalfTextures[i];
        }

        for (int v = 0; v < bottomHalfTextures.Length; v++)
        {
            var tmp = bottomHalfTextures[v];
            var r   = Random.Range(v, bottomHalfTextures.Length);
            bottomHalfTextures[v] = bottomHalfTextures[r];
            bottomHalfTextures[r] = tmp;
        }

        for (int i = 10; i < 20; i++)
        {
            ModuleButtons[i].transform.GetChild(1).GetComponent <Renderer>().material.SetTexture("_MainTex", ColTexturesB[bottomHalfTextures[i - 10]]);
        }

        var tempList = new List <int>();

        tempList.AddRange(topHalfTextures);
        tempList.AddRange(bottomHalfTextures);
        moduleTextures = tempList.ToArray();
        getCol         = ((x, y, z) => ((7 * ((5 * x) - subCols[x])) + (7 * (y - (x + 1))) == (z - (z % 7))));

        var serialDigits = BombInfo.GetSerialNumberNumbers().ToArray();
        var stepList     = new[] {
            hasButtonCC * 2,
            digits.Sum(),
            serialDigits.Sum(),
            int.Parse(serialNum[5].ToString()),
            BombInfo.GetBatteryCount(),
            BombInfo.GetPortCount(),
            BombInfo.GetBatteryHolderCount(),
            BombInfo.GetPortPlateCount(),
            Math.Min(serialDigits),
            Math.Max(serialDigits)
        };

        var modValue = 0;

        if (hasButtonCC > 0)
        {
            modValue = stepList[modSteps[0]];

            for (int i = 0; i < 3; i++)
            {
                digits[i] += modValue;
            }

            Debug.LogFormat(@"[Colorful Madness #{0}] There are {1} {2} and {3} button. Adding {4}: {5}", moduleId, hasButtonCC * 2, moduleColors[firstColor], moduleColors[secondColor], modValue, digits.Join(", "));
        }

        stepList[0] = hasButtonA * 2;
        stepList[1] = digits.Sum();

        if (hasButtonA > 0)
        {
            modValue = Mathf.Abs(stepList[modSteps[1]] - stepList[modSteps[2]]);

            for (int i = 0; i < 3; i++)
            {
                digits[i] = Mathf.Abs(digits[i] - modValue);
            }

            Debug.LogFormat(@"[Colorful Madness #{0}] There are {1} {2} buttons. Subtracting {3}: {4}", moduleId, hasButtonA * 2, moduleButtonNames[firstPattern], modValue, digits.Join(", "));
        }

        stepList[0] = hasButtonB * 2;
        stepList[1] = digits.Sum();

        if (hasButtonB > 0)
        {
            modValue = stepList[modSteps[3]] + stepList[modSteps[4]];

            for (int i = 0; i < 3; i++)
            {
                digits[i] *= modValue;
            }

            Debug.LogFormat(@"[Colorful Madness #{0}] There are {1} {2} buttons. Multiplying by {3}: {4}", moduleId, hasButtonB * 2, moduleButtonNames[secondPattern], modValue, digits.Join(", "));
        }

        for (int i = 0; i < 3; i++)
        {
            digits[i] = digits[i] % 10;
        }

        Debug.LogFormat(@"[Colorful Madness #{0}] Modulo 10: {1}", moduleId, digits.Join(", "));

        while (digits[0] == digits[1] || digits[0] == digits[2])
        {
            digits[0] = (digits[0] + firstUnique) % 10;
        }

        while (digits[1] == digits[0] || digits[1] == digits[2])
        {
            digits[1] = (digits[1] + (10 - secondUnique)) % 10;
        }

        Debug.LogFormat(@"[Colorful Madness #{0}] Make unique: {1}", moduleId, digits.Join(", "));
        Debug.LogFormat(@"[Colorful Madness #{0}] Added one: {1}", moduleId, digits.Select(x => x + 1).Join(", "));

        var counterparts = digits.Select(digit => Array.IndexOf(bottomHalfTextures, topHalfTextures[digit]) + 10).ToArray();

        Debug.LogFormat(@"[Colorful Madness #{0}] The correct counterpart buttons on the bottom half are: {1}", moduleId, counterparts.Select(x => x + 1).Join(", "));

        for (int i = 0; i < ModuleButtons.Length; i++)
        {
            int j = i;

            ModuleButtons[i].OnInteract += delegate() {
                OnButtonPress(j);

                return(false);
            };

            ModuleButtons[i].OnHighlight += delegate() {
                OnButtonHighlight(j);
            };

            ModuleButtons[i].OnDeselect += delegate() {
                ColScreen.transform.GetChild(0).GetComponent <TextMesh>().text = "";
            };
        }
    }
コード例 #20
0
        /** Draws some gizmos */
        void OnDrawGizmos(bool selected)
        {
            Color c = selected ? new Color(227 / 255f, 61 / 255f, 22 / 255f, 1.0f) : new Color(227 / 255f, 61 / 255f, 22 / 255f, 0.9f);

            if (selected)
            {
                Gizmos.color = Color.Lerp(c, new Color(1, 1, 1, 0.2f), 0.9f);

                Bounds b = GetBounds();
                Gizmos.DrawCube(b.center, b.size);
                Gizmos.DrawWireCube(b.center, b.size);
            }

            if (points == null)
            {
                return;
            }

            if (convex)
            {
                c.a *= 0.5f;
            }

            Gizmos.color = c;

            Matrix4x4 matrix = legacyMode && legacyUseWorldSpace ? Matrix4x4.identity : transform.localToWorldMatrix;

            if (convex)
            {
                c.r -= 0.1f;
                c.g -= 0.2f;
                c.b -= 0.1f;

                Gizmos.color = c;
            }

            if (selected || !convex)
            {
                for (int i = 0; i < points.Length; i++)
                {
                    Gizmos.DrawLine(matrix.MultiplyPoint3x4(points[i]), matrix.MultiplyPoint3x4(points[(i + 1) % points.Length]));
                }
            }

            if (convex)
            {
                if (convexPoints == null)
                {
                    RecalcConvex();
                }

                Gizmos.color = selected ? new Color(227 / 255f, 61 / 255f, 22 / 255f, 1.0f) : new Color(227 / 255f, 61 / 255f, 22 / 255f, 0.9f);

                for (int i = 0; i < convexPoints.Length; i++)
                {
                    Gizmos.DrawLine(matrix.MultiplyPoint3x4(convexPoints[i]), matrix.MultiplyPoint3x4(convexPoints[(i + 1) % convexPoints.Length]));
                }
            }

            // Draw the full 3D shape
            var pts = convex ? convexPoints : points;

            if (selected && pts != null && pts.Length > 0)
            {
                Gizmos.color = new Color(1, 1, 1, 0.2f);
                float miny = pts[0].y, maxy = pts[0].y;
                for (int i = 0; i < pts.Length; i++)
                {
                    miny = Mathf.Min(miny, pts[i].y);
                    maxy = Mathf.Max(maxy, pts[i].y);
                }
                var extraHeight = Mathf.Max(minBoundsHeight - (maxy - miny), 0) * 0.5f;
                miny -= extraHeight;
                maxy += extraHeight;

                for (int i = 0; i < pts.Length; i++)
                {
                    var next = (i + 1) % pts.Length;
                    var p1   = matrix.MultiplyPoint3x4(pts[i] + PF.Vector3.up * (miny - pts[i].y));
                    var p2   = matrix.MultiplyPoint3x4(pts[i] + PF.Vector3.up * (maxy - pts[i].y));
                    var p1n  = matrix.MultiplyPoint3x4(pts[next] + PF.Vector3.up * (miny - pts[next].y));
                    var p2n  = matrix.MultiplyPoint3x4(pts[next] + PF.Vector3.up * (maxy - pts[next].y));
                    Gizmos.DrawLine(p1, p2);
                    Gizmos.DrawLine(p1, p1n);
                    Gizmos.DrawLine(p2, p2n);
                }
            }
        }
コード例 #21
0
/**
 * Tweet cart is the whole script, fit in one tweet, i.e. code length must be <= 280 characters
 *
 * Tigra tweet cart shortcuts:
 *
 * Functions:
 * TIC() is called 60 times per second.
 *
 * Variables:
 * t:  elapsed time in seconds
 * f:  frame counter
 *
 * Aliases:
 * B:  bool
 * F:  float
 * I:  int
 * M:  UnityEngine.Mathf
 * R:  UnityEngine.Random
 * S:  System.String
 * V2: UnityEngine.Vector2
 * V3: UnityEngine.Vector3
 * Z:  Tic80
 *
 * Delegates:
 * CD: circ & circb delegate
 * RD: rect & rectb delegate
 * TD: tri & trib delegate
 *
 * Beautify/minify C# online tool:
 * https://codebeautify.org/csharpviewer
 */
class Tc3 : Z { void TIC()
                {
                    cls(2); var m = mouse(); var x = m[0]; var y = m[1]; var p = m[2]; circ(60, 50, 40, 15); circ(180, 50, 40, 15); circ(M.Min(80, M.Max(40, x)), M.Min(70, M.Max(30, y)), 15, 0); circ(M.Min(200, M.Max(160, x)), M.Min(70, M.Max(30, y)), 15, 0);
                }
コード例 #22
0
            /** Creates a VO for avoiding another agent.
             * Note that the segment is directed, the agent will want to be on the left side of the segment.
             */
            public static VO SegmentObstacle(Vector2 segmentStart, Vector2 segmentEnd, Vector2 offset, float radius, float inverseDt, float inverseDeltaTime)
            {
                var vo = new VO();

                // Adjusted so that a parameter weightFactor of 1 will be the default ("natural") weight factor
                vo.weightFactor = 1;
                // Just higher than anything else
                vo.weightBonus = Mathf.Max(radius, 1) * 40;

                var closestOnSegment = VectorMath.ClosestPointOnSegment(segmentStart.ToPFV2(), segmentEnd.ToPFV2(), Vector2.zero.ToPFV2());

                // Collision?
                if (closestOnSegment.magnitude <= radius)
                {
                    vo.colliding = true;

                    vo.line1  = closestOnSegment.normalized.ToUnityV3() * (closestOnSegment.magnitude - radius) * 0.3f * inverseDeltaTime;
                    vo.dir1   = new Vector2(vo.line1.y, -vo.line1.x).normalized;
                    vo.line1 += offset;

                    vo.cutoffDir  = Vector2.zero;
                    vo.cutoffLine = Vector2.zero;
                    vo.dir2       = Vector2.zero;
                    vo.line2      = Vector2.zero;
                    vo.radius     = 0;

                    vo.segmentStart = Vector2.zero;
                    vo.segmentEnd   = Vector2.zero;
                    vo.segment      = false;
                }
                else
                {
                    vo.colliding = false;

                    segmentStart *= inverseDt;
                    segmentEnd   *= inverseDt;
                    radius       *= inverseDt;

                    var cutoffTangent = (segmentEnd - segmentStart).normalized;
                    vo.cutoffDir   = cutoffTangent;
                    vo.cutoffLine  = segmentStart + new Vector2(-cutoffTangent.y, cutoffTangent.x) * radius;
                    vo.cutoffLine += offset;

                    // See documentation for details
                    // The call to Max is just to prevent floating point errors causing NaNs to appear
                    var startSqrMagnitude = segmentStart.sqrMagnitude;
                    var normal1           = -VectorMath.ComplexMultiply(segmentStart, new Vector2(radius, Mathf.Sqrt(Mathf.Max(0, startSqrMagnitude - radius * radius)))) / startSqrMagnitude;
                    var endSqrMagnitude   = segmentEnd.sqrMagnitude;
                    var normal2           = -VectorMath.ComplexMultiply(segmentEnd, new Vector2(radius, -Mathf.Sqrt(Mathf.Max(0, endSqrMagnitude - radius * radius)))) / endSqrMagnitude;

                    vo.line1 = segmentStart + normal1.ToUnityV2() * radius + offset;
                    vo.line2 = segmentEnd + normal2.ToUnityV2() * radius + offset;

                    // Note that the normals are already normalized
                    vo.dir1 = new Vector2(normal1.y, -normal1.x);
                    vo.dir2 = new Vector2(normal2.y, -normal2.x);

                    vo.segmentStart = segmentStart;
                    vo.segmentEnd   = segmentEnd;
                    vo.radius       = radius;
                    vo.segment      = true;
                }

                return(vo);
            }
コード例 #23
0
 public static Vector4 Max(Vector4 lhs, Vector4 rhs)
 {
     return(new Vector4(Mathf.Max(lhs.x, rhs.x), Mathf.Max(lhs.y, rhs.y), Mathf.Max(lhs.z, rhs.z), Mathf.Max(lhs.w, rhs.w)));
 }
コード例 #24
0
        RasterizationMesh RasterizeCapsuleCollider(float radius, float height, Bounds bounds, Matrix4x4 localToWorldMatrix)
        {
            // Calculate the number of rows to use
            // grows as sqrt(x) to the radius of the sphere/capsule which I have found works quite well
            int rows = Mathf.Max(4, Mathf.RoundToInt(colliderRasterizeDetail * Mathf.Sqrt(localToWorldMatrix.MultiplyVector(Vector3.one).magnitude)));

            if (rows > 100)
            {
                Debug.LogWarning("Very large detail for some collider meshes. Consider decreasing Collider Rasterize Detail (RecastGraph)");
            }

            int cols = rows;

            Vector3[] verts;
            int[]     trisArr;

            // Check if we have already calculated a similar capsule
            CapsuleCache cached = null;

            for (int i = 0; i < capsuleCache.Count; i++)
            {
                CapsuleCache c = capsuleCache[i];
                if (c.rows == rows && Mathf.Approximately(c.height, height))
                {
                    cached = c;
                }
            }

            if (cached == null)
            {
                // Generate a sphere/capsule mesh

                verts = new Vector3[(rows) * cols + 2];

                var tris = new List <int>();
                verts[verts.Length - 1] = Vector3.up;

                for (int r = 0; r < rows; r++)
                {
                    for (int c = 0; c < cols; c++)
                    {
                        verts[c + r * cols] = new Vector3(Mathf.Cos(c * Mathf.PI * 2 / cols) * Mathf.Sin((r * Mathf.PI / (rows - 1))), Mathf.Cos((r * Mathf.PI / (rows - 1))) + (r < rows / 2 ? height : -height), Mathf.Sin(c * Mathf.PI * 2 / cols) * Mathf.Sin((r * Mathf.PI / (rows - 1))));
                    }
                }

                verts[verts.Length - 2] = Vector3.down;

                for (int i = 0, j = cols - 1; i < cols; j = i++)
                {
                    tris.Add(verts.Length - 1);
                    tris.Add(0 * cols + j);
                    tris.Add(0 * cols + i);
                }

                for (int r = 1; r < rows; r++)
                {
                    for (int i = 0, j = cols - 1; i < cols; j = i++)
                    {
                        tris.Add(r * cols + i);
                        tris.Add(r * cols + j);
                        tris.Add((r - 1) * cols + i);

                        tris.Add((r - 1) * cols + j);
                        tris.Add((r - 1) * cols + i);
                        tris.Add(r * cols + j);
                    }
                }

                for (int i = 0, j = cols - 1; i < cols; j = i++)
                {
                    tris.Add(verts.Length - 2);
                    tris.Add((rows - 1) * cols + j);
                    tris.Add((rows - 1) * cols + i);
                }

                // Add calculated mesh to the cache
                cached        = new CapsuleCache();
                cached.rows   = rows;
                cached.height = height;
                cached.verts  = verts;
                cached.tris   = tris.ToArray();
                capsuleCache.Add(cached);
            }

            // Read from cache
            verts   = cached.verts;
            trisArr = cached.tris;

            return(new RasterizationMesh(verts, trisArr, bounds, localToWorldMatrix));
        }
コード例 #25
0
        public void LateUpdate()
        {
            if (!show || (!Application.isPlaying && !showInEditor))
            {
                return;
            }

            if (Time.unscaledDeltaTime <= 0.0001f)
            {
                return;
            }

            int collCount = System.GC.CollectionCount(0);

            if (lastCollectNum != collCount)
            {
                lastCollectNum = collCount;
                delta          = Time.realtimeSinceStartup - lastCollect;
                lastCollect    = Time.realtimeSinceStartup;
                lastDeltaTime  = Time.unscaledDeltaTime;
                collectAlloc   = allocMem;
            }

            allocMem = (int)System.GC.GetTotalMemory(false);

            bool collectEvent = allocMem < peakAlloc;

            peakAlloc = !collectEvent ? allocMem : peakAlloc;

            if (Time.realtimeSinceStartup - lastAllocSet > 0.3F || !Application.isPlaying)
            {
                int diff = allocMem - lastAllocMemory;
                lastAllocMemory  = allocMem;
                lastAllocSet     = Time.realtimeSinceStartup;
                delayedDeltaTime = Time.unscaledDeltaTime;

                if (diff >= 0)
                {
                    allocRate = diff;
                }
            }

            if (Application.isPlaying)
            {
                fpsDrops[Time.frameCount % fpsDrops.Length] = Time.unscaledDeltaTime > 0.00001f ? 1F / Time.unscaledDeltaTime : 0;
                int graphIndex = Time.frameCount % graph.Length;
                graph[graphIndex].fps          = Time.unscaledDeltaTime < 0.00001f ? 1F / Time.unscaledDeltaTime : 0;
                graph[graphIndex].collectEvent = collectEvent;
                graph[graphIndex].memory       = allocMem;
            }

            if (Application.isPlaying && cam != null && showGraph)
            {
                graphWidth = cam.pixelWidth * 0.8f;


                float minMem = float.PositiveInfinity, maxMem = 0, minFPS = float.PositiveInfinity, maxFPS = 0;
                for (int i = 0; i < graph.Length; i++)
                {
                    minMem = Mathf.Min(graph[i].memory, minMem);
                    maxMem = Mathf.Max(graph[i].memory, maxMem);
                    minFPS = Mathf.Min(graph[i].fps, minFPS);
                    maxFPS = Mathf.Max(graph[i].fps, maxFPS);
                }

                int currentGraphIndex = Time.frameCount % graph.Length;

                Matrix4x4 m = Matrix4x4.TRS(new Vector3((cam.pixelWidth - graphWidth) / 2f, graphOffset, 1), Quaternion.identity, new Vector3(graphWidth, graphHeight, 1));

                for (int i = 0; i < graph.Length - 1; i++)
                {
                    if (i == currentGraphIndex)
                    {
                        continue;
                    }

                    DrawGraphLine(i, m, i / (float)graph.Length, (i + 1) / (float)graph.Length, Mathf.InverseLerp(minMem, maxMem, graph[i].memory), Mathf.InverseLerp(minMem, maxMem, graph[i + 1].memory), Color.blue);
                    DrawGraphLine(i, m, i / (float)graph.Length, (i + 1) / (float)graph.Length, Mathf.InverseLerp(minFPS, maxFPS, graph[i].fps), Mathf.InverseLerp(minFPS, maxFPS, graph[i + 1].fps), Color.green);
                }
            }
        }
コード例 #26
0
ファイル: VoxelContour.cs プロジェクト: pinzeweifen/DCET
        public void BuildContours(float maxError, int maxEdgeLength, VoxelContourSet cset, int buildFlags)
        {
            AstarProfiler.StartProfile("Build Contours");

            AstarProfiler.StartProfile("- Init");
            int w = voxelArea.width;
            int d = voxelArea.depth;

            int wd = w * d;

            //cset.bounds = voxelArea.bounds;

            int maxContours = Mathf.Max(8 /*Max Regions*/, 8);


            //cset.conts = new VoxelContour[maxContours];
            List <VoxelContour> contours = new List <VoxelContour>(maxContours);

            AstarProfiler.EndProfile("- Init");
            AstarProfiler.StartProfile("- Mark Boundaries");

            //cset.nconts = 0;

            //NOTE: This array may contain any data, but since we explicitly set all data in it before we use it, it's OK.
            ushort[] flags = voxelArea.tmpUShortArr;
            if (flags.Length < voxelArea.compactSpanCount)
            {
                flags = voxelArea.tmpUShortArr = new ushort[voxelArea.compactSpanCount];
            }

            // Mark boundaries. (@?)
            for (int z = 0; z < wd; z += voxelArea.width)
            {
                for (int x = 0; x < voxelArea.width; x++)
                {
                    CompactVoxelCell c = voxelArea.compactCells[x + z];

                    for (int i = (int)c.index, ci = (int)(c.index + c.count); i < ci; i++)
                    {
                        ushort           res = 0;
                        CompactVoxelSpan s   = voxelArea.compactSpans[i];

                        if (s.reg == 0 || (s.reg & BorderReg) == BorderReg)
                        {
                            flags[i] = 0;
                            continue;
                        }

                        for (int dir = 0; dir < 4; dir++)
                        {
                            int r = 0;

                            if (s.GetConnection(dir) != NotConnected)
                            {
                                int nx = x + voxelArea.DirectionX[dir];
                                int nz = z + voxelArea.DirectionZ[dir];

                                int ni = (int)voxelArea.compactCells[nx + nz].index + s.GetConnection(dir);
                                r = voxelArea.compactSpans[ni].reg;
                            }

                            //@TODO - Why isn't this inside the previous IF
                            if (r == s.reg)
                            {
                                res |= (ushort)(1 << dir);
                            }
                        }

                        //Inverse, mark non connected edges.
                        flags[i] = (ushort)(res ^ 0xf);
                    }
                }
            }

            AstarProfiler.EndProfile("- Mark Boundaries");

            AstarProfiler.StartProfile("- Simplify Contours");
            List <int> verts = ListPool <int> .Claim(256);         //new List<int> (256);

            List <int> simplified = ListPool <int> .Claim(64);     //new List<int> (64);

            for (int z = 0; z < wd; z += voxelArea.width)
            {
                for (int x = 0; x < voxelArea.width; x++)
                {
                    CompactVoxelCell c = voxelArea.compactCells[x + z];

                    for (int i = (int)c.index, ci = (int)(c.index + c.count); i < ci; i++)
                    {
                        //CompactVoxelSpan s = voxelArea.compactSpans[i];

                        if (flags[i] == 0 || flags[i] == 0xf)
                        {
                            flags[i] = 0;
                            continue;
                        }

                        int reg = voxelArea.compactSpans[i].reg;

                        if (reg == 0 || (reg & BorderReg) == BorderReg)
                        {
                            continue;
                        }

                        int area = voxelArea.areaTypes[i];

                        verts.Clear();
                        simplified.Clear();

                        WalkContour(x, z, i, flags, verts);

                        SimplifyContour(verts, simplified, maxError, maxEdgeLength, buildFlags);
                        RemoveDegenerateSegments(simplified);

                        VoxelContour contour = new VoxelContour();
                        contour.verts = PF.ArrayPool <int> .Claim(simplified.Count);                      //simplified.ToArray ();

                        for (int j = 0; j < simplified.Count; j++)
                        {
                            contour.verts[j] = simplified[j];
                        }
#if ASTAR_RECAST_INCLUDE_RAW_VERTEX_CONTOUR
                        //Not used at the moment, just debug stuff
                        contour.rverts = ClaimIntArr(verts.Count);
                        for (int j = 0; j < verts.Count; j++)
                        {
                            contour.rverts[j] = verts[j];
                        }
#endif
                        contour.nverts = simplified.Count / 4;
                        contour.reg    = reg;
                        contour.area   = area;

                        contours.Add(contour);

                                                #if ASTARDEBUG
                        for (int q = 0, j = (simplified.Count / 4) - 1; q < (simplified.Count / 4); j = q, q++)
                        {
                            int i4 = q * 4;
                            int j4 = j * 4;

                            Vector3 p1 = Vector3.Scale(
                                new Vector3(
                                    simplified[i4 + 0],
                                    simplified[i4 + 1],
                                    (simplified[i4 + 2] / (float)voxelArea.width)
                                    ),
                                cellScale)
                                         + voxelOffset;

                            Vector3 p2 = Vector3.Scale(
                                new Vector3(
                                    simplified[j4 + 0],
                                    simplified[j4 + 1],
                                    (simplified[j4 + 2] / (float)voxelArea.width)
                                    )
                                , cellScale)
                                         + voxelOffset;


                            if (CalcAreaOfPolygon2D(contour.verts, contour.nverts) > 0)
                            {
                                Debug.DrawLine(p1, p2, AstarMath.IntToColor(reg, 0.5F));
                            }
                            else
                            {
                                Debug.DrawLine(p1, p2, Color.red);
                            }
                        }
                                                #endif
                    }
                }
            }

            ListPool <int> .Release(ref verts);

            ListPool <int> .Release(ref simplified);

            AstarProfiler.EndProfile("- Simplify Contours");

            AstarProfiler.StartProfile("- Fix Contours");

            // Check and merge droppings.
            // Sometimes the previous algorithms can fail and create several contours
            // per area. This pass will try to merge the holes into the main region.
            for (int i = 0; i < contours.Count; i++)
            {
                VoxelContour cont = contours[i];
                // Check if the contour is would backwards.
                if (CalcAreaOfPolygon2D(cont.verts, cont.nverts) < 0)
                {
                    // Find another contour which has the same region ID.
                    int mergeIdx = -1;
                    for (int j = 0; j < contours.Count; j++)
                    {
                        if (i == j)
                        {
                            continue;
                        }
                        if (contours[j].nverts > 0 && contours[j].reg == cont.reg)
                        {
                            // Make sure the polygon is correctly oriented.
                            if (CalcAreaOfPolygon2D(contours[j].verts, contours[j].nverts) > 0)
                            {
                                mergeIdx = j;
                                break;
                            }
                        }
                    }
                    if (mergeIdx == -1)
                    {
                        Debug.LogError("rcBuildContours: Could not find merge target for bad contour " + i + ".");
                    }
                    else
                    {
                        // Debugging
                        //Debug.LogWarning ("Fixing contour");

                        VoxelContour mcont = contours[mergeIdx];
                        // Merge by closest points.
                        int ia = 0, ib = 0;
                        GetClosestIndices(mcont.verts, mcont.nverts, cont.verts, cont.nverts, ref ia, ref ib);

                        if (ia == -1 || ib == -1)
                        {
                            Debug.LogWarning("rcBuildContours: Failed to find merge points for " + i + " and " + mergeIdx + ".");
                            continue;
                        }

#if ASTARDEBUG
                        int p4  = ia * 4;
                        int p42 = ib * 4;

                        Vector3 p12 = Vector3.Scale(
                            new Vector3(
                                mcont.verts[p4 + 0],
                                mcont.verts[p4 + 1],
                                (mcont.verts[p4 + 2] / (float)voxelArea.width)
                                ),
                            cellScale)
                                      + voxelOffset;

                        Vector3 p22 = Vector3.Scale(
                            new Vector3(
                                cont.verts[p42 + 0],
                                cont.verts[p42 + 1],
                                (cont.verts[p42 + 2] / (float)voxelArea.width)
                                )
                            , cellScale)
                                      + voxelOffset;

                        Debug.DrawLine(p12, p22, Color.green);
#endif

                        if (!MergeContours(ref mcont, ref cont, ia, ib))
                        {
                            Debug.LogWarning("rcBuildContours: Failed to merge contours " + i + " and " + mergeIdx + ".");
                            continue;
                        }

                        contours[mergeIdx] = mcont;
                        contours[i]        = cont;

                                                #if ASTARDEBUG
                        Debug.Log(mcont.nverts);

                        for (int q = 0, j = (mcont.nverts) - 1; q < (mcont.nverts); j = q, q++)
                        {
                            int i4 = q * 4;
                            int j4 = j * 4;

                            Vector3 p1 = Vector3.Scale(
                                new Vector3(
                                    mcont.verts[i4 + 0],
                                    mcont.verts[i4 + 1],
                                    (mcont.verts[i4 + 2] / (float)voxelArea.width)
                                    ),
                                cellScale)
                                         + voxelOffset;

                            Vector3 p2 = Vector3.Scale(
                                new Vector3(
                                    mcont.verts[j4 + 0],
                                    mcont.verts[j4 + 1],
                                    (mcont.verts[j4 + 2] / (float)voxelArea.width)
                                    )
                                , cellScale)
                                         + voxelOffset;

                            Debug.DrawLine(p1, p2, Color.red);
                            //}
                        }
                                                #endif
                    }
                }
            }

            cset.conts = contours;

            AstarProfiler.EndProfile("- Fix Contours");

            AstarProfiler.EndProfile("Build Contours");
        }
コード例 #27
0
        public void OnGUI()
        {
            if (!show || (!Application.isPlaying && !showInEditor))
            {
                return;
            }

            if (style == null)
            {
                style = new GUIStyle();
                style.normal.textColor = Color.white;
                style.padding          = new RectOffset(5, 5, 5, 5);
            }

            if (Time.realtimeSinceStartup - lastUpdate > 0.5f || cachedText == null || !Application.isPlaying)
            {
                lastUpdate = Time.realtimeSinceStartup;

                boxRect = new Rect(5, yOffset, 310, 40);

                text.Length = 0;
                text.AppendLine("A* Pathfinding Project Debugger");
                text.Append("A* Version: ").Append(AstarPath.Version.ToString());

                if (showMemProfile)
                {
                    boxRect.height += 200;

                    text.AppendLine();
                    text.AppendLine();
                    text.Append("Currently allocated".PadRight(25));
                    text.Append((allocMem / 1000000F).ToString("0.0 MB"));
                    text.AppendLine();

                    text.Append("Peak allocated".PadRight(25));
                    text.Append((peakAlloc / 1000000F).ToString("0.0 MB")).AppendLine();

                    text.Append("Last collect peak".PadRight(25));
                    text.Append((collectAlloc / 1000000F).ToString("0.0 MB")).AppendLine();


                    text.Append("Allocation rate".PadRight(25));
                    text.Append((allocRate / 1000000F).ToString("0.0 MB")).AppendLine();

                    text.Append("Collection frequency".PadRight(25));
                    text.Append(delta.ToString("0.00"));
                    text.Append("s\n");

                    text.Append("Last collect fps".PadRight(25));
                    text.Append((1F / lastDeltaTime).ToString("0.0 fps"));
                    text.Append(" (");
                    text.Append(lastDeltaTime.ToString("0.000 s"));
                    text.Append(")");
                }

                if (showFPS)
                {
                    text.AppendLine();
                    text.AppendLine();
                    var delayedFPS = delayedDeltaTime > 0.00001f ? 1F / delayedDeltaTime : 0;
                    text.Append("FPS".PadRight(25)).Append(delayedFPS.ToString("0.0 fps"));


                    float minFps = Mathf.Infinity;

                    for (int i = 0; i < fpsDrops.Length; i++)
                    {
                        if (fpsDrops[i] < minFps)
                        {
                            minFps = fpsDrops[i];
                        }
                    }

                    text.AppendLine();
                    text.Append(("Lowest fps (last " + fpsDrops.Length + ")").PadRight(25)).Append(minFps.ToString("0.0"));
                }

                if (showPathProfile)
                {
                    AstarPath astar = AstarPath.active;

                    text.AppendLine();

                    if (astar == null)
                    {
                        text.Append("\nNo AstarPath Object In The Scene");
                    }
                    else
                    {
        #if ProfileAstar
                        double searchSpeed = (double)AstarPath.TotalSearchedNodes * 10000 / (double)AstarPath.TotalSearchTime;
                        text.Append("\nSearch Speed	(nodes/ms)	").Append(searchSpeed.ToString("0")).Append(" (" + AstarPath.TotalSearchedNodes + " / ").Append(((double)AstarPath.TotalSearchTime / 10000F).ToString("0") + ")");
        #endif

                        if (ListPool <Vector3> .GetSize() > maxVecPool)
                        {
                            maxVecPool = ListPool <Vector3> .GetSize();
                        }
                        if (ListPool <GraphNode> .GetSize() > maxNodePool)
                        {
                            maxNodePool = ListPool <GraphNode> .GetSize();
                        }

                        text.Append("\nPool Sizes (size/total created)");

                        for (int i = 0; i < debugTypes.Length; i++)
                        {
                            debugTypes[i].Print(text);
                        }
                    }
                }

                cachedText = text.ToString();
            }


            if (font != null)
            {
                style.font     = font;
                style.fontSize = fontSize;
            }

            boxRect.height = style.CalcHeight(new GUIContent(cachedText), boxRect.width);

            GUI.Box(boxRect, "");
            GUI.Label(boxRect, cachedText, style);

            if (showGraph)
            {
                float minMem = float.PositiveInfinity, maxMem = 0, minFPS = float.PositiveInfinity, maxFPS = 0;
                for (int i = 0; i < graph.Length; i++)
                {
                    minMem = Mathf.Min(graph[i].memory, minMem);
                    maxMem = Mathf.Max(graph[i].memory, maxMem);
                    minFPS = Mathf.Min(graph[i].fps, minFPS);
                    maxFPS = Mathf.Max(graph[i].fps, maxFPS);
                }

                float line;
                GUI.color = Color.blue;
                // Round to nearest x.x MB
                line = Mathf.RoundToInt(maxMem / (100.0f * 1000));
                GUI.Label(new Rect(5, Screen.height - AstarMath.MapTo(minMem, maxMem, 0 + graphOffset, graphHeight + graphOffset, line * 1000 * 100) - 10, 100, 20), (line / 10.0f).ToString("0.0 MB"));

                line = Mathf.Round(minMem / (100.0f * 1000));
                GUI.Label(new Rect(5, Screen.height - AstarMath.MapTo(minMem, maxMem, 0 + graphOffset, graphHeight + graphOffset, line * 1000 * 100) - 10, 100, 20), (line / 10.0f).ToString("0.0 MB"));

                GUI.color = Color.green;
                // Round to nearest x.x MB
                line = Mathf.Round(maxFPS);
                GUI.Label(new Rect(55, Screen.height - AstarMath.MapTo(minFPS, maxFPS, 0 + graphOffset, graphHeight + graphOffset, line) - 10, 100, 20), line.ToString("0 FPS"));

                line = Mathf.Round(minFPS);
                GUI.Label(new Rect(55, Screen.height - AstarMath.MapTo(minFPS, maxFPS, 0 + graphOffset, graphHeight + graphOffset, line) - 10, 100, 20), line.ToString("0 FPS"));
            }
        }
コード例 #28
0
        #pragma warning restore 414

    KMSelectable[] ProcessTwitchCommand(string command)
    {
        command = command.ToLowerInvariant().Trim();

        if (Regex.IsMatch(command, @"^press +[0-9^, |&]+$"))
        {
            command = command.Substring(6).Trim();
            var presses   = command.Split(new[] { ',', ' ', '|', '&' }, StringSplitOptions.RemoveEmptyEntries);
            var pressList = new List <KMSelectable>();

            for (int i = 0; i < presses.Length; i++)
            {
                if (Regex.IsMatch(presses[i], @"^[0-9]{1,2}$"))
                {
                    pressList.Add(ModuleButtons[Math.Clamp(Math.Max(1, int.Parse(presses[i].ToString())) - 1, 0, ModuleButtons.Length - 1)]);
                }
            }

            return((pressList.Count > 0) ? pressList.ToArray() : null);
        }

        if (Regex.IsMatch(command, @"^show +([0-9^, |&]|all|top|bottom)+$"))
        {
            if (!ColScreen.activeSelf)
            {
                return(null);
            }

            command = command.Substring(5).Trim();
            var showing  = command.Split(new[] { ',', ' ', '|', '&' }, StringSplitOptions.RemoveEmptyEntries);
            var showList = new List <int>();

            for (int i = 0; i < showing.Length; i++)
            {
                if (Regex.IsMatch(showing[i], @"^[0-9]{1,2}$"))
                {
                    showList.Add(Math.Clamp(Math.Max(1, int.Parse(showing[i].ToString())) - 1, 0, ModuleButtons.Length - 1));
                }
                else
                {
                    showList.Clear();

                    for (int j = ((showing[i].Equals("bottom")) ? 10 : 0); j < 20 - (((showing[i].Equals("top")) ? 10 : 0)); j++)
                    {
                        showList.Add(j);
                    }

                    break;
                }
            }

            if (showList.Count == 0)
            {
                return(null);
            }

            StopAllCoroutines();
            StartCoroutine(ShowScreen(showList));

            return(new KMSelectable[0]);
        }

        if (Regex.IsMatch(command, @"^\s*(colorblind|cb)\s*$"))
        {
            ColScreen.SetActive(true);

            return(new KMSelectable[0]);
        }

        return(null);
    }