private void FixedUpdate() { transform.position = target.transform.position; camRig.velocity = playerRig.velocity; //transform.rotation = target.transform.rotation; transform.rotation = SmoothDamp.Rotate(transform.rotation, target.transform.rotation, 1f, .5f); }
private void RunFlightModelLinear(float deltaTime) { // Gravity can speed the plane up in a dive, or slow it in a climb. Vector3 gravityForce = Physics.gravity * Mass; // Engines provide thrust forwards. float thrust = FlightInput.Reheat ? ReheatThrust : FlightInput.Throttle * MilThrust; Vector3 thrustForce = transform.forward * thrust; // Drag holds the plane back the faster it goes, until it eventually reaches an equilibrium // between the drag force and thrust at the plane's top speed. float linearDrag = Mathf.Pow(Speed, 2f) * Drag; float totalDrag = linearDrag; // Extending things from the plane increases drag. if (Brakes.ExtendState > Mathf.Epsilon) { totalDrag += linearDrag * Brakes.DragMultiplier * Brakes.ExtendState; } if (Gear.ExtendState > Mathf.Epsilon) { totalDrag += linearDrag * Gear.DragMultiplier * Gear.ExtendState; } if (Flaps.ExtendState > Mathf.Epsilon) { totalDrag += linearDrag * Flaps.DragMultiplier * Flaps.ExtendState; } Vector3 dragForce = -transform.forward * totalDrag; // Induced drag decreases speed when turning. The higher the angle of attack, the more drag. var inducedAOA = Vector3.Angle(transform.forward, VelocityDirection); Vector3 inducedDragForce = -transform.forward * Mathf.Pow(Speed, 2f) * InducedDrag * inducedAOA; // Consider the forces only as they affect forward speed as a simplification of physics. var acceleration = (gravityForce + thrustForce + dragForce + inducedDragForce) / Mass; var forwardAccel = Vector3.Dot(transform.forward, acceleration); Speed += forwardAccel * deltaTime; // Stalling will turn the velocity vector down towards the ground. var stallAOA = Maths.Remap(DynamicStallSpeed, DynamicStallSpeed * 1.5f, StallAOA, 0f, Speed); // The direction that the velocity vector would ideally face. This includes things that // affect it such as stalling, which lowers the velocity vector towards the ground. var targetVelocityVector = transform.forward; targetVelocityVector = Vector3.RotateTowards(targetVelocityVector, Vector3.down, stallAOA * Mathf.Deg2Rad, 0f); // Change the direction of the velocity smoothly so that some alpha gets generated. VelocityDirection = SmoothDamp.Move( VelocityDirection, targetVelocityVector, Responsiveness, deltaTime); Velocity = VelocityDirection * Speed; transform.position += Velocity * Scale * deltaTime; }
private void FixedUpdate() { var targetVolume = Mathf.Lerp(MinVolume, MaxVolume, ship.Pilot.Throttle); smoothVolume = SmoothDamp.Move(audio.volume, targetVolume, 0.5f, Time.fixedDeltaTime); audio.volume = smoothVolume; var targetPitch = Mathf.Lerp(MinPitch, MaxPitch, ship.Pilot.Throttle); smoothPitch = SmoothDamp.Move(audio.pitch, targetPitch, 0.5f, Time.fixedDeltaTime); audio.pitch = smoothPitch; }
private void RunFlightModelRotations(float deltaTime) { PitchG = Maths.CalculatePitchG(transform, Velocity, PitchRate); PitchGSmoothed = SmoothDamp.Move(PitchGSmoothed, PitchG, 3f, deltaTime); // The stall speed affects low speed handling. The lower the stall speed, the more control // the plane has at low speeds. A high stall speed results in not only poor control at low // speed, but also requires more speed to generate the maximum turn rate. var controlAuthority = GetControlAuthority(); // Limit pitch input based on G. This is a reactive system. At low framerates (e.g. 10) the // sample rate will cause oscillations similar to RPMs bouncing off a rev limiter. A better // way to do this would be to pre-calculate a max turn rate based for a given G. float gLerp = PitchG > 0 ? Mathf.InverseLerp(MaxG, MaxG + MaxG * .1f, PitchG) : Mathf.InverseLerp(-MinG, -MinG - MinG * .1f, PitchG); var gLimiter = Mathf.Lerp(0f, 1f, 1f - gLerp); // For each axis, generate a rotation and then damp it to create smooth motion. var targetPitch = FlightInput.Pitch * MaxPitchRate * gLimiter * controlAuthority; PitchRate = SmoothDamp.Move(PitchRate, targetPitch, PitchResponse, deltaTime); var pitchRotation = Quaternion.AngleAxis(PitchRate * deltaTime, Vector3.right); var targetYaw = FlightInput.Yaw * MaxYawRate * controlAuthority; YawRate = SmoothDamp.Move(YawRate, targetYaw, YawResponse, deltaTime); var yawRotation = Quaternion.AngleAxis(YawRate * deltaTime, Vector3.up); var targetRoll = FlightInput.Roll * MaxRollRate * controlAuthority; RollRate = SmoothDamp.Move(RollRate, targetRoll, RollResponse, deltaTime); var rollRotation = Quaternion.AngleAxis(-RollRate * deltaTime, Vector3.forward); transform.localRotation *= pitchRotation * rollRotation * yawRotation; // When stalling, the plane pitches down towards the ground. var stallRate = GetStallRate(); if (stallRate > 0f) { // Generate stall rotation. var stallAxis = Vector3.Cross(transform.forward, Vector3.down); transform.rotation = Quaternion.AngleAxis(stallRate * deltaTime, stallAxis) * transform.rotation; } }
public void Update(Pilot pilot, ref ShipSpecs specs) { if (isDestroyed) { return; } rigidbody.AddRelativeTorque( pilot.Pitch * specs.Engine.Torque * Multiplier, pilot.Yaw * specs.Engine.Torque * Multiplier, -pilot.Roll * specs.Engine.Torque * Multiplier); // Ramp up/down speed for smoother acceleration. smoothThrottle = SmoothDamp.Move( smoothThrottle, pilot.Throttle, specs.Engine.Accel, Time.fixedDeltaTime); rigidbody.AddRelativeForce( Vector3.forward * specs.Engine.Thrust * Multiplier * smoothThrottle, ForceMode.Force); }
private void RunGroundHandling(float deltaTime) { var hitSomething = Physics.Raycast( origin: transform.position, direction: -transform.up, hitInfo: out RaycastHit hitInfo, maxDistance: GearHeight * 2f, layerMask: CollisionMask); // Panic early escape in something weird happened. // Might trigger if the player drove off a sheer cliff? if (!hitSomething) { IsGrounded = false; return; } Vector3 thrustForce = CalculateThrustForce(); Vector3 dragForce = CalculateDragForce(); Vector3 gravityForce = CalculateGravityForce(); var accelerationVector = (thrustForce + dragForce + gravityForce) / Mass; if (accelerationVector.y <= 0f) { // If the velocity vector is still pointing down, the plane is still grounded. // Care only about the speed/acceleration in the forward direction. (No slipping.) var acceleration = Vector3.Dot(transform.forward, accelerationVector); Speed += acceleration * deltaTime; // Brakes get an extra boost to being stopping because of wheel brakes. Speed = Mathf.MoveTowards(Speed, 0f, Brakes.ExtendState * 5f * deltaTime); // Stalling will turn the velocity vector down towards the ground. var stallAOA = Maths.Remap(DynamicStallSpeed, DynamicStallSpeed * 1.5f, StallAOA, 0f, Speed); // The direction that the velocity vector would ideally face. This includes things that // affect it such as stalling, which lowers the velocity vector towards the ground. var targetVelocityVector = transform.forward; targetVelocityVector = Vector3.RotateTowards(targetVelocityVector, Vector3.down, stallAOA * Mathf.Deg2Rad, 0f); if (targetVelocityVector.y < 0f) { // Velocity still isn't going up, so stay ground clamped. targetVelocityVector.y = 0f; Velocity = targetVelocityVector * Speed; VelocityDirection = targetVelocityVector; transform.position += Velocity * Scale * deltaTime; // Handle rotation. Re-uses a lot of the same code as the flying stuff. PitchG = 1f; PitchGSmoothed = 1f; // Pitching uses the same control authority as in flight to simulate aerodynamics. var controlAuthority = GetControlAuthority(); // Same pitching code as when in flight, but without the stalling rotation stuff. var targetPitch = FlightInput.Pitch * MaxPitchRate * controlAuthority; var stallRate = GetStallRate() * deltaTime; PitchRate = SmoothDamp.Move(PitchRate + stallRate, targetPitch, PitchResponse, deltaTime); LandedPitchAngle += PitchRate * deltaTime; // Prevent pitch down into the ground while grounded. The way the rotation math // works out, negative values for pitch are what result in a pitch up. LandedPitchAngle = Mathf.Clamp(LandedPitchAngle, -30f, 0f); var pitchRotation = Quaternion.AngleAxis(LandedPitchAngle, Vector3.right); // Nosewheel steering allows the plane to be turned while on the ground. // Blend roll and yaw so that roll can be used to steer on the ground like in old games. // You'd probably want this to be optional in a real game. const float NosewheelTurnRate = 45f; const float NosewheelSteeringResponse = 3f; float nosewheelSteeringYawRate = Speed >= 5f ? Mathf.InverseLerp(45f, 15f, Speed) : Mathf.InverseLerp(0f, 5f, Speed); // Allow for some yaw authority after nosewheel steering reaches zero power so that // adjustments can continue to be made at high speed. In real life, this would be // caused by the rudder rather than any kind of steering system. This specific // method has the side effect of allowing the plane to turn in place while stopped, // but I won't tell if you don't. float maxYawRate = Mathf.Max( NosewheelTurnRate * 0.1f, nosewheelSteeringYawRate * NosewheelTurnRate); var blendedYawInput = Mathf.Clamp(FlightInput.Yaw + FlightInput.Roll, -1f, 1f); var targetYaw = blendedYawInput * maxYawRate; YawRate = SmoothDamp.Move(YawRate, targetYaw, NosewheelSteeringResponse, deltaTime); var yawRotation = Quaternion.AngleAxis(YawRate * deltaTime, Vector3.up); // This SERIOUSLY breaks down if the ground beneath the player isn't flat. To fix // this requires some fancy vector math that I don't have a handle on quite yet. var flattenedForward = GetFlattenedForward(); transform.rotation = Quaternion.LookRotation(flattenedForward, hitInfo.normal); transform.localRotation *= yawRotation * pitchRotation; } else { // Acceleration vector now points skywards. Take off! IsGrounded = false; Debug.Log($"{name}: Took off!"); } } else { // The velocity vector is starting to point upwards, which means the plane wants to go // up and the plane has taken off. IsGrounded = false; } }
private void LateUpdate() { if (!_active) { return; } // スピードダウン if (Input.GetButtonDown(InputPredefined.JOYSTICK_LEFT_PRESS) || Input.GetKeyDown(KeyCode.F)) { switch (_speedMode) { case SpeedMode.Default: _speedMode = SpeedMode.Slow; break; case SpeedMode.Turbo: _speedMode = SpeedMode.Default; break; default: break; } } // スピードアップ if (Input.GetButtonDown(InputPredefined.JOYSTICK_RIGHT_PRESS) || Input.GetKeyDown(KeyCode.G)) { switch (_speedMode) { case SpeedMode.Default: _speedMode = SpeedMode.Turbo; break; case SpeedMode.Slow: _speedMode = SpeedMode.Default; break; default: break; } } _mousePosDelta = Input.mousePosition - _prevMousePos; _prevMousePos = Input.mousePosition; _nextPosition = transform.position; // 速度の設定 var movingSpeed = _movingSensitivity; var hoveringSpeed = _hoveringSensitivity; if (Input.GetKey(KeyCode.LeftShift)) { _speedMode = SpeedMode.Turbo; } else { _speedMode = SpeedMode.Default; } switch (_speedMode) { case SpeedMode.Slow: movingSpeed = _movingSensitivity * 0.5f; hoveringSpeed = _hoveringSensitivity * 0.5f; break; case SpeedMode.Default: movingSpeed = _movingSensitivity * 1.0f; hoveringSpeed = _hoveringSensitivity * 1.0f; break; case SpeedMode.Turbo: movingSpeed = _movingSensitivity * 2.0f; hoveringSpeed = _hoveringSensitivity * 2.0f; break; default: break; } movingSpeed *= transform.lossyScale.x; var smoothness = _smoothMode == SmoothMode.Smooth ? _smoothness : _noSmoothness; var deltaTime = Time.deltaTime; var rightDir = transform.right; var upDir = _axisMode == AxisMode.Global ? Vector3.up : transform.up; var forwardDir = _axisMode == AxisMode.Global ? Vector3.ProjectOnPlane(transform.forward, Vector3.up) : transform.forward; var leftJoystick = new Vector2(Input.GetAxis(InputPredefined.HORIZONTAL_LEFT), Input.GetAxis(InputPredefined.VERTICAL_LEFT)); var rightJoystick = new Vector2(Input.GetAxis(InputPredefined.HORIZONTAL_RIGHT), Input.GetAxis(InputPredefined.VERTICAL_RIGHT)); var trigger = 0f; if (Input.GetAxis(InputPredefined.TRIGGER_LEFT) > 0f) { trigger = -_hoveringSensitivity * (Input.GetAxis(InputPredefined.TRIGGER_LEFT) + 1) / 2.0f; } else if (Input.GetAxis(InputPredefined.TRIGGER_RIGHT) > 0f) { trigger = _hoveringSensitivity * (Input.GetAxis(InputPredefined.TRIGGER_RIGHT) + 1) / 2.0f; } if (Input.GetMouseButton(1) || Input.GetKey(KeyCode.LeftAlt) && Input.GetMouseButton(0) || leftJoystick.sqrMagnitude > 0f || rightJoystick.sqrMagnitude > 0f || trigger != 0f) { // キーボード移動 if (Input.GetKey(KeyCode.W)) { _nextPosition = _nextPosition + forwardDir * movingSpeed; } if (Input.GetKey(KeyCode.A)) { _nextPosition = _nextPosition - rightDir * movingSpeed; } if (Input.GetKey(KeyCode.S)) { _nextPosition = _nextPosition - forwardDir * movingSpeed; } if (Input.GetKey(KeyCode.D)) { _nextPosition = _nextPosition + rightDir * movingSpeed; } if (Input.GetKey(KeyCode.Q)) { _nextPosition = _nextPosition - upDir * hoveringSpeed; } if (Input.GetKey(KeyCode.E)) { _nextPosition = _nextPosition + upDir * hoveringSpeed; } // コントローラー移動 _nextPosition += rightDir * leftJoystick.x * movingSpeed + forwardDir * leftJoystick.y * movingSpeed + upDir * trigger * movingSpeed; // マウス回転 _elapsedAngles.y += Input.GetAxis(InputPredefined.MOUSE_X) * _rotationSensitivity; _elapsedAngles.x += -Input.GetAxis(InputPredefined.MOUSE_Y) * _rotationSensitivity; // コントローラー回転 _elapsedAngles.y += rightJoystick.x * _rotationSensitivity; _elapsedAngles.x += -rightJoystick.y * _rotationSensitivity; transform.localRotation = SmoothDamp.Pow(transform.localRotation, Quaternion.Euler( new Vector3(_elapsedAngles.x, _elapsedAngles.y, 0f)), smoothness, deltaTime); } else if (Input.GetMouseButton(2)) { var mouseDelta = _mousePosDelta; _nextPosition -= rightDir * mouseDelta.x * movingSpeed * 0.1f; _nextPosition -= upDir * mouseDelta.y * movingSpeed * 0.1f; //Debug.Log("mouseDelta : " + mouseDelta); } if (Input.mousePosition.x < Screen.width && Input.mousePosition.x > 0 && Input.mousePosition.y < Screen.height && Input.mousePosition.y > 0) { // マウスホイール前後移動 _nextPosition += forwardDir * Input.GetAxis(InputPredefined.MOUSE_SCROLLWHEEL) * movingSpeed * _mouseWheelSensitivity; } transform.position = SmoothDamp.Pow(transform.position, _nextPosition, smoothness, deltaTime); // ズーム if (Input.GetKey(KeyCode.C) || Input.GetButton(InputPredefined.BUMPER_RIGHT_PRESS)) { _cam.fieldOfView = SmoothDamp.Pow(_cam.fieldOfView, _defaultFov * 0.5f, 0.01f, deltaTime); } else if (Input.GetKey(KeyCode.Z) || Input.GetButton(InputPredefined.BUMPER_LEFT_PRESS)) { _cam.fieldOfView = SmoothDamp.Pow(_cam.fieldOfView, _defaultFov * 1.5f, 0.01f, deltaTime); } else { _cam.fieldOfView = SmoothDamp.Pow(_cam.fieldOfView, _defaultFov, 0.01f, deltaTime); } }