/// <summary>
        /// Gets the steering output.
        /// </summary>
        /// <param name="input">The steering input containing relevant information to use when calculating the steering output.</param>
        /// <param name="output">The steering output to be populated.</param>
        public void GetSteering(SteeringInput input, SteeringOutput output)
        {
            GetDesiredSteering(input, output);

            if (output.hasOutput)
            {
                output.desiredAcceleration *= this.weight;
            }
        }
        /// <summary>
        /// Gets the steering output.
        /// </summary>
        /// <param name="input">The steering input containing relevant information to use when calculating the steering output.</param>
        /// <param name="output">The steering output to be populated.</param>
        public void GetSteering(SteeringInput input, SteeringOutput output)
        {
            for (int i = 0; i < _steeringComponents.Count; i++)
            {
                var c = _steeringComponents[i];

                _memberOutput.Clear();
                c.GetSteering(input, _memberOutput);

                output.overrideHeightNavigation |= _memberOutput.overrideHeightNavigation;
                if (_memberOutput.hasOutput)
                {
                    output.desiredAcceleration += _memberOutput.desiredAcceleration;
                    output.verticalForce += _memberOutput.verticalForce;
                    output.maxAllowedSpeed = Mathf.Max(output.maxAllowedSpeed, _memberOutput.maxAllowedSpeed);
                    output.pause |= _memberOutput.pause;
                }
            }
        }
Example #3
0
        protected float GetAngularAcceleration(Vector3 targetOrientation, SteeringInput input)
        {
            var dp = Vector3.Dot(input.unit.forward, targetOrientation);

            //Once the alignment is within a reasonable threshold we just zero out the angular velocity
            if (dp > 0.99999f)
            {
                return(-input.currentAngularSpeed / Time.fixedDeltaTime);
            }

            var targetSpeed = input.desiredAngularSpeed;

            //Check for slow down. Once the unit reaches the threshold, start slowing down.
            var slowMark = 1 - this.slowingDistance;

            if (dp > this.slowingDistance)
            {
                if (this.slowingAlgorithm == SlowingAlgorithm.Logarithmic)
                {
                    targetSpeed *= Mathf.Log10(((9.0f / slowMark) * (1f - dp)) + 1.0f);
                }
                else
                {
                    targetSpeed *= ((1f - dp) / slowMark);
                }

                //We want to avoid turning too slowly towards the end, so stop at a reasonably slow turn pace.
                //This means that the unit will continue at its current turn rate until alignment is complete.
                if (targetSpeed < 0.1f)
                {
                    return(0f);
                }
            }

            //Scale the angular acceleration remaining to reach desired velocity as quick as possible within the bounds of max acceleration.
            float targetAcceleration = input.maxAngularAcceleration;

            targetSpeed = (targetSpeed - input.currentAngularSpeed) / Time.fixedDeltaTime;

            return(Mathf.Clamp(targetSpeed, -targetAcceleration, targetAcceleration));
        }
        /// <summary>
        /// Calculates the angular acceleration.
        /// </summary>
        /// <param name="targetOrientation">The target orientation.</param>
        /// <param name="input">The input.</param>
        /// <returns>The angular acceleration.</returns>
        protected float GetAngularAcceleration(Vector3 targetOrientation, SteeringInput input)
        {
            var dp = Vector3.Dot(input.unit.forward, targetOrientation);

            //Once the alignment is within a reasonable threshold we just zero out the angular velocity
            if (dp > 0.99999f)
            {
                return -input.currentAngularSpeed / Time.fixedDeltaTime;
            }

            var targetSpeed = input.desiredAngularSpeed;

            //Check for slow down. Once the unit reaches the threshold, start slowing down.
            var slowMark = 1 - this.slowingDistance;
            if (dp > this.slowingDistance)
            {
                if (this.slowingAlgorithm == SlowingAlgorithm.Logarithmic)
                {
                    targetSpeed *= Mathf.Log10(((9.0f / slowMark) * (1f - dp)) + 1.0f);
                }
                else
                {
                    targetSpeed *= ((1f - dp) / slowMark);
                }

                //We want to avoid turning too slowly towards the end, so stop at a reasonably slow turn pace.
                //This means that the unit will continue at its current turn rate until alignment is complete.
                if (targetSpeed < 0.1f)
                {
                    return 0f;
                }
            }

            //Scale the angular acceleration remaining to reach desired velocity as quick as possible within the bounds of max acceleration.
            float targetAcceleration = input.maxAngularAcceleration;

            targetSpeed = (targetSpeed - input.currentAngularSpeed) / Time.fixedDeltaTime;

            return Mathf.Clamp(targetSpeed, -targetAcceleration, targetAcceleration);
        }
