예제 #1
0
    public static void Simulate(PlayerSimulationConfig config, IRigidbody body, PlayerInput input)
    {
        Vector3 forward = body.State.Rotation * Vector3.forward;
        Vector3 up      = body.State.Rotation * Vector3.up;

        float speedFactor     = Mathf.Clamp01((body.State.Velocity.magnitude - 5f) / 10f);
        float forwardDot      = Mathf.Clamp01(1f - forward.y);
        float rollAngle       = MathUtils.AngleAroundAxis(up, Vector3.up, forward);
        float rollInducedBank = Mathf.Pow(Mathf.Clamp01(Mathf.Abs(rollAngle) * MathUtils.OneOver180 * forwardDot * speedFactor), 1.5f) * Mathf.Sign(rollAngle);

        float rollStabilizer = Mathf.Pow(Mathf.Clamp01(Mathf.Abs(rollAngle) * MathUtils.OneOver180 * forwardDot), 2f) * Mathf.Sign(rollAngle);

        rollStabilizer *= 1f - Mathf.Abs(input.Roll);

        body.AddRelativeTorque(new Vector3(
                                   input.Pitch * config.RotationSpeed.x + Mathf.Abs(rollInducedBank) * -0.66f * config.RotationSpeed.x,
                                   input.Yaw * config.RotationSpeed.y + rollInducedBank * 0.66f * config.RotationSpeed.y,
                                   input.Roll * -config.RotationSpeed.z + rollStabilizer * 0.66f * config.RotationSpeed.z),
                               ForceMode.Force);

        float maxThrust = input.Boost ? 50f : 20f;

        body.AddRelativeForce(Vector3.forward * maxThrust * input.Thrust, ForceMode.Force);

        Vector3 offHeadingVelocity = body.State.Velocity - Vector3.Project(body.State.Velocity, forward);
        Vector3 dampening          = offHeadingVelocity * -2.0f;
        Vector3 conserved          = offHeadingVelocity.magnitude * forward * 0.33f;

        body.AddForce(dampening + conserved + Vector3.down, ForceMode.Force);
    }
예제 #2
0
    private void UpdateStatistics()
    {
        /* Note: Calculating position derivatives in Update caused framerate dependent effects to happen
         * (which is what caused the OrbitCamera to lag behind at low fps) */

        /* Update altitudes. */
        _altitudeSeaLevel = _body.transform.position.y;
        RaycastHit hit;

        if (Physics.Raycast(_body.transform.position, Vector3.down, out hit, Mathf.Infinity, _layerMask))
        {
            _altitudeGround = hit.distance;
            //Debug.Log("I hit this thang: " + hit.collider.name);
        }

        /* Find position derivatives. */
        Vector3 velocity    = _body.velocity;
        Vector3 oldVelocity = RigidbodyState.Lerp(_historyBuffer, Time.fixedTime - 0.25f).Velocity;

        _acceleration = (velocity - oldVelocity) / 0.25f;

        Vector3 localAngularVelocity = _body.transform.InverseTransformDirection(_body.angularVelocity);

        _localAngularAcceleration = localAngularVelocity - _localAngularVelocity;
        _localAngularVelocity     = localAngularVelocity;

        /* Determine relative wind vector. */
        Vector3 windVelocity = _wind.GetWindVelocity(_body.transform.position);

        _relativeVelocity = _body.velocity - windVelocity;
        _trueAirspeed     = _relativeVelocity.magnitude;

        /* Determine angle of attack. */
        Vector3 v1 = _body.transform.TransformDirection(_rollAxis);
        Vector3 v2 = _relativeVelocity.normalized;
        Vector3 n  = _body.transform.TransformDirection(_pitchAxis);

        _angleOfAttack = MathUtils.AngleAroundAxis(v1, v2, n);

        /* Determine glide ratio. */
        float horizontalDistance = Mathf.Sqrt(Mathf.Pow(_body.velocity.x, 2f) + Mathf.Pow(_body.velocity.z, 2f));
        float verticalDistance   = -_body.velocity.y;

        _glideRatio = horizontalDistance / verticalDistance;

        /* Determine Angle to ground for local axes. */
        Vector3 rollAxisCenter = _body.transform.forward;

        _angleToGroundRoll = MathUtils.AngleAroundAxis(Vector3.down, rollAxisCenter,
                                                       _body.transform.TransformDirection(_rollAxis));
        Vector3 forward          = _body.transform.TransformDirection(_rollAxis);
        Vector3 projectedForward = new Vector3(forward.x, 0f, forward.z);

        _angleToGroundPitch = MathUtils.AngleAroundAxis(projectedForward, forward,
                                                        _body.transform.TransformDirection(_pitchAxis));

        _historyBuffer.Enqueue(RigidbodyState.ToImmutable(_body, Time.fixedTime));
    }
예제 #3
0
    private float GetAxis(Vector3 controllerVector, Vector3 baseVector, Vector3 rotationAxis)
    {
        const float maxAngle = 45f;
        float       angle    = MathUtils.AngleAroundAxis(controllerVector, baseVector, rotationAxis);
        float       input    = Mathf.Clamp(angle / maxAngle, -1f, 1f);

        input = MathUtils.ScaleQuadratically(input, 2f);
        return(input);
    }
