// Update is called once per frame void FixedUpdate() { float leftTrig = 0.0f; float rightTrig = 0.0f; if (leftTrackedObject != null && leftTrackedObject.isActiveAndEnabled) { // The trigger button leftTrig = leftController.GetAxis(Valve.VR.EVRButtonId.k_EButton_Axis1).x; } if (rightTrackedObject != null && rightTrackedObject.isActiveAndEnabled) { // The trigger button rightTrig = rightController.GetAxis(Valve.VR.EVRButtonId.k_EButton_Axis1).x; } if (leftTrig > 0.2f) { rigidBody.AddForceAtPosition(leftTrackedObject.transform.forward * power * leftTrig, leftTrackedObject.transform.position); } else { } leftEngine.GetComponent <JetFire>().fire = leftTrig; float max = 3999; SteamVR_Controller.Input( SteamVR_Controller.GetDeviceIndex(SteamVR_Controller.DeviceRelation.Leftmost) ).TriggerHapticPulse((ushort)(leftTrig * max)); SteamVR_Controller.Input( SteamVR_Controller.GetDeviceIndex(SteamVR_Controller.DeviceRelation.Rightmost) ).TriggerHapticPulse((ushort)(rightTrig * max)); rightEngine.GetComponent <JetFire>().fire = rightTrig; if (rightTrig > 0.2f) { rigidBody.AddForceAtPosition(rightTrackedObject.transform.forward * power * rightTrig, rightTrackedObject.transform.position); } else { } rigidBody.velocity = Vector3.ClampMagnitude(rigidBody.velocity, maxSpeed); //rigidBody.velocity = Vector3.ClampMagnitude(rigidBody.velocity, 10f); /* * if (leftTrig > 0.2f && rightTrig > 0.2f) * { * rigidBody.AddForce(head.transform.forward * power * 10); * } * else if (leftTrig > 0.2f) * { * desiredYaw *= Quaternion.AngleAxis(leftTrig * 0.5f, Vector3.up); * } * else if (rightTrig > 0.2f) * { * desiredYaw *= Quaternion.AngleAxis(rightTrig * 0.5f, -Vector3.up); * } * * float currentYaw = transform.rotation.eulerAngles.y; * transform.rotation = Quaternion.Slerp(transform.rotation, desiredYaw, Time.deltaTime); */ }
private void pushRigidBody(Rigidbody rb) { rb.AddForceAtPosition(mainCamera.transform.forward * power, hit.point, ForceMode.Impulse); UIController.AddScoreUIForFPP(1); }
// Update is called once per frame void Update() { rb.AddForceAtPosition(Vector3.down * carConfig.downForce, transform.position + transform.forward, ForceMode.Acceleration); rb.AddForceAtPosition(Vector3.down * carConfig.downForce, transform.position - transform.forward, ForceMode.Acceleration); }
private void PullEndpoints() { float num = 0f; for (int i = 1; i < this.m_nodes.Count; i++) { Rigidbody rigidbody = this.m_nodes[i - 1].rigidbody; Rigidbody rigidbody2 = this.m_nodes[i].rigidbody; if (rigidbody && rigidbody2) { float num2 = Vector3.Distance(rigidbody.position, rigidbody2.position); if (i > 1 && i < this.m_nodes.Count - 2) { if (num2 > 1.25f) { this.Cut(i); return; } } else if (num2 > 1.75f) { this.Cut(i); return; } num += num2; } } float num3 = 0.5f * (float)this.m_nodes.Count; float num4 = num / (1.18f * num3) - 1f; float num5 = 0.4f; num4 = num5 * this.ResponseCurve(num4 / num5); num4 = Mathf.Clamp(num4, 0f, num5); float num6 = num4 - this.m_previousStretchFactor; this.m_previousStretchFactor = num4; if (num > 1.18f * num3) { Rigidbody rigidbody3 = this.m_nodes[0].rigidbody; Rigidbody rigidbody4 = this.m_nodes[1].rigidbody; Vector3 position = rigidbody3.position; Vector3 position2 = rigidbody4.position; if (num6 < 0f) { num4 *= 0.7f; } float num7 = 750f; float num8 = num7 * num4; num8 = Mathf.Clamp(num8, 0f, 300f); Vector3 force = num8 * (position2 - position).normalized; if (this.LeftPart) { rigidbody3.AddForceAtPosition(force, position, ForceMode.Force); } rigidbody3 = this.m_nodes[this.m_nodes.Count - 1].rigidbody; rigidbody4 = this.m_nodes[this.m_nodes.Count - 2].rigidbody; position = rigidbody3.position; position2 = rigidbody4.position; force = num8 * (position2 - position).normalized; if (this.RightPart) { rigidbody3.AddForceAtPosition(force, position, ForceMode.Force); } } }
/// <summary> /// Handles the gravity and hovering for the ship. /// </summary> public void Gravity() { // Reset gravity/magstrip bShipIsGrounded = false; bShipIsOnMagStrip = false; // Increase the rideheight slightly (keeps the ship at the actual wanted height) float rideHeight = GlobalSettings.shipRideHeight * 1.2f; // Pitching if (controller.inputPitch != 0) { shipPitchAmount = Mathf.Lerp(shipPitchAmount, controller.inputPitch * GlobalSettings.shipPitchGroundAmount, Time.deltaTime * GlobalSettings.shipPitchDamping); } else { shipPitchAmount = Mathf.Lerp(shipPitchAmount, 0.0f, Time.deltaTime * GlobalSettings.shipPitchDamping); } shipBody.AddTorque(transform.right * (shipPitchAmount * 10)); // Get the current class and set the gravity multipliers float gravityMul = 0; float trackGrav = 0; float flightGrav = 0; switch (eventSpeedClass) { case GlobalSettings.SpeedClasses.D: // Gravity Multiplier gravityMul = GlobalSettings.airGravityMulD; // Track Gravity trackGrav = GlobalSettings.shipTrackGravityD; // Flight Gravity flightGrav = GlobalSettings.shipFlightGravityD; break; case GlobalSettings.SpeedClasses.C: // Gravity Multiplier gravityMul = GlobalSettings.airGravityMulC; // Track Gravity trackGrav = GlobalSettings.shipTrackGravityC; // Flight Gravity flightGrav = GlobalSettings.shipFlightGravityC; break; case GlobalSettings.SpeedClasses.B: // Gravity Multiplier gravityMul = GlobalSettings.airGravityMulB; // Track Gravity trackGrav = GlobalSettings.shipTrackGravityB; // Flight Gravity flightGrav = GlobalSettings.shipFlightGravityB; break; case GlobalSettings.SpeedClasses.A: // Gravity Multiplier gravityMul = GlobalSettings.airGravityMulA; // Track Gravity trackGrav = GlobalSettings.shipTrackGravityA; // Flight Gravity flightGrav = GlobalSettings.shipFlightGravityA; break; case GlobalSettings.SpeedClasses.AP: // Gravity Multiplier gravityMul = GlobalSettings.airGravityMulAP; // Track Gravity trackGrav = GlobalSettings.shipTrackGravityAP; // Flight Gravity flightGrav = GlobalSettings.shipFlightGravityAP; break; case GlobalSettings.SpeedClasses.APP: // Gravity Multiplier gravityMul = GlobalSettings.airGravityMulAPP; // Track Gravity trackGrav = GlobalSettings.shipTrackGravityAPP; // Flight Gravity flightGrav = GlobalSettings.shipFlightGravityAPP; break; } // Create hover points list List <Vector3> hoverPoints = new List <Vector3>(); // Get a slightly smaller area of the ship size Vector2 hoverArea = new Vector2(settings.physColliderSize.x / 2, settings.physColliderSize.z / 2.05f); // Add hover points hoverPoints.Add(transform.TransformPoint(-hoverArea.x, Mathf.Clamp(shipPitchAmount, 0.0f, 0.5f), hoverArea.y)); // Front Left hoverPoints.Add(transform.TransformPoint(hoverArea.x, Mathf.Clamp(shipPitchAmount, 0.0f, 0.5f), hoverArea.y)); // Front Right hoverPoints.Add(transform.TransformPoint(hoverArea.x, Mathf.Clamp(-shipPitchAmount, 0.0f, 0.7f), -hoverArea.y)); // Back Right hoverPoints.Add(transform.TransformPoint(-hoverArea.x, Mathf.Clamp(-shipPitchAmount, 0.0f, 0.7f), -hoverArea.y)); // Back Left // Run through each hover point and apply hover forces if needed for (int i = 0; i < hoverPoints.Count; i++) { // Bitshift track floor and mag lock layers into a new integer for the ship to only check for those two collision layers int trackFloorMask = 1 << LayerMask.NameToLayer("TrackFloor") | 1 << LayerMask.NameToLayer("Maglock"); // Create raycasthit to store hit data into RaycastHit hoverHit; // Raycast down for track if (Physics.Raycast(hoverPoints[i], -transform.up, out hoverHit, rideHeight, trackFloorMask)) { // Get the distance to the ground float dist = hoverHit.distance; // Normalize the distance into a compression ratio float compressionRatio = ((dist / rideHeight) - 1) * -1; // Get the velocity at the hover point Vector3 hoverVel = shipBody.GetPointVelocity(hoverPoints[i]); // Project the velocity onto the ships up vector Vector3 projForce = Vector3.Project(hoverVel, transform.up); // Check to see if the ship is on a magstrip if (hoverHit.collider.gameObject.layer == LayerMask.NameToLayer("Maglock")) { bShipIsOnMagStrip = true; } /* Calculate force needed to push ship away from track */ // Set a force multiplier float forceMult = 5; // Calcaulate a ratio to multiply the compression ratio by (drasticly increases the hover force as it gets closer to the track) float forceRatio = ((dist / 2) / (rideHeight / 2) - 1) * -forceMult; // Clamp the ratio forceRatio = Mathf.Clamp(forceRatio, 2.0f, 10.0f); // Create the new force float force = 200.0f * (compressionRatio * forceRatio); /* Calculate damping amount to bring the ship to rest quicker */ // Set a damping multiplier float dampMult = 6.5f; // Calculate a ratio to multiply the compression ratio by float dampRatio = ((dist / 2) / (rideHeight / 2) - 1) * -dampMult; // Clamp the ratio dampRatio = Mathf.Clamp(dampRatio, 1.0f, 5.5f); // Clamp the compression ratio, min being the base damp amount float clampedCR = Mathf.Clamp(compressionRatio, 0.5f, 1.0f); // Get the landing rebound to dampen forces straight after a long fall (stops the ship rebounding high off the track) float reboundDamper = Mathf.Clamp(shipReboundLand * 15, 1.0f, Mathf.Infinity); // Create the new damping force float damping = (1 * (clampedCR * dampRatio) * reboundDamper); // If the ship is over a magstrip then we want the ship to act a bit differently if (bShipIsOnMagStrip) { // Calculate how strong the magstrip is based on the ships current angular velocity and speed float magStrength = Mathf.Abs(transform.InverseTransformDirection(shipBody.angularVelocity).x *Time.deltaTime) * Mathf.Abs(transform.InverseTransformDirection(shipBody.velocity).z *Time.deltaTime); // Multiply the strength as the above calculate will result in a terrible lock strength magStrength *= 1000; // Clamp the strength so it can't be too strong magStrength = Mathf.Clamp(magStrength, 0.0f, (transform.InverseTransformDirection(shipBody.velocity).z *Time.deltaTime) * 3.8f); // Set new force and damping multipliers force = (trackGrav * (5.0f + magStrength)); damping = 2f; // Apply the magstrip lock force shipBody.AddForceAtPosition(-transform.up * (trackGrav * (magStrength * 4.0f)), hoverPoints[i], ForceMode.Acceleration); } // Calculate the suspension force Vector3 suspensionForce = transform.up * compressionRatio * force; // Now apply damping Vector3 dampedForce = suspensionForce - (projForce * damping); // Finally, apply the force shipBody.AddForceAtPosition(dampedForce, hoverPoints[i], ForceMode.Acceleration); // Set the grounded boolean to true bShipIsGrounded = true; // Debug line if (bDebugVisualizeHovering) { Debug.DrawLine(hoverPoints[i], hoverHit.point); } // Force feedback if (dist < rideHeight * 0.6f) { vibrationManager.vibLeftMotor = 0.3f; vibrationManager.vibRightMotor = 0.3f; vibrationManager.timerMotor = 1.1f; } } } /* If the ship is grounded then we also want to have the ship be pulled down by gravity * We want to do another raycast for the trackfloor layer only from the centre of the ship * then calculate everything from that. * * Don't worry, we are only casting for one layer over a short distance, this isn't very * expensive to do. */ // Create raycasthit to store hit data into RaycastHit centreHit; // Raycast down if (Physics.Raycast(transform.position, -transform.up, out centreHit, rideHeight, 1 << LayerMask.NameToLayer("TrackFloor"))) { // Use a dot product to find out how much we need to rotate the ship to get it to face down Vector3 trackRot = transform.forward - (Vector3.Dot(transform.forward, centreHit.normal) * centreHit.normal); // Use the track rotation to calculate how much we are going to rotate the ship float rotAmount = (trackRot.x * trackRot.z) * (Mathf.Clamp(Mathf.Abs(trackRot.y), 0.0f, 0.1f) * 10); // Increase the rotation amount as the ship speeds up float rotForce = 20 + (transform.InverseTransformDirection(shipBody.velocity).z *Time.deltaTime) * 1.2f; // Apply the rotation transform.Rotate(Vector3.up * (rotAmount * Time.deltaTime) * rotForce); // Apply gravity force shipBody.AddForce(new Vector3(centreHit.normal.x, 0, centreHit.normal.z) * (Mathf.Abs(trackRot.x)) * 22); } /* We also want to check for pads on the track. We'll do exactly the same as above to do this. * Also we can recycle the centrehit variable! */ // Bitshift pads into integer int padMask = 1 << LayerMask.NameToLayer("SpeedPad") | 1 << LayerMask.NameToLayer("WeaponPad"); // Raycast down if (Physics.Raycast(transform.position, -transform.up, out centreHit, rideHeight + 2, padMask)) { // If the ship hits a speed pad then apply the appropiate force if (centreHit.collider.gameObject.layer == LayerMask.NameToLayer("SpeedPad")) { // Get the pad's forward direction speedPadDirection = centreHit.collider.gameObject.transform.right * GlobalSettings.speedPadAmount; // Set the ships boost timer shipBoostTimer = GlobalSettings.speedPadTime; // Set boosting to true bShipIsBoosting = true; // If we havn't hit this pad already, play the boost sound if (!bShipHitPad) { bShipHitPad = true; // Get sound to play AudioClip boostSFX = Resources.Load("Audio/Ships/BoostSpeedPad") as AudioClip; // Play the sound PlayOneShot.PlayShot("BoostSFX", 1.0f, 1.0f, 50.0f, 500.0f, transform, transform.position, boostSFX); } } } else { // We are not hitting a pad, set the hitting pad boolean to false bShipHitPad = false; } // If the boost timer is over zero then we want to decrease it and apply any boost the ship has if (shipBoostTimer > 0) { // Decrease timer shipBoostTimer -= Time.deltaTime; // Apply pad boost shipBody.AddForce(speedPadDirection, ForceMode.Acceleration); } else { // Make sure that the pad hit boolean is no longer true bShipHitPad = false; // Override boost if the ship has boost power from a barrel rol if (shipBRBoostTimer > 0) { bShipIsBoosting = true; // Apply the barrel roll boost shipBody.AddForce(transform.forward * settings.engineTurbo, ForceMode.Acceleration); } else { // Otherwise the boosting is set to false bShipIsBoosting = false; } } // Allow the turbo pickup to override the boost if (bShipBoostingOverride) { bShipIsBoosting = true; } // Boosting Force Feedback if (bShipIsBoosting) { vibrationManager.timerMotor = 1.1f; vibrationManager.vibLeftMotor = 0.4f; vibrationManager.vibRightMotor = 0.4f; } /* And finally we want to apply gravity, we want to swap out the gravity between two different variables * which allows the ship to feel much lighter on the track, this also makes the hovering feel much better too */ // Check to see if the ship is grounded if (bShipIsGrounded) { // If the ship is on a magstrip then the gravity wants to be heavier if (bShipIsOnMagStrip) { // Set gravity shipGravityForce = -transform.up * (trackGrav * 5); } else { // Set gravity shipGravityForce = -transform.up * trackGrav; } // Set the rebound jump time so the stick force is always maxed when the ship enters flight shipReboundJump = settings.agReboundJumpTime; // Decrease the rebound land shipReboundLand -= Time.deltaTime; } else { // Set the gravity shipGravityForce = Vector3.down * (flightGrav * gravityMul); // Decrease the jump shipReboundJump -= Time.deltaTime; // Apply the stick force if (shipReboundJump > 0) { // Apply the force to keep the ship grounded shipBody.AddForce(Vector3.down * ((10 * GlobalSettings.shipNormalGravity) * settings.agRebound), ForceMode.Acceleration); } // Set rebound to zero if it has gone under zero if (shipReboundLand < 0) { shipReboundLand = 0; } // Increase the rebound land shipReboundLand += Time.deltaTime; // Clamp the rebound land if (shipReboundLand > settings.agReboundLanding) { shipReboundLand = settings.agReboundLanding; } // Slowly rotate the ship forward transform.Rotate(Vector3.right * 0.05f); } // And finally, apply the gravity shipBody.AddForce(shipGravityForce, ForceMode.Acceleration); }
/*This is the die effect. A simple-complicated effect of subdivide any big part of the player. * Only works for this "marvellous designed" game character ;) Assume that it works of everything made of cubes and have no children under a mesh renderer ! * This effect is pretty heavy to process because of the high number of instance done, and should make disappear the part of the body quickly to avoid too much object in the scene, or at least cut the physics. **/ void DieEffect(Bullet bullet) { //First we search all the gameObject that compose the player. We don't take the root. SearchAllGameobject(transform.GetChild(0)); //Calculation of the volume represented by the given subdivision float volumeSubdivision = Mathf.Pow(sizeSubdivision, 3f); int subDivisionMaxCount = 0; int subDivisionCount = 0; BloodManager.instance.setTimeBeforeDisappear(timeBeforeDivideOnDeath); BloodManager.instance.registerNewBloodMaterial(new Material(bloodMaterial)); foreach (GameObject gameObj in physicalObjects) { //We just move the object to the instance manager, to clean the scene InstanceManager.instance.MoveTo(InstanceManager.InstanceType.Graphics, gameObj); //We add box and rigidbody to this object, we set the layer BoxCollider boxObj = gameObj.AddComponent <BoxCollider>(); boxObj.isTrigger = false; Rigidbody rigidObj = gameObj.AddComponent <Rigidbody>(); gameObj.layer = LayerMask.NameToLayer("Default"); //We disable the box collider and the rigidbody for now boxObj.enabled = false; rigidObj.useGravity = false; rigidObj.isKinematic = true; //Here's the touchy part : If the object can contains at least 4 subdivision, we'll devide it if (gameObj.transform.lossyScale.x * gameObj.transform.lossyScale.y * gameObj.transform.lossyScale.z >= 4f * volumeSubdivision && gameObj.tag != "DontSubdivide") { //First we calculate how many subdivision we are going to have on each side x, y, z. We ceil it to avoid a 0 case. Vector3 maxSubdivision = gameObj.transform.lossyScale / sizeSubdivision; maxSubdivision = new Vector3(Mathf.Ceil(maxSubdivision.x), Mathf.Ceil(maxSubdivision.y), Mathf.Ceil(maxSubdivision.z)); //To simply the maths, we'll use the child property to adjust local position. The local position for one of the cube angle is -0.5, -0.5, -0.5 //We had the half of a subdivision size to avoid a translation for instancing the small object (if not, the subdivision will be center at the corner, which is not good) Vector3 positionOriginSubdivision = (Vector3.one * -0.5f) + new Vector3(1f / (maxSubdivision.x * 2f), 1f / (maxSubdivision.y * 2f), 1f / (maxSubdivision.z * 2f)); subDivisionCount = 0; //We are rolling all subdivision for (int x = 0; x < maxSubdivision.x; x++) { for (int y = 0; y < maxSubdivision.y; y++) { for (int z = 0; z < maxSubdivision.z; z++) { //The global scale of the subdivision Vector3 scaleSubdivision = new Vector3(gameObj.transform.localScale.x / maxSubdivision.x, gameObj.transform.localScale.y / maxSubdivision.y, gameObj.transform.localScale.z / maxSubdivision.z); //Local subdivision position, by going from Vector3(-0.5) to Vector3(0.5) Vector3 positionSubdivision = positionOriginSubdivision + new Vector3((x / maxSubdivision.x), (y / maxSubdivision.y), (z / maxSubdivision.z)); //Instancing the mini object from the blood pool GameObject miniObject = BloodManager.instance.GetPoolInstance(); miniObject.transform.position = positionSubdivision; miniObject.transform.rotation = gameObj.transform.rotation; //We set the local scale (which is the global scale) miniObject.transform.localScale = scaleSubdivision; //We set it under the parent object to conserve physic-links for the beginning //This trick avoid us to do the maths of the correct translation, taking rotation into account miniObject.transform.SetParent(gameObj.transform); miniObject.transform.localPosition = positionSubdivision; //If the object is "hidden" in the center of the cube subdivided //Tag "SubdivideTop" : top of the cube, don't display bloody subdivision at the top //Tag "SubdivideBottom" : bottom of the cube, don't display bloody subdivision at the bottom if ((x > 0 && x < maxSubdivision.x - 1 && z > 0 && z < maxSubdivision.z - 1) && ((y > 0 || gameObj.CompareTag("SubdivideBottom") || gameObj.CompareTag("SubdivideInside")) && (y < maxSubdivision.y - 1 || gameObj.CompareTag("SubdivideTop") || gameObj.CompareTag("SubdivideInside")))) { //The Cubes insides are blood BloodManager.instance.registerNewBloodObject(miniObject.GetComponent <BloodObject>() ?? miniObject.AddComponent <BloodObject>()); } else { //The cubes are body part, we change the material miniObject.GetComponent <MeshRenderer>().sharedMaterial = gameObj.GetComponent <MeshRenderer>().sharedMaterial; BloodManager.instance.registerNewBodyPartObject(miniObject.GetComponent <BloodObject>() ?? miniObject.AddComponent <BloodObject>()); } instRigidObject.Add(miniObject.GetComponent <Rigidbody>()); subDivisionCount++; } } } //The layer of the parent must be in a layer that exclude the subdivisions, to avoid conflict during forces gameObj.layer = LayerMask.NameToLayer("AvoidMovables"); //We enable all the physics. Note that it can be tweaked to have a better rag-doll reaction. boxObj.enabled = true; rigidObj.useGravity = true; rigidObj.isKinematic = false; rigidObj.mass = 0.2f; rigidObj.drag = 10f; rigidObj.angularDrag = 0f; //To move the parent object, we had a force relative to the bullet position and the bullet physical force rigidObj.AddForceAtPosition((bullet.transform.forward).normalized * bullet.physicalForceBullet, bullet.transform.position, ForceMode.Force); //We take the biggest part of the body to carry other tiny parts if (subDivisionCount > subDivisionMaxCount) { parentObjectOfTinyBodyPart = gameObj; subDivisionMaxCount = subDivisionCount; } gameObj.GetComponent <MeshRenderer>().enabled = false; parentToDestroy.Add(gameObj); } else //If it's too small, we don't devide and use the object itself { BloodManager.instance.registerNewBodyPartObject(rigidObj.gameObject.AddComponent <BloodObject>()); bodyPartRigidObject.Add(rigidObj); } } //If there's any parent of subdivision, we find the biggest one and assume that it's the body. if (parentObjectOfTinyBodyPart != null) { //We make children every body parts that are not subdivide foreach (Rigidbody rbo in bodyPartRigidObject) { rbo.transform.SetParent(parentObjectOfTinyBodyPart.transform); } } //We apply a force into all the small object, like a shockwave, closer the object is from the impact, higher will be the force. //Only the object in the shockwave moves. Others stays non-physics for the moment foreach (Rigidbody rbo in instRigidObject) { float rboDistance = Vector3.Distance(rbo.transform.position, bullet.transform.position); if (rboDistance < bullet.impactRadius) { InstanceManager.instance.MoveTo(InstanceManager.InstanceType.Graphics, rbo.gameObject); rbo.isKinematic = false; rbo.useGravity = true; rbo.isKinematic = false; rbo.GetComponent <BoxCollider>().enabled = true; rbo.AddForce((rbo.transform.position - bullet.transform.position).normalized * bullet.forceImpactInRadius.Evaluate(rboDistance / bullet.impactRadius) * bullet.forceImpact, ForceMode.Impulse); } } instRigidObject.RemoveAll(c => c.useGravity); instRigidObject.AddRange(bodyPartRigidObject); //We enable physics after a shot period of time Invoke("EnableAllRigidbodyPhysics", timeBeforeDivideOnDeath); }
public static Vector3 DoAeroForces(MissileLauncher ml, Vector3 targetPosition, float liftArea, float steerMult, Vector3 previousTorque, float maxTorque, float maxAoA, FloatCurve liftCurve, FloatCurve dragCurve) { Rigidbody rb = ml.part.rb; double airDensity = ml.vessel.atmDensity; double airSpeed = ml.vessel.srfSpeed; Vector3d velocity = ml.vessel.srf_velocity; //temp values Vector3 CoL = new Vector3(0, 0, -1f); float liftMultiplier = BDArmorySettings.GLOBAL_LIFT_MULTIPLIER; float dragMultiplier = BDArmorySettings.GLOBAL_DRAG_MULTIPLIER; //lift float AoA = Mathf.Clamp(Vector3.Angle(ml.transform.forward, velocity.normalized), 0, 90); if (AoA > 0) { double liftForce = 0.5 * airDensity * Math.Pow(airSpeed, 2) * liftArea * liftMultiplier * liftCurve.Evaluate(AoA); Vector3 forceDirection = Vector3.ProjectOnPlane(-velocity, ml.transform.forward).normalized; rb.AddForceAtPosition((float)liftForce * forceDirection, ml.transform.TransformPoint(ml.part.CoMOffset + CoL)); } //drag if (airSpeed > 0) { double dragForce = 0.5 * airDensity * Math.Pow(airSpeed, 2) * liftArea * dragMultiplier * dragCurve.Evaluate(AoA); rb.AddForceAtPosition((float)dragForce * -velocity.normalized, ml.transform.TransformPoint(ml.part.CoMOffset + CoL)); } //guidance if (airSpeed > 1) { Vector3 targetDirection; float targetAngle; if (AoA < maxAoA) { targetDirection = (targetPosition - ml.transform.position); targetAngle = Vector3.Angle(velocity.normalized, targetDirection) * 4; } else { targetDirection = velocity.normalized; targetAngle = AoA; } Vector3 torqueDirection = -Vector3.Cross(targetDirection, velocity.normalized).normalized; torqueDirection = ml.transform.InverseTransformDirection(torqueDirection); float torque = Mathf.Clamp(targetAngle * steerMult, 0, maxTorque); Vector3 finalTorque = Vector3.ProjectOnPlane(Vector3.Lerp(previousTorque, torqueDirection * torque, 1), Vector3.forward); rb.AddRelativeTorque(finalTorque); return(finalTorque); } else { Vector3 finalTorque = Vector3.ProjectOnPlane(Vector3.Lerp(previousTorque, Vector3.zero, 0.25f), Vector3.forward); rb.AddRelativeTorque(finalTorque); return(finalTorque); } }
void FixedUpdate() { // Do hover/bounce force RaycastHit hit; bool onGround = false; for (int i = 0; i < hoverPoints.Length; i++) { var hoverPoint = hoverPoints[i]; //lancer de rayons pour savoir si le véhicule est au sol if (Physics.Raycast(hoverPoint.transform.position, -Vector3.up, out hit, hoverHeight, layerMask)) { //surélévation du véhicule afin d'éviter les frottement avec le sol body.AddForceAtPosition(Vector3.up * hoverForce * (0.9f - (hit.distance / hoverHeight)), hoverPoint.transform.position); onGround = true; } else { //si le véhicule n'est pas au sol on simule la gravité pour le faire descendre //stabilise également le véhicule si il se trouve de travers if (transform.position.y > hoverPoint.transform.position.y) { body.AddForceAtPosition(hoverPoint.transform.up * gravityForce, hoverPoint.transform.position); } else { body.AddForceAtPosition(hoverPoint.transform.up * -gravityForce, hoverPoint.transform.position); } } } //emission d'une trainée si le vehicule est au sol var emissionRate = 0; if (onGround) { body.drag = groundedDrag; emissionRate = 10; } else { body.drag = 0.1f; thrust /= 100f; turnValue /= 100f; } // émettre une trainée derrière le véhicule if (dustTrails.Length > 0) { for (int i = 0; i < dustTrails.Length; i++) { var emission = dustTrails[i].emission; } } // faire avancer/reculer le vehicule if (Mathf.Abs(thrust) > 0) { body.AddForce(transform.forward * thrust); } // faire tourner le vehicule if (turnValue > 0) { body.AddRelativeTorque(Vector3.up * turnValue * turnStrength); } else if (turnValue < 0) { body.AddRelativeTorque(Vector3.up * turnValue * turnStrength); } if (body.velocity.sqrMagnitude > (body.velocity.normalized * maxVelocity).sqrMagnitude) { body.velocity = body.velocity.normalized * maxVelocity; } }
// Update is called once per frame void Update() { if (!isGrounded && canDash && particulasJump.gameObject.activeSelf == false) { StartCoroutine(turnJumpParticlesOn()); } if (!isGrounded && !canDash) { particulasJump.gameObject.SetActive(false); } //Registra la velocidad en X y Y del personaje lastFrameVelocity = rb.velocity; velY = rb.velocity.y; velX = rb.velocity.x; //Si el jugador esta moviendose mientras no esta en el aire, reproduce la animacion de Grund Dash if (Gdash) { knight_animation.SetBool("Gdash", true); } else { knight_animation.SetBool("Gdash", false); } //Regristra si el jugador esta moviendose para las animaciones speed = rb.velocity.magnitude; knight_animation.SetFloat("speed", (float)velX); if (alive) { if (Input.GetKeyDown(KeyCode.R)) { saved_variables.progreso.score = 0; saved_variables.progreso.hscore = 0; saved_variables.progreso.Tutorial = true; } //Checks if player is touching the ground if (isGrounded) { //Apaga las particulas que indican si tienes un dash extra disponible transform.GetChild(5).gameObject.SetActive(false); //Indica que estoy haciendo un dash en el suelo if (velX > 0 && velY == 0) { Gdash = true; } //Si el jugador "aterriza", hace que su velocidad sea 0 para que no derrape if (landing && velY <= 0) { landing = false; rb.velocity = new Vector3(0, 0, 0); } } //Dash if (direction == 0 && dashTime == startDashTime && !p.paused) { //Testing with mouse if (Input.GetButtonDown("Fire1") && !p.paused) { touchStart = Input.mousePosition; } if (Input.GetButtonUp("Fire1") && !p.paused) { touchEnd = Input.mousePosition; direction = 5; stopDashing = false; transform.GetChild(5).gameObject.SetActive(false); } } else { //Checks if dash is complete and if so, returns direction to 0. Allowing the player to dash again. if (dashTime <= 0.0f && !stopDashing) { stopDashing = true; dashTime = startDashTime; direction = 0; } else { if (!p.paused) { if (!stopDashing) { dashTime -= Time.deltaTime; } if (direction == 1) { rb.velocity = Vector3.left * dashSpeed; } else if (direction == 2) { rb.velocity = Vector3.right * dashSpeed; } else if (direction == 3) { canDash = false; rb.velocity = Vector3.up * dashSpeed; } else if (direction == 4) { rb.velocity = Vector3.down * dashSpeed; } else if (direction == 5) { DoInput(); } } } } //Jump if (isGrounded && Input.GetKeyDown(KeyCode.Space) && !p.paused) { jump(); } if (!isGrounded && Input.GetKeyDown(KeyCode.Space)) { groundPound(); } if (!isGrounded && direction == 0) { if (rb) { rb.AddForceAtPosition(new Vector3(0f, fallMultiplier * -1, 0f), Vector3.down); } } } }
// SuperCollision - Adds actual force for marble-marble collisions across the network. [RPC] public void SuperCollision(Vector3 velocity, Vector3 position) { //marbody.AddExplosionForce(velocity.magnitude * 5, position, 2, 0.25f, ForceMode.Impulse); marbody.AddForceAtPosition(velocity, position - (Vector3.up * 0.25f), ForceMode.Impulse); }
void Break(LinkedShape shape, Vector3 point, Vector3 force, float quantitéDeMouvement, bool addVelocity) { if (linkedShapes.Count <= 1) { return; } if (intactVisual != null) { intactVisual.enabled = false; } //double time1 = EditorApplication.timeSinceStartup; Vector3 dir = force.normalized; float propagation = Mathf.Max(0, 0.025f * force.magnitude / (0.5f + elasticity) / massPerBlock); List <List <LinkedShape> > groups = shape.FormGroupsWithNeighbors(propagation, force.normalized, Mathf.Max(linkedShapes.Count / 2, 1), point); //Validate neighbors int totalInGroups = 0; for (int i = 0; i < groups.Count; i++) { totalInGroups += groups[i].Count; foreach (LinkedShape item in groups[i]) { item.ValidateNeighbors(groups[i]); } } int skipLastGroup = linkedShapes.Count > totalInGroups ? 0 : 1; //Remove groups from list for (int i = 0; i < groups.Count - skipLastGroup; i++) { List <LinkedShape> group = groups[i]; foreach (LinkedShape item in group) { linkedShapes.Remove(item); } } //Parcourt de l'arbre pour séparé les région qui ne sont plus en contact List <List <LinkedShape> > newGroups = FindSeperatedRegions(); for (int i = 0; i < newGroups.Count; i++) { totalInGroups += newGroups[i].Count; foreach (LinkedShape item in newGroups[i]) { item.ValidateNeighbors(newGroups[i]); } } //Remove newGroups from list for (int i = 0; i < newGroups.Count; i++) { foreach (LinkedShape item in newGroups[i]) { linkedShapes.Remove(item); } } //Ajoute les nouveaux groupes à la liste groups.AddRange(newGroups); //Kinematic settings bool resetKinematic = false; if (myRb.isKinematic) { resetKinematic = true; myRb.isKinematic = false; } Vector3 oldMassCenter = myRb.worldCenterOfMass; float velocityChange = quantitéDeMouvement / (totalInGroups * massPerBlock); //Nouveaux blocka for (int i = 0; i < groups.Count - skipLastGroup; i++) { List <LinkedShape> group = groups[i]; FragmentTree newTree = Instantiate(newChunkPrefab.gameObject).GetComponent <FragmentTree>(); newTree.linkedShapes = group; newTree.hardness = hardness; newTree.debugDraw = debugDraw; newTree.relinkTree = false; newTree.newChunkPrefab = newChunkPrefab; newTree.elasticity = elasticity; newTree.original = original; newTree.massPerBlock = massPerBlock; Rigidbody rb = newTree.GetComponent <Rigidbody>(); rb.velocity = myRb.velocity; rb.angularVelocity = myRb.angularVelocity; rb.mass = newTree.linkedShapes.Count * massPerBlock; rb.drag = myRb.drag; rb.angularDrag = myRb.angularDrag; rb.ResetCenterOfMass(); foreach (LinkedShape item in group) { item.shape.tr.SetParent(newTree.transform, true); } Vector3 dist = rb.worldCenterOfMass - point; float alignment = Vector3.Dot(dist.normalized, dir); //de 0 à 1 //float forceRatio = Mathf.Max(1.5f + 0.5f*alignment, 0.1f); // REMOVE float distanceFactor = Mathf.Pow(1 / (dist.magnitude + 1), elasticity); // de 0 à 1 Vector3 addVel = dir * velocityChange * alignment * distanceFactor * 2; //print("remains: " + alignment * distanceFactor + " vel: " + addVel); if (addVelocity) { rb.AddForceAtPosition(addVel, point, ForceMode.VelocityChange); } //rb.AddExplosionForce(force.magnitude*forceRatio, point, 10, 0); } //Reset mass settings myRb.ResetCenterOfMass(); myRb.mass = linkedShapes.Count * massPerBlock; if (resetKinematic) { Vector3 newCenterOfMass = myRb.worldCenterOfMass; if (oldMassCenter.y < newCenterOfMass.y) { myRb.isKinematic = false; } else { myRb.isKinematic = true; } } }
//Add all forces that act on the squares below the water void AddUnderWaterForces() { //The resistance coefficient - same for all triangles float Cf = BoatPhysicsMath.ResistanceCoefficient( rhoWater, boatRB.velocity.magnitude, modifyBoatMesh.CalculateUnderWaterLength()); //To calculate the slamming force we need the velocity at each of the original triangles List <SlammingForceData> slammingForceData = modifyBoatMesh.slammingForceData; CalculateSlammingVelocities(slammingForceData); //Need this data for slamming forces float boatArea = modifyBoatMesh.boatArea; float boatMass = boatRB.mass; //Replace this line with your boat's total mass //To connect the submerged triangles with the original triangles List <int> indexOfOriginalTriangle = modifyBoatMesh.indexOfOriginalTriangle; //Get all triangles List <TriangleData> underWaterTriangleData = modifyBoatMesh.underWaterTriangleData; for (int i = 0; i < underWaterTriangleData.Count; i++) { TriangleData triangleData = underWaterTriangleData[i]; //Calculate the forces Vector3 forceToAdd = Vector3.zero; //Force 1 - The hydrostatic force (buoyancy) forceToAdd += BoatPhysicsMath.BuoyancyForce(rhoWater, triangleData); //Force 2 - Viscous Water Resistance forceToAdd += BoatPhysicsMath.ViscousWaterResistanceForce(rhoWater, triangleData, Cf); //Force 3 - Pressure drag forceToAdd += BoatPhysicsMath.PressureDragForce(triangleData); //Force 4 - Slamming force //Which of the original triangles is this triangle a part of int originalTriangleIndex = indexOfOriginalTriangle[i]; SlammingForceData slammingData = slammingForceData[originalTriangleIndex]; forceToAdd += BoatPhysicsMath.SlammingForce(slammingData, triangleData, boatArea, boatMass); //Add the forces to the boat boatRB.AddForceAtPosition(forceToAdd, triangleData.center); //Debug //SlammingForce //Debug.DrawRay (triangleData.center, BoatPhysicsMath.SlammingForce (slammingData, triangleData, boatArea, boatMass), Color.blue); //Normal //Debug.DrawRay(triangleData.center, triangleData.normal * 3f, Color.white); //Buoyancy //Debug.DrawRay(triangleData.center, BoatPhysicsMath.BuoyancyForce(rhoWater, triangleData).normalized * -3f, Color.red); //Velocity //Debug.DrawRay(triangleCenter, triangleVelocityDir * 3f, Color.black); //Viscous Water Resistance //Debug.DrawRay(triangleData.center, BoatPhysicsMath.ViscousWaterResistanceForce(rhoWater, triangleData, Cf).normalized * 0.3f, Color.black); } }
/// <summary> /// The object has taken been damaged. /// </summary> /// <param name="amount">The amount of damage taken.</param> /// <param name="position">The position of the damage.</param> /// <param name="direction">The direction that the object took damage from.</param> /// <param name="forceMagnitude">The magnitude of the force that is applied to the object.</param> /// <param name="frames">The number of frames to add the force to.</param> /// <param name="radius">The radius of the explosive damage. If 0 then a non-explosive force will be used.</param> /// <param name="attacker">The GameObject that did the damage.</param> /// <param name="hitCollider">The Collider that was hit.</param> public virtual void OnDamage(float amount, Vector3 position, Vector3 direction, float forceMagnitude, int frames, float radius, GameObject attacker, Collider hitCollider) { #if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER if (m_NetworkInfo != null && m_NetworkInfo.IsServer()) { m_NetworkHealthMonitor.OnDamage(amount, position, direction, forceMagnitude, frames, radius, attacker, hitCollider); } #endif // Add a multiplier if a particular collider was hit. Do not apply a multiplier if the damage is applied through a radius because multiple // collider are hit. if (radius == 0 && direction != Vector3.zero && hitCollider != null) { Hitbox hitbox; if (m_ColliderHitboxMap != null && m_ColliderHitboxMap.Count > 0) { if (m_ColliderHitboxMap.TryGetValue(hitCollider, out hitbox)) { amount *= hitbox.DamageMultiplier; } else { // The main collider may be overlapping child hitbox colliders. Perform one more raycast to ensure a hitbox collider shouldn't be hit. float distance = 0.2f; if (hitCollider is CapsuleCollider) { distance = (hitCollider as CapsuleCollider).radius; } else if (hitCollider is SphereCollider) { distance = (hitCollider as SphereCollider).radius; } // The hitbox collider may be underneath the base collider. Fire a raycast to detemine if there are any colliders underneath the hit collider // that should apply a multiplier. var hitCount = Physics.RaycastNonAlloc(position, direction, m_RaycastHits, distance, ~(1 << LayerManager.IgnoreRaycast | 1 << LayerManager.Overlay | 1 << LayerManager.VisualEffect), QueryTriggerInteraction.Ignore); for (int i = 0; i < hitCount; ++i) { var closestRaycastHit = QuickSelect.SmallestK(m_RaycastHits, hitCount, i, m_RaycastHitComparer); if (closestRaycastHit.collider == hitCollider) { continue; } // A new collider has been found - stop iterating if the hitbox map exists and use the hitbox multiplier. if (m_ColliderHitboxMap.TryGetValue(closestRaycastHit.collider, out hitbox)) { amount *= hitbox.DamageMultiplier; hitCollider = hitbox.Collider; break; } } } } } // Apply the damage to the shield first because the shield can regenrate. if (m_ShieldAttribute != null && m_ShieldAttribute.Value > m_ShieldAttribute.MinValue) { var shieldAmount = Mathf.Min(amount, m_ShieldAttribute.Value - m_ShieldAttribute.MinValue); amount -= shieldAmount; m_ShieldAttribute.Value -= shieldAmount; } // Decrement the health by remaining amount after the shield has taken damage. if (m_HealthAttribute != null && m_HealthAttribute.Value > m_HealthAttribute.MinValue) { m_HealthAttribute.Value -= Mathf.Min(amount, m_HealthAttribute.Value - m_HealthAttribute.MinValue); } var force = direction * forceMagnitude; if (forceMagnitude > 0) { // Apply a force to the object. if (m_ForceObject != null) { m_ForceObject.AddForce(force, frames); } else { // Apply a force to the rigidbody if the object isn't a character. if (m_Rigidbody != null && !m_Rigidbody.isKinematic) { if (radius == 0) { m_Rigidbody.AddForceAtPosition(force * MathUtility.RigidbodyForceMultiplier, position); } else { m_Rigidbody.AddExplosionForce(force.magnitude * MathUtility.RigidbodyForceMultiplier, position, radius); } } } } // Let other interested objects know that the object took damage. EventHandler.ExecuteEvent <float, Vector3, Vector3, GameObject, Collider>(m_GameObject, "OnHealthDamage", amount, position, force, attacker, hitCollider); if (m_OnDamageEvent != null) { m_OnDamageEvent.Invoke(amount, position, force, attacker); } // The object is dead when there is no more health or shield. if (!IsAlive()) { Die(position, force, attacker); } else { // Play any take damage audio if the object did not die. If the object died then the death audio will play. m_TakeDamageAudioClipSet.PlayAudioClip(m_GameObject); } }
//todo anti roll when car is out of control void AntiRollBars() { //Horizontal anti roll float travelFL = 1f; float travelFR = 1f; //if front left wheel is grounded bool groundedFL = wheels[0].wheelCollider.GetGroundHit(out WheelHit wheelHit); if (groundedFL) travelFL = (-wheels[0].wheelTransform.InverseTransformPoint(wheelHit.point).y - wheels[0].wheelCollider.radius) / wheels[0].wheelCollider.suspensionDistance; //if front right wheel is grounded bool groundedFR = wheels[1].wheelCollider.GetGroundHit(out wheelHit); if (groundedFR) travelFR = (-wheels[1].wheelTransform.InverseTransformPoint(wheelHit.point).y - wheels[1].wheelCollider.radius) / wheels[1].wheelCollider.suspensionDistance; float antiRollFrontHorizontal = (travelFL - travelFR) * this.antiRollFrontHorizontal; //anti roll force if (groundedFL) rigidBody.AddForceAtPosition(wheels[0].wheelTransform.up * -antiRollFrontHorizontal, wheels[0].wheelTransform.position); if (groundedFR) rigidBody.AddForceAtPosition(wheels[1].wheelTransform.up * antiRollFrontHorizontal, wheels[1].wheelTransform.position); float travelRL = 1f; float travelRR = 1f; //if rear left wheel is grounded bool groundedRL = wheels[2].wheelCollider.GetGroundHit(out wheelHit); if (groundedRL) travelRL = (-wheels[2].wheelTransform.InverseTransformPoint(wheelHit.point).y - wheels[2].wheelCollider.radius) / wheels[2].wheelCollider.suspensionDistance; //if rear right wheel is grounded bool groundedRR = wheels[3].wheelCollider.GetGroundHit(out wheelHit); if (groundedRR) travelRR = (-wheels[3].wheelTransform.InverseTransformPoint(wheelHit.point).y - wheels[3].wheelCollider.radius) / wheels[3].wheelCollider.suspensionDistance; float antiRollRearHorizontal = (travelRL - travelRR) * this.antiRollRearHorizontal; //anti roll force if (groundedRL) rigidBody.AddForceAtPosition(wheels[2].wheelTransform.up * -antiRollRearHorizontal, wheels[2].wheelTransform.position); if (groundedRR) rigidBody.AddForceAtPosition(wheels[3].wheelTransform.up * antiRollRearHorizontal, wheels[3].wheelTransform.position); //Vertical anti roll float antiRollFrontVertical = (travelFL - travelRL) * antiRollVertical; if (groundedFL) rigidBody.AddForceAtPosition(wheels[0].wheelTransform.up * -antiRollFrontVertical, wheels[0].wheelTransform.position); if (groundedRL) rigidBody.AddForceAtPosition(wheels[2].wheelTransform.up * antiRollFrontVertical, wheels[2].wheelTransform.position); float antiRollRearVertical = (travelFR - travelRR) * antiRollVertical; if (groundedFR) rigidBody.AddForceAtPosition(wheels[1].wheelTransform.up * -antiRollRearVertical, wheels[1].wheelTransform.position); if (groundedRR) rigidBody.AddForceAtPosition(wheels[3].wheelTransform.up * antiRollRearVertical, wheels[3].wheelTransform.position); }
public void AddForceAtPosition(Vector3 force, Vector3 position) { mRigidBody.AddForceAtPosition(force, position); }
// Update is called once per frame void FixedUpdate() { //Input float throttleInput = Input.GetAxis("Throttle"); float brakeInput = Input.GetAxis("Brake"); float steeringInput = Input.GetAxis("Steering"); Vector3 velocity = body.velocity; Vector3 angVelocity = body.angularVelocity; //Gearing if (Input.GetKeyDown(KeyCode.E) && currentGear < gearRatios.Length - 1) { currentGear++; } if (Input.GetKeyDown(KeyCode.Q) && currentGear > 0) { currentGear--; } if (gearbox == Gearbox.Automatic) { if (RPM >= maxRPM && currentGear < gearRatios.Length - 1) { currentGear++; } if (RPM <= 1500 && currentGear > 0) { currentGear--; } } if (Input.GetKeyDown(KeyCode.R)) { transform.rotation = Quaternion.identity; } //Aero float CDrag = (0.5f * 0.3f * frontArea * 1.29f); float CRoll = 30 * CDrag; Vector3 FDrag = -CDrag * velocity * velocity.magnitude; Vector3 FRoll = -CRoll * velocity; //Braking float TBrake = brakePressure * brakeInput * -Mathf.Sign(speed); //Engine float avgAngularVelocity = 0; for (int i = 0; i < wheels.Length; i++) { avgAngularVelocity += wheels[i].angularVelocity; } avgAngularVelocity /= wheels.Length; RPM = (avgAngularVelocity * gearRatios[currentGear] * finalDriveRatio * 60) / (2 * Mathf.PI); if (RPM < 1000) { RPM = 1000; } if (RPM > maxRPM) { throttleInput = 0; } float TMax = torqueCurve.Evaluate(RPM); float TEngine = 2 * TMax * throttleInput; float TDrive = TEngine * gearRatios[currentGear] * finalDriveRatio * 0.7f; print(TDrive); //Apply for (int i = 0; i < wheels.Length; i++) { float FDrive = TDrive * wheels[i].radius; if (i < 2) { wheels[i].turnAngle = steeringInput * maxSteeringAngle; } else { body.AddForceAtPosition(transform.forward * FDrive, wheels[i].transform.position); } float wheelLongVelocity = Vector3.Dot(wheels[i].transform.forward, wheels[i].velocity / Time.fixedDeltaTime); float wheelLatVelocity = Vector3.Dot(wheels[i].transform.right, wheels[i].velocity / Time.fixedDeltaTime); //print(wheels[i].gameObject.name + " | " + wheels[i].GetComponent<Rigidbody>().velocity); //Debug.DrawLine(transform.position, (wheels[i].velocity * 10) + transform.position, Color.blue); //Debug.DrawLine(wheels[i].transform.position, wheels[i].transform.position + (wheels[i].transform.right * 10), Color.red); body.AddForceAtPosition(-wheelLatVelocity * wheels[i].transform.right * 1000, wheels[i].transform.position); body.AddForceAtPosition(TBrake * wheels[i].transform.forward, wheels[i].transform.position); wheels[i].angularVelocity = Mathf.Rad2Deg * Vector3.Dot(wheels[i].transform.forward, wheels[i].velocity) * Mathf.PI; } speed = transform.InverseTransformVector(velocity).z * 3.6f; }
void FixedUpdate() { if (OceanRenderer.Instance == null) { return; } UnityEngine.Profiling.Profiler.BeginSample("BoatAlignNormal.FixedUpdate"); _sampleHeightHelper.Init(transform.position, _boatWidth, true); var height = OceanRenderer.Instance.SeaLevel; _sampleHeightHelper.Sample(out Vector3 disp, out var normal, out var waterSurfaceVel); // height = base sea level + surface displacement y height += disp.y; { _sampleFlowHelper.Init(transform.position, _boatWidth); _sampleFlowHelper.Sample(out var surfaceFlow); waterSurfaceVel += new Vector3(surfaceFlow.x, 0, surfaceFlow.y); } // I could filter the surface vel as the min of the last 2 frames. theres a hard case where a wavelength is turned on/off // which generates single frame vel spikes - because the surface legitimately moves very fast. if (_debugDraw) { Debug.DrawLine(transform.position + 5f * Vector3.up, transform.position + 5f * Vector3.up + waterSurfaceVel, new Color(1, 1, 1, 0.6f)); } var velocityRelativeToWater = _rb.velocity - waterSurfaceVel; float bottomDepth = height - transform.position.y - _bottomH; _inWater = bottomDepth > 0f; if (!_inWater) { UnityEngine.Profiling.Profiler.EndSample(); return; } var buoyancy = -Physics.gravity.normalized * _buoyancyCoeff * bottomDepth * bottomDepth * bottomDepth; _rb.AddForce(buoyancy, ForceMode.Acceleration); // Approximate hydrodynamics of sliding along water if (_accelerateDownhill > 0f) { _rb.AddForce(new Vector3(normal.x, 0f, normal.z) * -Physics.gravity.y * _accelerateDownhill, ForceMode.Acceleration); } // apply drag relative to water var forcePosition = _rb.position + _forceHeightOffset * Vector3.up; _rb.AddForceAtPosition(Vector3.up * Vector3.Dot(Vector3.up, -velocityRelativeToWater) * _dragInWaterUp, forcePosition, ForceMode.Acceleration); _rb.AddForceAtPosition(transform.right * Vector3.Dot(transform.right, -velocityRelativeToWater) * _dragInWaterRight, forcePosition, ForceMode.Acceleration); _rb.AddForceAtPosition(transform.forward * Vector3.Dot(transform.forward, -velocityRelativeToWater) * _dragInWaterForward, forcePosition, ForceMode.Acceleration); float forward = _throttleBias; float rawForward = Input.GetAxis("Vertical"); if (_playerControlled) { forward += rawForward; } _rb.AddForceAtPosition(transform.forward * _enginePower * forward, forcePosition, ForceMode.Acceleration); float reverseMultiplier = (rawForward < 0f ? -1f : 1f); float sideways = _steerBias; if (_playerControlled) { sideways += (Input.GetKey(KeyCode.A) ? reverseMultiplier * -1f : 0f) + (Input.GetKey(KeyCode.D) ? reverseMultiplier * 1f : 0f); } _rb.AddTorque(transform.up * _turnPower * sideways, ForceMode.Acceleration); FixedUpdateOrientation(normal); UnityEngine.Profiling.Profiler.EndSample(); }
void HandleRaycast() { RaycastHit hit; int mask = (1 << LayerMask.NameToLayer("Track")) | (1 << LayerMask.NameToLayer("Default")); Camera cam = GetComponentInChildren <Camera>(); foreach (Transform wheel in wheels) { onTrack = false; if (Physics.Raycast(wheel.position + transform.up * raycastStart, -transform.up, out hit, 50.0f, mask)) { onTrack = true; if (enableGravity) { float f = 10.0f; if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Track")) { f = 50.0f; } rb.AddForceAtPosition(hit.normal * f * (hoverDist - hit.distance + raycastStart) * 0.25f, wheel.position, ForceMode.Acceleration); } if (Input.GetButton("Brake" + id)) { rb.drag = handBrakePower; } else { rb.drag = drag; rb.AddForce(transform.forward * Input.GetAxis("HLook" + id) * thrustPower * gc.playerSpeedMultiplier, ForceMode.Acceleration); //rb.AddTorque(transform.up * Input.GetAxis("Horizontal"+id) * 1f, ForceMode.Acceleration); float h = Vector3.Angle(transform.forward, cam.transform.forward) * 0.05f * Mathf.Abs(Input.GetAxis("HLook" + id)); if (h > 2) { h = 2; } rb.AddTorque(Vector3.Cross(transform.forward, cam.transform.forward).normalized *h, ForceMode.Acceleration); } } } if (Input.GetButton("Sudoku" + id)) { if (cur_off_time < off_time) { cur_off_time += Time.deltaTime; } else { Die(); } } else { cur_off_time = 0; } }
public void Bang() { Vector3 position = (_useLocalPOI) ? _rigidbody.centerOfMass + _position : _position; _rigidbody.AddForceAtPosition(_force, position, _forceMode); }
public void FixedUpdate() { //ResetInputs(); //air drag (quadratic) rb.AddForce(-airDragCoeff * rb.velocity * rb.velocity.magnitude); //downforce (quadratic) rb.AddForce(-airDownForceCoeff * rb.velocity.sqrMagnitude * transform.up); //tire drag (Linear) rb.AddForceAtPosition(-tireDragCoeff * rb.velocity, transform.position); //calc current gear ratio float gearRatio = Mathf.Lerp(gearRatios[Mathf.FloorToInt(currentGear) - 1], gearRatios[Mathf.CeilToInt(currentGear) - 1], currentGear - Mathf.Floor(currentGear)); if (InReverse) { gearRatio = -1.0f * gearRatios[0]; } //calc engine RPM from wheel rpm float wheelsRPM = (axles[1].right.rpm + axles[1].left.rpm) / 2f; if (wheelsRPM < 0) { wheelsRPM = 0; } // if the engine is on, the fuel injectors are going to be triggered at minRPM // to keep the engine running. If the engine is OFF, then the engine will eventually // go all the way down to 0, because there's nothing keeping it spinning. var minPossibleRPM = ignitionStatus == IgnitionStatus.On ? minRPM : 0.0f; currentRPM = Mathf.Lerp(currentRPM, minPossibleRPM + (wheelsRPM * finalDriveRatio * gearRatio), Time.fixedDeltaTime * RPMSmoothness); // I don't know why, but logging RPM while engine is off and we're not moving, is showing // a constant drift between 0.0185 and 0.0192 or so .. so just clamp it down to 0 at that // point. if (currentRPM < 0.02f) { currentRPM = 0.0f; } //find out which wheels are on the ground foreach (var axle in axles) { axle.isGroundedLeft = axle.left.GetGroundHit(out axle.hitLeft); axle.isGroundedRight = axle.right.GetGroundHit(out axle.hitRight); } //convert inputs to torques float steer = maxSteeringAngle * steerInput; currentTorque = rpmCurve.Evaluate(currentRPM / maxRPM) * gearRatio * finalDriveRatio * tractionControlAdjustedMaxTorque; foreach (var axle in axles) { if (axle.steering) { axle.left.steerAngle = steer; axle.right.steerAngle = steer; } } if (handbrakeApplied) { //Make the accellInput negative so that brakes are applied in ApplyTorque() accellInput = -1.0f; } // No autodrive while engine is off. if (ignitionStatus == IgnitionStatus.On) { AutoSteer(); } ApplyTorque(); TractionControl(); //shift if need be. No auto shifting while engine is off. if (ignitionStatus == IgnitionStatus.On) { AutoGearBox(); } //record current speed in MPH currentSpeed = rb.velocity.magnitude * 2.23693629f; float deltaDistance = wheelsRPM / 60.0f * (axles[1].left.radius * 2.0f * Mathf.PI) * Time.fixedDeltaTime; odometer += deltaDistance; /* * // why does this not work :( * float currentRPS = currentRPM / 60.0f; * * float accel = Mathf.Max(0.0f, accellInput); * float angularV = currentRPS * Mathf.PI * 2.0f; * * float power = currentTorque //(rpmCurve.Evaluate(currentRPM / maxRPM) * accel * maxMotorTorque) //Nm * angularV; // Watt * * float energy = power * Time.fixedDeltaTime // w/s * / 1000.0f * 3600.0f; // kw/h * * print("p:" + power + " e:" + energy); * //approximation function for * // https://en.wikipedia.org/wiki/Brake_specific_fuel_consumption#/media/File:Brake_specific_fuel_consumption.svg * // range ~ 200-400 g/kWh * float bsfc = (206.0f + Mathf.Sqrt(Mathf.Pow(currentRPM - 2200, 2.0f) + Mathf.Pow((accel - 0.9f) * 10000.0f, 2.0f)) / 80 + currentRPM / 4500); // g/kWh + + float gasolineDensity = 1f / .75f; // cm^3/g + + float deltaConsumption = bsfc * energy // g * gasolineDensity // cm^3 * / 1000.0f; // l */ // FIXME fix the more correct method above... float deltaConsumption = currentRPM * 0.00000001f + currentTorque * 0.000000001f * Mathf.Max(0.0f, accellInput); // if engine is not powered up, or there's zero acceleration, AND we're not idling // the engine to keep it on, then the fuel injectors are off, and no fuel is being used // idling == non-scientific calculation of "minRPM + 25%". if (ignitionStatus != IgnitionStatus.On || (accellInput <= 0.0f && currentRPM > minRPM + (minRPM * 0.25))) { deltaConsumption = 0.0f; } consumptionDistance = deltaConsumption / deltaDistance; // l/m consumptionTime = deltaConsumption / Time.fixedDeltaTime; // l/s fuelLevel -= deltaConsumption; float engineWeight = 200.0f; // kg float energyDensity = 34.2f * 1000.0f * 1000.0f; // J/l fuel float specificHeatIron = 448.0f; // J/kg for 1K temperature increase engineTemperatureK += (deltaConsumption * energyDensity) / (specificHeatIron * engineWeight); float coolFactor = 0.00002f; //ambient exchange if (engineTemperatureK > zeroK + 90.0f && !coolingMalfunction) { coolFactor += 0.00002f + 0.0001f * Mathf.Max(0.0f, currentSpeed); // working temperature reached, start cooling } engineTemperatureK = Mathf.Lerp(engineTemperatureK, ambientTemperatureK, coolFactor); //find current road surface type WheelHit hit; if (axles[0].left.GetGroundHit(out hit)) { traction = hit.forwardSlip; var roadObject = hit.collider.transform.parent == null ? hit.collider.transform : hit.collider.transform.parent; CurrentSurface = roadType == "roads" || roadObject.CompareTag("Road") ? RoadSurface.Tarmac : RoadSurface.Offroad; } else { traction = 0f; CurrentSurface = RoadSurface.Airborne; } //find traction values for audio tractionR = axles[0].right.GetGroundHit(out hit) ? hit.forwardSlip : 0f; rtractionR = axles[1].right.GetGroundHit(out hit) ? hit.forwardSlip : 0f; rtraction = axles[1].left.GetGroundHit(out hit) ? hit.forwardSlip : 0f; // apply turn signal logic const float turnSignalTriggerThreshold = 0.2f; const float turnSignalOffThreshold = 0.1f; if (leftTurnSignal) { if (resetTurnSignal) { if (steerInput > -turnSignalOffThreshold) { leftTurnSignal = false; } } else { if (steerInput < -turnSignalTriggerThreshold) { // "click" resetTurnSignal = true; } } } if (rightTurnSignal) { if (resetTurnSignal) { if (steerInput < turnSignalOffThreshold) { rightTurnSignal = false; } } else { if (steerInput > turnSignalTriggerThreshold) { // "click" resetTurnSignal = true; } } } }
void SuspensionForceAtWheel(Axle axle, WheelData wheelData) { Vector3 compressedWheelPos = WheelPosition(axle, wheelData, false); RaycastHit hit; int layerMask = canDriveOnEntities ? ~LayerMask.GetMask("Water") : LayerMask.GetMask("Terrain"); bool hitSomething = Physics.Raycast(compressedWheelPos, -transform.up, out hit, axle.suspensionHeight, layerMask, QueryTriggerInteraction.Ignore); Debug.DrawLine(compressedWheelPos, compressedWheelPos - (transform.up * axle.suspensionHeight), Color.green); wheelData.isGrounded = hitSomething; if (hitSomething) { // calculate suspension force float suspensionLength = hit.distance; float suspensionForceMag = 0.0f; wheelData.compression = 1.0f - Mathf.Clamp01(suspensionLength / axle.suspensionHeight); // Hooke's Law (springs) float springForce = wheelData.compression * -axle.suspensionStiffness; suspensionForceMag += springForce; // Damping force (try to rest velocity to 0) float suspensionCompressionVelocity = (wheelData.compression - wheelData.compressionPrev) / Time.deltaTime; wheelData.compressionPrev = wheelData.compression; float damperFoce = -suspensionCompressionVelocity * axle.suspensionDampining; suspensionForceMag += damperFoce; // Only consider component of force that is along contact normal float denom = Vector3.Dot(hit.normal, transform.up); suspensionForceMag *= denom; // Apply suspension force Vector3 suspensionForce = suspensionForceMag * -transform.up; rb.AddForceAtPosition(suspensionForce, hit.point); // calculate friction Vector3 wheelVelocity = rb.GetPointVelocity(hit.point); Vector3 contactUp = hit.normal; Vector3 contactLeft = -transform.right; Vector3 contactForward = transform.forward; // Calculate sliding velocity (without normal force) Vector3 lVel = Vector3.Dot(wheelVelocity, contactLeft) * contactLeft; Vector3 fVel = Vector3.Dot(wheelVelocity, contactForward) * contactForward; Vector3 slideVelocity = (lVel + fVel) * 0.5f; // Calculate current sliding force // (4 because we have 4 wheels) // TODO use num wheel variable Vector3 slidingForce = (slideVelocity * rb.mass / Time.deltaTime) / 4; float laterialFriciton = Mathf.Clamp01(axle.laterialFriction); Vector3 frictionForce = -slidingForce * laterialFriciton; Vector3 longitudinalForce = Vector3.Dot(frictionForce, contactForward) * contactForward; // TODO // Apply rolling-friction only if player doesn't press the accelerator float rollingK = 1.0f - Mathf.Clamp01(axle.rollingFriction); longitudinalForce *= rollingK; frictionForce -= longitudinalForce; rb.AddForceAtPosition(frictionForce, FixToCarCentre(hit.point)); } else { // relax suspension wheelData.compressionPrev = wheelData.compression; wheelData.compression = Mathf.Clamp01(wheelData.compression - axle.suspensionRelaxSpeed * Time.deltaTime); } }
private IEnumerator AddGuideForce() { //if (blockRadar.target.transform != preTargetTransform) //{ previousPosition = Vector3.zero; //preTargetTransform = blockRadar.target.transform; integral = 0; lastError = 0; //} Vector3 addedForce; // Calculating the rotating axis Vector3 positionDiff = blockRadar.target.Position - parentBlock.transform.position; //Vector3 targetVelocity = blockRadar.target.rigidbody == null ? // (blockRadar.target.Position - previousPosition) / Time.fixedDeltaTime : blockRadar.target.Velocity; Vector3 targetVelocity = blockRadar.target.Velocity; previousPosition = blockRadar.target.Position; Vector3 relVelocity = targetVelocity - parentBlock.Rigidbody.velocity; //float speed; bool turretMode; if (blockRadar.RadarType == RadarScript.RadarTypes.ActiveRadar) { turretMode = blockRadar.ShowBulletLanding; //speed = turretMode ? blockRadar.cannonBallSpeed : parentRigidbody.velocity.magnitude; } else { turretMode = blockRadar.passiveSourceRadar == null ? false : blockRadar.passiveSourceRadar.ShowBulletLanding && sourceSpeedPower < 0.1f; //speed = turretMode ? blockRadar.passiveSourceRadar.cannonBallSpeed : parentRigidbody.velocity.magnitude; } // Get the predicted point float time; Vector3 positionDiffPredicted; if (turretMode) { Vector3 aimDir; if (blockRadar.RadarType == RadarScript.RadarTypes.ActiveRadar) { aimDir = blockRadar.aimDir; } else { aimDir = blockRadar.passiveSourceRadar == null ? Vector3.zero : blockRadar.passiveSourceRadar.aimDir; } positionDiffPredicted = parentBlock.transform.position + aimDir * parentBlock.transform.position.magnitude * 10000; } else { time = InterceptionCalculation.FirstOrderInterceptTime(parentRigidbody.velocity.magnitude, positionDiff, relVelocity); positionDiffPredicted = positionDiff + relVelocity * time; } positionDiffPredicted = positionDiffPredicted.normalized; // Get the angle difference float dotProduct = Vector3.Dot(ForwardDirection, positionDiffPredicted); Vector3 towardsPositionDiff = (dotProduct * positionDiffPredicted - ForwardDirection) * Mathf.Sign(dotProduct); towardsPositionDiff = towardsPositionDiff.normalized; if (constantForce) { addedForce = torque * maxTorque * towardsPositionDiff * 2000f; } else { float angleDiff = Vector3.Angle(ForwardDirection, positionDiff) + Vector3.Angle(positionDiff, positionDiffPredicted); integral += angleDiff * Time.fixedDeltaTime; float derivitive = (angleDiff - lastError) / Time.fixedDeltaTime; lastError = angleDiff; float coefficient = angleDiff * pFactor + integral * iFactor + derivitive * dFactor; addedForce = torque * maxTorque * coefficient * towardsPositionDiff; } // Add force to rotate rocket parentRigidbody.AddForceAtPosition(addedForce, parentBlock.transform.position + ForwardDirection); parentRigidbody.AddForceAtPosition(-addedForce, parentBlock.transform.position - ForwardDirection); yield break; }
IEnumerator StartAction() { Debug.Log("Starting recording... waiting on Delay."); yield return(new WaitForSeconds(startSecondDelay)); Debug.Log("Delay is over. Applying force."); switch (type) { case ForceType.Explosion: if (isOffSetRelative) { rb.AddExplosionForce(strength, transform.position + offSet, radius); } else { rb.AddExplosionForce(strength, offSet, radius); } break; case ForceType.Force: rb.AddForce(offSet * strength); //Maybe use a different Vector3 //Add more options break; case ForceType.ForceAtPosition: if (isOffSetRelative) { rb.AddForceAtPosition(direction * strength, transform.position + offSet); } else { rb.AddForceAtPosition(direction * strength, offSet); } break; } Debug.Log("Setting up vars for recording..."); isRecording = true; //Set the status to being recorded currentTime = 0; //Start at frame 0 recordTimeFrames = (int)recordTime * 60; //Convert to frames clip.ClearCurves(); //Clear whatever was in this animtion before clip.legacy = false; //Set it to legacy so this method will work //Create enough keyframes for ourselves xPosKeys = new Keyframe[recordTimeFrames / recordingResolution]; yPosKeys = new Keyframe[recordTimeFrames / recordingResolution]; zPosKeys = new Keyframe[recordTimeFrames / recordingResolution]; xRotKeys = new Keyframe[recordTimeFrames / recordingResolution]; yRotKeys = new Keyframe[recordTimeFrames / recordingResolution]; zRotKeys = new Keyframe[recordTimeFrames / recordingResolution]; wRotKeys = new Keyframe[recordTimeFrames / recordingResolution]; KeyPosRot(); Debug.Log("Setup done. Initial keys set. Recording beginning..."); }
void AddForceAtPosition(Vector3 force, Vector3 position) { rb.AddForceAtPosition(force, position); // Debug.DrawRay(position, force, Color.magenta); }
void RepelPlayer(Rigidbody player) { Vector3 repelVector = -(transform.position - player.transform.position).normalized * m_repelForce; player.AddForceAtPosition(repelVector, player.transform.position); }
private void ApplyNeutralBuoyancy() { _buoyancyVector = -_relativeDownVector *_gravity *Random.Range(.99f, 1.01f) * thrustAmpFactor; _rigidbody.AddForceAtPosition(_buoyancyVector, _transform.TransformPoint(relativePosition), ForceMode.Acceleration); }
private void FixedUpdateRotatorTrack() { var rotateForce = trackPoint.position - originalControllerAttachPoint.position; rb.AddForceAtPosition(rotateForce, originalControllerAttachPoint.position, ForceMode.VelocityChange); }
public void FallDownByButtonPush() { Vector3 Extents = gameObject.GetComponent <Collider>().bounds.extents; rb.AddForceAtPosition(100 * transform.forward.normalized, transform.position + 0.8f * Extents); }
public void EnableRagdoll(Rigidbody body, Vector3 point, Vector3 impulse) { EnableRagdoll(); body?.AddForceAtPosition(impulse, point, ForceMode.Impulse); }
/* * * // DEBUG * * private var m_lastVelocity = Vector3.zero; * private var m_velocity = Vector3.zero; * private var m_acceleration = Vector3.zero; * private var m_loadMass = 0.0; * private var m_force = Vector3.zero; * * static function Lin2Log(value : float) : float * { * return Mathf.Log(Mathf.Abs(value)+1) * Mathf.Sign(value); * } * * static function Lin2Log(value : Vector3) : Vector3 * { * return Vector3.ClampMagnitude(value, Lin2Log(value.magnitude)); * } * * * function Update () * { * var hit : RaycastHit; * * if (Physics.Raycast(m_wheel.transform.position, -m_wheel.transform.up, hit, (m_wheel.suspensionDistance + m_wheel.radius) * m_wheel.transform.lossyScale.y)) * { * Debug.DrawLine(hit.point, hit.point + m_velocity * 1, Color.gray); * Debug.DrawLine(hit.point, hit.point + m_acceleration * 1, Color.yellow); * Debug.DrawLine(hit.point, hit.point + Lin2Log(m_force) * 0.1, Color.magenta); * } * } */ void FixedUpdate() { /* * // DATOS Debug * * m_grounded = m_wheel.GetGroundHit(m_wheelHit); * if (m_grounded) * { * m_velocity = m_rigidbody.GetPointVelocity(m_wheelHit.point); * m_acceleration = (m_velocity - m_lastVelocity) / Time.deltaTime; * m_lastVelocity = m_velocity; * m_loadMass = m_wheelHit.force / -Physics.gravity.y; * m_force = m_acceleration * m_loadMass; * } * else * { * m_velocity = Vector3.zero; * m_lastVelocity = Vector3.zero; * m_acceleration = Vector3.zero; * m_loadMass = 0.0; * m_force = Vector3.zero; * } * * //----------- */ // Calcular el ajuste temporal m_DeltaTimeFactor = Time.fixedDeltaTime * Time.fixedDeltaTime * 2500.0f; // equivale a (fixedDeltaTime/0.02)^2 // Determinar el estado de la rueda m_grounded = m_wheel.GetGroundHit(out m_wheelHit); // Calcular los elementos costosos (picos de las curvas de fricción) if (!optimized) { RecalculateStuff(); } //====================================================================== // 1. Fricción longitudinal //====================================================================== // Calcular el rendimiento neto aceleración-freno aplicado sobre la rueda. Determinará el factor de amplificación (slopeFactor) a aplicar. float resultInput = Mathf.Abs(motorInput) - brakeInput; // Calcular parámetros de ajuste de la curva: // - fslipFactor escalará la curva de forma que el punto de máximo rendimiento coincida (mas o menos) con el valor dado. // - fSlopeFactor es el stiffnes que multiplicará a grip y a drift. // Si es != 1.0 se desplaza ligeramente el punto de máximo rendimiento, pero no se nota mucho. float fSlipFactor = serviceMode ? 1.0f : performancePeak / m_forwardFrictionPeak.y; float fSlopeFactor = resultInput >= 0 ? motorForceFactor : brakeForceFactor; // Calcular la curva correcta para el WheelCollider m_wheel.forwardFriction = GetWheelFrictionCurve(ForwardWheelFriction, fSlopeFactor, fSlipFactor); m_wheel.motorTorque = SlipToTorque(motorInput); m_wheel.brakeTorque = SlipToTorque(brakeInput); //====================================================================== // 2. Fricción lateral //====================================================================== // Calcular la pérdida de agarre lateral en función del rendimiento longitudinal de la rueda // Si la rueda está en el suelo se usa el slip longitundinal real, si no se usa el de la entrada. m_driftFactor = Mathf.Lerp(1.0f, sidewaysDriftFriction, Mathf.InverseLerp(m_wheel.forwardFriction.extremumSlip * m_forwardFrictionPeak.x, m_wheel.forwardFriction.asymptoteSlip, Mathf.Abs(m_grounded ? m_wheelHit.forwardSlip : resultInput))); // Calcular y aplicar la curva de fricción lateral en el WheelCollider fSlopeFactor = serviceMode ? 1.0f : m_driftFactor * sidewaysForceFactor; m_wheel.sidewaysFriction = GetWheelFrictionCurve(SidewaysWheelFriction, fSlopeFactor, 1.0f); //====================================================================== // 3. Datos, ajustes & correcciones //====================================================================== if (m_grounded) { // Datos para telemetría WheelFrictionCurve sF = m_wheel.sidewaysFriction; WheelFrictionCurve fF = m_wheel.forwardFriction; m_forwardSlipRatio = GetWheelSlipRatio(m_wheelHit.forwardSlip, fF.extremumSlip * m_forwardFrictionPeak.x, fF.asymptoteSlip); m_sidewaysSlipRatio = GetWheelSlipRatio(m_wheelHit.sidewaysSlip, sF.extremumSlip * m_sidewaysFrictionPeak.x, sF.asymptoteSlip); // Corregir el diseño de las curvas de fricción de WheelFrictionCurve // - Fricción lateral float absSlip = Mathf.Abs(m_wheelHit.sidewaysSlip); if (staticFrictionMax > sF.extremumValue && absSlip < sF.extremumSlip) // Baja velocidad - reforzar ligeramente el control estático del WheelCollider { sF.extremumValue = GetFixedSlope(CarWheelFriction.MCsideways, absSlip, sF.extremumSlip, sF.extremumValue, 0); if (sF.extremumValue > staticFrictionMax) { sF.extremumValue = staticFrictionMax; } } if (absSlip > sF.asymptoteSlip) { sF.asymptoteValue = GetFixedSlope(CarWheelFriction.MCsideways, absSlip, sF.asymptoteSlip, sF.asymptoteValue, SidewaysWheelFriction.driftSlope); } // - Fricción longitudinal absSlip = Mathf.Abs(m_wheelHit.forwardSlip); if (absSlip > fF.asymptoteSlip) { fF.asymptoteValue = GetFixedSlope(CarWheelFriction.MCforward, absSlip, fF.asymptoteSlip, fF.asymptoteValue, ForwardWheelFriction.driftSlope); } // Ajustar la curva en función del terreno if (m_wheelHit.collider.sharedMaterial) { fF.stiffness *= (m_wheelHit.collider.sharedMaterial.dynamicFriction + 1.0f) * 0.5f; sF.stiffness *= (m_wheelHit.collider.sharedMaterial.dynamicFriction + 1.0f) * 0.5f; // Aplicar fuerza de resistencia fuera de la carretera Vector3 wheelV = m_rigidbody.GetPointVelocity(m_wheelHit.point); m_rigidbody.AddForceAtPosition(wheelV * wheelV.magnitude * -m_wheelHit.force * m_wheelHit.collider.sharedMaterial.dynamicFriction * 0.001f, m_wheelHit.point); } m_wheel.sidewaysFriction = sF; m_wheel.forwardFriction = fF; } else { m_forwardSlipRatio = 0; m_sidewaysSlipRatio = 0; } }