Example #5
0
 protected Vector3 Arrive(SteeringInput input)
 {
     return(Vector3.ClampMagnitude(-input.currentPlanarVelocity / Time.fixedDeltaTime, input.maxDeceleration));
 }
 /// <summary>
 /// Arrives over a certain time.
 /// </summary>
 /// <param name="timeToTarget">The time to target, i.e. the time over which to stop.</param>
 /// <param name="input">The input.</param>
 /// <returns>The deceleration vector</returns>
 protected Vector3 Arrive(float timeToTarget, SteeringInput input)
 {
     timeToTarget = Mathf.Max(timeToTarget, Time.fixedDeltaTime);
     return Vector3.ClampMagnitude(-input.currentPlanarVelocity / timeToTarget, input.maxDeceleration);
 }
 /// <summary>
 /// Arrives, i.e. stops as fast as possible.
 /// </summary>
 /// <param name="input">The input.</param>
 /// <returns>The deceleration vector</returns>
 protected Vector3 Arrive(SteeringInput input)
 {
     return Vector3.ClampMagnitude(-input.currentPlanarVelocity / Time.fixedDeltaTime, input.maxDeceleration);
 }
 /// <summary>
 /// Flees the specified 'from' position.
 /// </summary>
 /// <param name="position">The position.</param>
 /// <param name="from">From.</param>
 /// <param name="input">The input.</param>
 /// <returns>The flee acceleration vector</returns>
 protected Vector3 Flee(Vector3 position, Vector3 from, SteeringInput input)
 {
     return Seek(from, position, input);
 }
Example #9
0
 /// <summary>
 /// Gets the desired steering output.
 /// </summary>
 /// <param name="input">The steering input containing relevant information to use when calculating the steering output.</param>
 /// <param name="output">The steering output to be populated.</param>
 public abstract void GetDesiredSteering(SteeringInput input, SteeringOutput output);
