IEnumerator LerpGray() { float startTime = Time.time; float prevMaxRamp = maxRampOffset; float prevLerpFreq = lerpFrequency; float offset = 0; while (true) { if (!prevMaxRamp.Approx(maxRampOffset)) { prevMaxRamp = maxRampOffset; } if (!prevLerpFreq.Approx(lerpFrequency)) { prevLerpFreq = lerpFrequency; float currLerpParam = Mathf.InverseLerp(0, maxRampOffset, gray.rampOffset); float sinVal = Mathf.Sin(Time.time - startTime); float upOrDown = Mathf.Sign(sinVal); startTime = Time.time - (Mathf.Asin(currLerpParam * 2f - 1f) / lerpFrequency); //startTime = startTime + 2 * (Mathf.PI / 2 - startTime); // if opposite direction, (pi / 2) - startTime } gray.rampOffset = Mathf.Lerp(0, maxRampOffset, (Mathf.Sin((Time.time - startTime) * lerpFrequency) + 1f) / 2f); yield return(null); } }
public bool Iteration() { var dict = new SortedDictionary <float, float>(); theta0 = GetIterValue(); dict.Add(Dist(), GetIterValue()); // 计算当前距离并存放到字典里,以距离作为Key排序 SetIterValue(theta0 + alpha); // 计算向前步进后的距离,放进字典 var dist = Dist(); if (!dict.ContainsKey(dist)) { dict.Add(dist, GetIterValue()); //(字典里的值是被DOF限制后的) } SetIterValue(theta0 - alpha); // 反向 dist = Dist(); if (!dict.ContainsKey(dist)) { dict.Add(dist, GetIterValue()); } foreach (var i in dict) { SetIterValue(i.Value); astIK.Rotate(); break; } theta1 = GetIterValue(); return(theta0.Approx(theta1)); // 是否已经接近最佳值 }
internal static float ValueFromSides(this float negativeSide, float positiveSide) { float v1 = negativeSide.Abs(); float v2 = positiveSide.Abs(); if (v1.Approx(v2)) { return(0.0f); } return((double)v1 > (double)v2 ? -v1 : v2); }
private void ModeSiphon() { float moles = metaNode.GasMix.Moles * (IsExpandedRange ? 0.40f : 0.05f) * Effectiveness; // siphon a portion moles = moles.Clamp(0, nominalMolesTransferCap); if (moles.Approx(0)) { return; } GasMix.TransferGas(pipeMix, metaNode.GasMix, moles); }
public void SetIntegrityLevel(float newLevel) { Mathf.Clamp(newLevel, 0, 100); //0 check if (newLevel.Approx(0)) { integritySlider.value = 0; return; } // 0 to 1 integritySlider.value = newLevel / 100; }
public void SetPowerLevel(float newLevel) { Mathf.Clamp(newLevel, 0, 100); //0 check if (newLevel.Approx(0)) { powerSlider.value = 0; return; } // 0 to 1 powerSlider.value = newLevel / 100; }
private static void InternalSetMoles(GasData data, GasSO gasType, float moles, bool isChange) { lock (data.GasesArray) //Because it gets the gas and it could be added in between this { //Try to get gas value if already inside mix GetGasType(data, gasType, out var gas); if (gas != null) { if (isChange) { gas.Moles += moles; } else { gas.Moles = moles; } //Remove gas from mix if less than threshold if (gas.Moles <= AtmosConstants.MinPressureDifference) { data.RemoveGasType(gasType); } return; } //Gas isn't inside mix so we'll add it //Dont add new data for negative moles if (Math.Sign(moles) == -1) { return; } //Dont add if approx 0 or below threshold if (moles.Approx(0) || moles <= AtmosConstants.MinPressureDifference) { return; } var newValues = GetGasValues(); newValues.Moles = moles; newValues.GasSO = gasType; data.GasesArray.Add(newValues); data.GasesDict.Add(gasType, newValues); } }
private void ModeScrub() { // Scrub out a portion of each specified gas. // If all these gases exceed transfer amount, reduce each gas scrub mole count proportionally. float scrubbableMolesAvailable = 0; lock (metaNode.GasMix.GasesArray) //no Double lock { foreach (GasValues gas in metaNode.GasMix.GasesArray) //doesn't appear to modify list while iterating { if (FilteredGases.Contains(gas.GasSO)) { scrubbingGasMoles[gas.GasSO] = gas.Moles * (IsExpandedRange ? 0.05f : 0.20f) * Effectiveness; scrubbableMolesAvailable += scrubbingGasMoles[gas.GasSO]; } } } if (scrubbableMolesAvailable.Approx(0)) { return; // No viable gases found } float molesToTransfer = scrubbableMolesAvailable.Clamp(0, nominalMolesTransferCap * Effectiveness); float ratio = molesToTransfer / scrubbableMolesAvailable; ratio = ratio.Clamp(0, 1); // actual scrubbing for (int i = 0; i < Gas.Gases.Count; i++) { GasSO gas = Gas.Gases[i]; float transferAmount = scrubbingGasMoles[i] * ratio; if (transferAmount.Approx(0)) { continue; } metaNode.GasMix.RemoveGas(gas, transferAmount); if (selfSufficient == false) { pipeMix.AddGas(gas, transferAmount); } } Array.Clear(scrubbingGasMoles, 0, scrubbingGasMoles.Length); }
public bool Approx(Float2 other, float maxDifference = .0001f) => X.Approx(other.X, maxDifference) && Y.Approx(other.Y, maxDifference);
/// <summary> /// Pulls in the desired gas, as well as others, from the specified gas mix and adds them to the blood stream /// </summary> /// <param name="gasMix">The gas mix to breathe in from</param> /// <param name="blood">The blood to put gases into</param> /// <returns> True if breathGasMix was changed </returns> private bool BreatheIn(GasMix breathGasMix, ReagentMix blood, float efficiency) { if (RelatedPart.HealthMaster.RespiratorySystem.CanBreathAnywhere) { blood.Add(RelatedPart.requiredReagent, RelatedPart.bloodType.GetSpareGasCapacity(blood)); return(false); } ReagentMix toInhale = new ReagentMix(); var Available = RelatedPart.bloodType.GetGasCapacityOfnonMeanCarrier(blood); var TotalMoles = breathGasMix.Moles; foreach (var gasValues in breathGasMix.GasData.GasesArray) { var gas = gasValues.GasSO; if (GAS2ReagentSingleton.Instance.DictionaryGasToReagent.ContainsKey(gas) == false) { continue; } // n = PV/RT float gasMoles = breathGasMix.GetPressure(gas) * LungSize / (8.314f * breathGasMix.Temperature); // Get as much as we need, or as much as in the lungs, whichever is lower Reagent gasReagent = GAS2ReagentSingleton.Instance.GetGasToReagent(gas); float molesRecieved = 0; if (gasReagent == RelatedPart.bloodType.CirculatedReagent) { molesRecieved = Mathf.Min(gasMoles, RelatedPart.bloodType.GetSpareGasCapacity(blood, gasReagent)); } else { if (gasMoles == 0) { molesRecieved = 0; } else { molesRecieved = Available / (TotalMoles / gasMoles); molesRecieved = Mathf.Min(molesRecieved, gasMoles); } } if (molesRecieved.Approx(0) == false) { toInhale.Add(gasReagent, molesRecieved * efficiency); } //TODO: Add pressureSafeMax check here, for hyperoxia } RelatedPart.HealthMaster.RespiratorySystem.GasExchangeToBlood(breathGasMix, blood, toInhale); // Counterintuitively, in humans respiration is stimulated by pressence of CO2 in the blood, not lack of oxygen // May want to change this code to reflect that in the future so people don't hyperventilate when they are on nitrous oxide var inGas = GAS2ReagentSingleton.Instance.GetGasToReagent(requiredGas); float bloodCap = RelatedPart.bloodType.GetGasCapacity(RelatedPart.BloodContainer.CurrentReagentMix); float foreignCap = RelatedPart.bloodType.GetGasCapacityForeign(RelatedPart.BloodContainer.CurrentReagentMix); float bloodSaturation = 0; if (bloodCap + foreignCap == 0) { bloodSaturation = 0; } else { var ratioNativeBlood = bloodCap / (bloodCap + foreignCap); bloodSaturation = RelatedPart.BloodContainer[RelatedPart.requiredReagent] * ratioNativeBlood / bloodCap; } if (bloodSaturation >= RelatedPart.HealthMaster.CirculatorySystem.BloodInfo.BLOOD_REAGENT_SATURATION_OKAY) { currentBreatheCooldown = breatheCooldown; //Slow breathing, we're all good RelatedPart.HealthMaster.HealthStateController.SetSuffocating(false); } else if (bloodSaturation <= RelatedPart.HealthMaster.CirculatorySystem.BloodInfo.BLOOD_REAGENT_SATURATION_BAD) { RelatedPart.HealthMaster.HealthStateController.SetSuffocating(true); if (Random.value < 0.2) { Chat.AddActionMsgToChat(RelatedPart.HealthMaster.gameObject, "You gasp for breath", $"{RelatedPart.HealthMaster.PlayerScriptOwner.visibleName} gasps"); } } //Debug.Log("Gas inhaled: " + toInhale.Total + " Saturation: " + saturation); return(toInhale.Total > 0); }
private static void InternalSetMoles(GasData data, GasSO gasType, float moles, bool isChange) { //Try to get gas value if already inside mix GetGasType(data, gasType, out var gas); if (gas != null) { if (isChange) { gas.Moles += moles; } else { gas.Moles = moles; } //Remove gas from mix if less than threshold if (gas.Moles <= AtmosConstants.MinPressureDifference) { data.RemoveGasType(gasType); } return; } //Gas isn't inside mix so we'll add it //Dont add new data for negative moles if (Math.Sign(moles) == -1) { return; } //Dont add if approx 0 or below threshold if (moles.Approx(0) || moles <= AtmosConstants.MinPressureDifference) { return; } //Create new array and add old gas values and new gas var newValues = new GasValues { Moles = moles, GasSO = gasType }; var newArray = new GasValues[data.GasesArray.Length + 1]; for (int i = 0; i < newArray.Length; i++) { if (data.GasesArray.Length == i) { newArray[i] = newValues; //Should only happen on last index since we are adding only one thing so can break break; } newArray[i] = data.GasesArray[i]; } data.GasesArray = newArray; data.GasesDict.Add(gasType, newValues); }
IEnumerator PerformFollowPath(List <Node> path) { int node = 1; while (node < path.Count) { if (!activated) { yield return(WaitFor.EndOfFrame); yield break; } if (!movingToTile) { if (TickDelay.Approx(0) == false) { yield return(WaitFor.Seconds(TickDelay)); } var dir = path[node].position - Vector2Int.RoundToInt(transform.localPosition); if (!registerTile.Matrix.IsPassableAtOneMatrixOneTile(registerTile.LocalPositionServer + (Vector3Int)dir, true, context: gameObject)) { var dC = registerTile.Matrix.GetFirst <DoorController>( registerTile.LocalPositionServer + (Vector3Int)dir, true); if (dC != null) { dC.MobTryOpen(gameObject); yield return(WaitFor.Seconds(1f)); } else { ResetMovingValues(); FollowCompleted(); Logger.Log("Path following timed out. Something must be in the way", Category.Movement); yield break; } } if (directional != null) { directional.FaceDirection(Orientation.From(dir)); } cnt.Push(dir, context: gameObject); movingToTile = true; } else { if (arrivedAtTile) { movingToTile = false; arrivedAtTile = false; timeOut = 0f; node++; } else { //Mob has 5 seconds to get to the next tile //or the AI should do something else timeOut += Time.deltaTime; if (timeOut > 5f) { ResetMovingValues(); Logger.Log("Path following timed out. Something must be in the way", Category.Movement); FollowCompleted(); yield break; } } } yield return(WaitFor.EndOfFrame); } yield return(WaitFor.EndOfFrame); ResetMovingValues(); FollowCompleted(); }
public bool Approx(Float4 other, float maxDifference = .0001f) => X.Approx(other.X, maxDifference) && Y.Approx(other.Y, maxDifference) && Z.Approx(other.Z, maxDifference) && W.Approx(other.W, maxDifference);