예제 #4
0
    private void FixedUpdate()
    {
        if (_body == null || _wind == null)
        {
            return;
        }

        if (OnPreFixedUpdate != null)
        {
            OnPreFixedUpdate(this);
        }

        Vector3 centerPosition = transform.position;

        Vector3 windVelocity = _wind.GetWindVelocity(centerPosition);
        float   airDensity   = _wind.GetAirDensity(centerPosition);

        RelativeVelocity = _body.velocity - windVelocity;
        AirSpeed         = RelativeVelocity.magnitude;

        Vector3 worldLongitudinalAxis = transform.TransformDirection(_longitudinalAxis);
        Vector3 axis = Vector3.Cross(worldLongitudinalAxis, RelativeVelocity).normalized;

        AngleOfAttack = MathUtils.AngleAroundAxis(worldLongitudinalAxis, RelativeVelocity, axis);

        float liftCoefficient = _liftCoeffients.Evaluate(AngleOfAttack) * _liftCoefficientMultiplier;
        float dragCoefficient = _dragCoeffients.Evaluate(AngleOfAttack) * _dragCoefficientMultiplier;

        float dynamicSurfacePressure = 0.5f * airDensity * _referenceArea * AirSpeed * AirSpeed;

        // Todo: can optimize by not normalizing relative velocity
        LiftForce = Vector3.Cross(RelativeVelocity, axis).normalized *(dynamicSurfacePressure * liftCoefficient);
        DragForce = -RelativeVelocity.normalized * (dynamicSurfacePressure * dragCoefficient);

        _body.AddForceAtPosition(LiftForce + DragForce, transform.position);

        if (OnPostFixedUpdate != null)
        {
            OnPostFixedUpdate(this);
        }
    }
예제 #5
0
    private void EvaluateForces()
    {
        Transform wingTransform = transform;
        Vector3   wingPosition  = wingTransform.position;

        Vector3 windVelocity = _wind.GetWindVelocity(wingPosition);
        float   airDensity   = _wind.GetAirDensity(wingPosition);

        Vector3 velocity = (wingPosition - _lastPosition) / Time.deltaTime;

        _lastPosition    = wingPosition;
        RelativeVelocity = velocity - windVelocity;
        AirSpeed         = RelativeVelocity.magnitude;

        const float groundEffectHeight     = 32f;
        const float groundEffectPow        = 2f;
        float       groundEffectMultiplier = 1f;
        RaycastHit  hit;

        if (Physics.Raycast(_body.transform.position, Vector3.down, out hit, groundEffectHeight, _layerMask))
        {
            groundEffectMultiplier += Mathf.Pow(Mathf.InverseLerp(groundEffectHeight, 0f, hit.distance), groundEffectPow);
        }

        UpdateStats(wingTransform);

        // Calculate forces per section of the wing
        for (int i = 0; i < _numSections; i++)
        {
            var section = _sectionStates[i];

            Vector3 sectionWorldPosition = wingTransform.TransformPoint(section.LocalPosition);
            Vector3 sectionWorldVelocity = (sectionWorldPosition - section.LastSectionWorldPosition) / Time.fixedDeltaTime;
            section.LastSectionWorldPosition = sectionWorldPosition;
            section.RelativeVelocity         = sectionWorldVelocity - windVelocity;

            section.AirSpeed = section.RelativeVelocity.magnitude;

            float dynamicPressure = 0.5f * airDensity * section.AirSpeed * section.AirSpeed * groundEffectMultiplier;

            section.Lift   = Vector3.zero;
            section.Drag   = Vector3.zero;
            section.Moment = Vector3.zero;

            //Vector3 localRelativeVelocity = wingTransform.InverseTransformDirection(section.RelativeVelocity);

            // Calculate the effects around each axis
            for (int j = 0; j < _components.Length; j++)
            {
                AirfoilAxisResponse coefficient = _components[j];
                AirfoilAxis         airfoilAxis = _axes[(int)coefficient.AxisType];

                Vector3 worldAxis     = wingTransform.TransformDirection(airfoilAxis.Axis);
                Vector3 worldAxisBase = wingTransform.TransformDirection(airfoilAxis.AxisZero);

                // Todo: Collapse this all into 2D calculations around the coefficient axis

                Vector3 projectedVelocity = section.RelativeVelocity - Vector3.Project(section.RelativeVelocity, worldAxis);
                section.AngleOfAttack = MathUtils.AngleAroundAxis(worldAxisBase, projectedVelocity, worldAxis);
                Vector3 sectionRelativeDirection = projectedVelocity.normalized;

                float forceCoefficient = coefficient.Coefficients.Evaluate(section.AngleOfAttack + section.Offset) * coefficient.Multiplier;
                float forceMagnitude   = dynamicPressure * section.SurfaceArea * forceCoefficient;

                var input = new SectionForceInput()
                {
                    body                     = _body,
                    force                    = forceMagnitude,
                    efficiency               = _efficiency,
                    section                  = section,
                    sectionWorldPosition     = sectionWorldPosition,
                    sectionRelativeDirection = sectionRelativeDirection,
                    worldAxis                = worldAxis,
                    worldAxisZero            = worldAxisBase
                };

                //ForceApplicators[(int) coefficient.Type](input);
                switch (coefficient.Type)
                {
                case ForceType.Lift:
                    ApplyLift(input);
                    break;

                case ForceType.Drag:
                    ApplyDrag(input);
                    break;

                case ForceType.Moment:
                    ApplyMoment(input);
                    break;
                }
            }
        }
    }