Example #10
0
 public abstract void GetOrientation(SteeringInput input, OrientationOutput output);
 /// <summary>
 /// Gets the orientation output.
 /// </summary>
 /// <param name="input">The steering input containing relevant information to use when calculating the orientation output.</param>
 /// <param name="output">The orientation output to be populated.</param>
 public abstract void GetOrientation(SteeringInput input, OrientationOutput output);
 /// <summary>
 /// Seeks the specified destination.
 /// </summary>
 /// <param name="destination">The destination.</param>
 /// <param name="input">The input.</param>
 /// <param name="maxAcceleration">The maximum allowed acceleration.</param>
 /// <returns>The seek acceleration vector</returns>
 protected Vector3 Seek(Vector3 destination, SteeringInput input, float maxAcceleration)
 {
     return Seek(input.unit.position, destination, input, maxAcceleration);
 }
        /// <summary>
        /// Gets the desired steering output.
        /// </summary>
        /// <param name="input">The steering input containing relevant information to use when calculating the steering output.</param>
        /// <param name="output">The steering output to be populated.</param>
        public override void GetDesiredSteering(SteeringInput input, SteeringOutput output)
        {
            if (input.currentPlanarVelocity.sqrMagnitude < _minSpeedSquared)
            {
                return;
            }

            var otherUnits = _scanner.Units;
            float maxAdj = 0f;
            float adjSum = 0f;
            Vector3 moveVector = Vector3.zero;

            for (int i = 0; i < otherUnits.Length; i++)
            {
                var other = otherUnits[i];
                if (other.Equals(null) || other.Equals(input.unit.collider))
                {
                    continue;
                }

                Vector3 evadePos;
                var otherVelo = other.GetUnitFacade();

                if (otherVelo == null)
                {
                    evadePos = other.transform.position;
                }
                else
                {
                    var otherPos = otherVelo.position;
                    var distToOther = (otherPos - input.unit.position).magnitude;
                    var otherSpeed = otherVelo.velocity.magnitude;

                    var predictionTime = 0.1f;
                    if (otherSpeed > 0f)
                    {
                        //Half the prediction time for better behavior
                        predictionTime = (distToOther / otherSpeed) / 2f;
                    }

                    evadePos = otherPos + (otherVelo.velocity * predictionTime);
                }

                var offset = input.unit.position - evadePos;
                var offsetMagnitude = offset.magnitude;

                //Only do avoidance if inside vision cone or very close to the unit
                if (offsetMagnitude > _omniAwareRadius && Vector3.Dot(input.unit.forward, offset / offsetMagnitude) > _fovReverseAngleCos)
                {
                    continue;
                }

                //The adjustment normalizes the offset and adjusts its impact according to the offset length, i.e. the further the other unit is away the less it will impact the steering
                var adj = 1f / (offsetMagnitude * offsetMagnitude);
                adjSum += adj;
                if (adj > maxAdj)
                {
                    maxAdj = adj;
                }

                moveVector += (offset * adj);
            }

            if (maxAdj > 0f)
            {
                //Lastly we average out the move vector based on adjustments
                moveVector = moveVector / (adjSum / maxAdj);
                output.desiredAcceleration = Seek(input.unit.position + moveVector, input);
            }
        }
        private void Awake()
        {
            this.WarnIfMultipleInstances();

            _transform = this.transform;
            var rb = this.GetComponent<Rigidbody>();

            //Resolve the mover
            _mover = this.As<IMoveUnits>();
            if (_mover == null)
            {
                var fact = this.As<IMoveUnitsFactory>();
                var charController = this.GetComponent<CharacterController>();

                if (fact != null)
                {
                    _mover = fact.Create();
                }
                else if (charController != null)
                {
                    _mover = new CharacterControllerMover(charController);
                }
                else if (rb != null)
                {
                    _mover = new RigidBodyMover(rb);
                }
                else
                {
                    _mover = new DefaultMover(_transform);
                }
            }

            //Make sure the rigidbody obeys the rules
            if (rb != null)
            {
                rb.constraints |= RigidbodyConstraints.FreezeRotation;
                rb.useGravity = false;
            }

            //Height resolver
            _heights = GameServices.heightStrategy.heightSampler;

            //Assign unit ref, container for components and steering visitors
            _steeringComponents = new List<ISteeringBehaviour>();
            _orientationComponents = new List<IOrientationBehaviour>();
            _steering = new SteeringOutput();
            _orientation = new OrientationOutput();
            _steeringInput = new SteeringInput();
        }
Example #15
0
        protected Vector3 Seek(Vector3 position, Vector3 destination, SteeringInput input, float acceleration)
        {
            var dir = position.DirToXZ(destination);
            var desiredVelocity = dir.normalized * acceleration;

            return desiredVelocity - input.currentPlanarVelocity;
        }
Example #16
0
 protected Vector3 Seek(Vector3 position, Vector3 destination, SteeringInput input)
 {
     return(Seek(position, destination, input, input.maxAcceleration));
 }
Example #17
0
 protected Vector3 Seek(Vector3 destination, SteeringInput input, float acceleration)
 {
     return(Seek(input.unit.position, destination, input, acceleration));
 }
Example #18
0
 protected Vector3 Seek(Vector3 destination, SteeringInput input)
 {
     return(Seek(input.unit.position, destination, input));
 }
 /// <summary>
 /// Gets the desired steering output.
 /// </summary>
 /// <param name="input">The steering input containing relevant information to use when calculating the steering output.</param>
 /// <param name="output">The steering output to be populated.</param>
 public abstract void GetDesiredSteering(SteeringInput input, SteeringOutput output);
 /// <summary>
 /// Seeks the specified destination.
 /// </summary>
 /// <param name="destination">The destination.</param>
 /// <param name="input">The input.</param>
 /// <returns>The seek acceleration vector</returns>
 protected Vector3 Seek(Vector3 destination, SteeringInput input)
 {
     return Seek(input.unit.position, destination, input);
 }
        private void Awake()
        {
            this.WarnIfMultipleInstances();

            _transform = this.transform;
            var rb = this.GetComponent<Rigidbody>();

            //Resolve the mover
            _mover = this.As<IMoveUnits>();
            if (_mover == null)
            {
                var fact = this.As<IMoveUnitsFactory>();
                var charController = this.GetComponent<CharacterController>();

                if (fact != null)
                {
                    _mover = fact.Create();
                }
                else if (charController != null)
                {
                    _mover = new CharacterControllerMover(charController);
                }
                else if (rb != null)
                {
                    _mover = new RigidBodyMover(rb);
                }
                else
                {
                    _mover = new DefaultMover(_transform);
                }
            }

            //Height resolver
            _heights = this.As<IHeightNavigator>();
            if (_heights == null)
            {
                _heights = NoHeightNavigator.Instance;
            }

            //Assign unit ref, container for components and steering visitors
            _steeringComponents = new List<ISteeringBehaviour>();
            _orientationComponents = new List<IOrientationBehaviour>();
            _steering = new SteeringOutput();
            _orientation = new OrientationOutput();
            _steeringInput = new SteeringInput();
        }
Example #22
0
 protected Vector3 Flee(Vector3 position, Vector3 from, SteeringInput input)
 {
     return(Seek(from, position, input));
 }
 /// <summary>
 /// Flees the specified 'from' position.
 /// </summary>
 /// <param name="from">From.</param>
 /// <param name="input">The input.</param>
 /// <returns>The flee acceleration vector</returns>
 protected Vector3 Flee(Vector3 from, SteeringInput input)
 {
     return Seek(from, input.unit.transform.position, input);
 }
 /// <summary>
 /// Seeks from the specified position to a destination.
 /// </summary>
 /// <param name="position">The position from which to seek.</param>
 /// <param name="destination">The destination.</param>
 /// <param name="input">The input.</param>
 /// <returns>The seek acceleration vector</returns>
 protected Vector3 Seek(Vector3 position, Vector3 destination, SteeringInput input)
 {
     return Seek(position, destination, input, input.maxAcceleration);
 }
Example #25
0
 protected Vector3 Arrive(float timeToTarget, SteeringInput input)
 {
     timeToTarget = Mathf.Max(timeToTarget, Time.fixedDeltaTime);
     return(Vector3.ClampMagnitude(-input.currentPlanarVelocity / timeToTarget, input.maxDeceleration));
 }
        /// <summary>
        /// Seeks from the specified position to a destination.
        /// </summary>
        /// <param name="position">The position from which to seek.</param>
        /// <param name="destination">The destination.</param>
        /// <param name="input">The input.</param>
        /// <param name="maxAcceleration">The maximum allowed acceleration.</param>
        /// <returns>The seek acceleration vector</returns>
        protected Vector3 Seek(Vector3 position, Vector3 destination, SteeringInput input, float maxAcceleration)
        {
            var dir = position.DirToXZ(destination);
            var desiredVelocity = dir.normalized * input.desiredSpeed;

            return Vector3.ClampMagnitude((desiredVelocity - input.currentPlanarVelocity) / input.deltaTime, maxAcceleration);
        }
Example #27
0
 protected Vector3 Flee(Vector3 from, SteeringInput input)
 {
     return(Seek(from, input.unit.transform.position, input));
 }