void Awake() { GetTriggerCollider(); _body = GetComponentInParent<CelestialBody>(); if ( !_detector || !_body ) { enabled = false; } TriggerRadius = Mathf.Abs( TriggerRadius ); }
public FakeBody(SpaceGravity2D.CelestialBody body) { position = body.transform.position; LastPosition = body.LastPosition; Velocity = body.Velocity; _additionVelocity = body._additionalVelocity; personalTimeScale = body.personalTimeScale; }
void OnEnable() { if (_lineRenderer == null) { CreateLineRend(); } if (_body == null) { _body = GetComponentInParent<CelestialBody>(); if (_body == null) { Debug.LogWarning("SpaceGravity2D: Orbit Display can't find celestial body on " + name); enabled = false; } } }
/// <summary> /// Post frame assignation coroutine is used for preventing cases, when random attractor is assigned from set of attractors /// </summary> IEnumerator SetNearestAttractor(bool checkIsInRange) { yield return new WaitForEndOfFrame(); if (_newAttractorsBuffer == null || _newAttractorsBuffer.Count == 0) { yield break; } if (_newAttractorsBuffer.Count == 1) { if (checkIsInRange) { if (_newAttractorsBuffer[0] == null || ( _newAttractorsBuffer[0]._transform.position - _transform.position ).magnitude < Mathf.Min(_newAttractorsBuffer[0].MaxAttractionRange, _simulationControl.MaxAttractionRange)) { Attractor = _newAttractorsBuffer[0]; CalculateNewOrbitData(); } } else { Attractor = _newAttractorsBuffer[0]; CalculateNewOrbitData(); } _newAttractorsBuffer.Clear(); yield break; } CelestialBody nearest = _newAttractorsBuffer[0]; float sqrDistance = nearest != null ? ( nearest._transform.position - _transform.position ).sqrMagnitude : float.MaxValue; for (int i = 1; i < _newAttractorsBuffer.Count; i++) { if (_newAttractorsBuffer[i] == nearest) { continue; } if (_newAttractorsBuffer[i] != null && ( _newAttractorsBuffer[i].transform.position - _transform.position ).sqrMagnitude < sqrDistance) { nearest = _newAttractorsBuffer[i]; sqrDistance = ( _newAttractorsBuffer[i].transform.position - _transform.position ).sqrMagnitude; } } _newAttractorsBuffer.Clear(); Attractor = nearest; CalculateNewOrbitData(); }
/// <summary> /// Assign new attractor for body at the end of current frame. If called multiple times in single frame, nearest attractor will be chosen /// </summary> /// <param name="attr">new attractor reference or null</param> /// <param name="checkIsInRange"></param> /// <param name="instant">if false, attractor will be assigned at End Of Frame</param> public void SetAttractor(CelestialBody attr, bool checkIsInRange = false, bool instant = false) { if (attr == null || attr != Attractor && attr != this) { if (!Application.isPlaying || instant) { TerminateRailMotion(); Attractor = attr; CalculateNewOrbitData(); return; } if (_newAttractorsBuffer == null || _newAttractorsBuffer.Count == 0) { _newAttractorsBuffer = new List<CelestialBody>(); StartCoroutine(SetNearestAttractor(checkIsInRange)); TerminateRailMotion(); } _newAttractorsBuffer.Add(attr); } }
void UnregisterBody(CelestialBody body) { _bodies.Remove(body); }
void RegisterBody(CelestialBody body) { _bodies.Add(body); }
/// <summary> /// Return ratio of perturbation force from third body relative to attraction force of mainAttractor /// </summary> /// <param name="targetBody"></param> /// <param name="mainAttractor"></param> /// <param name="perturbatingAttractor"></param> public static float RelativePerturbationRatio(CelestialBody targetBody, CelestialBody mainAttractor, CelestialBody perturbatingAttractor) { float mainAcceleration = AccelerationByAttractionForce(targetBody._transform.position, mainAttractor._transform.position, mainAttractor.MG).magnitude; float perturbAcceleration = AccelerationByAttractionForce(targetBody._transform.position, perturbatingAttractor._transform.position, perturbatingAttractor.MG).magnitude; return perturbAcceleration / mainAcceleration; }
/// <summary> /// One more convenient way to set attractor; /// </summary> /// <param name="body"></param> public void SetBiggestAttractorForBody(CelestialBody body) { GetCentralAttractor(); if (_centralAttractor != null) { body.SetAttractor(_centralAttractor, false, true); } }
/// <summary> /// Find attractor which has biggest gravitational influence on body comparing to others. If fail, null will be assigned. /// It can be used in realtime for implementing more precise transitions beetween spheres of influence, /// but performance cost is high /// </summary> public void SetMostProperAttractorForBody(CelestialBody body) { body.SetAttractor(FindMostProperAttractor(body), false, true); }
/// <summary> /// Fast and simple way to find attractor; /// But note, that not always nearest attractor is most proper /// </summary> /// <param name="body"></param> public void FindNearestAttractorForBody(CelestialBody body) { CelestialBody resultAttractor = null; float sqrDistance = 0; if (!Application.isPlaying) { _bodies = new List<CelestialBody>(GameObject.FindObjectsOfType<CelestialBody>()); } foreach (var otherBody in _bodies) { if (otherBody == body || otherBody.Mass < MinAttractorMass || ( otherBody.transform.position - body.transform.position ).magnitude > Mathf.Min(MaxAttractionRange, otherBody.MaxAttractionRange)) { continue; } float _sqrDistance = ( body._transform.position - otherBody._transform.position ).sqrMagnitude; if (resultAttractor == null || sqrDistance > _sqrDistance) { resultAttractor = otherBody; sqrDistance = _sqrDistance; } } if (!Application.isPlaying) { _bodies.Clear(); //_bodies must be empty in editor mode } if (resultAttractor != null) { if (resultAttractor != body.Attractor) { body.SetAttractor(resultAttractor, false, true); } } }
/// <summary> /// Find biggest attractor in scene /// </summary> public void GetCentralAttractor() { var tempBodies = Application.isPlaying ? _bodies.ToArray() : GameObject.FindObjectsOfType<CelestialBody>(); if (tempBodies.Length == 0) { _centralAttractor = null; return; } if (tempBodies.Length == 1) { _centralAttractor = tempBodies[0]; return; } var biggestMassIndex = 0; for (int i = 1; i < tempBodies.Length; i++) { if (!Application.isPlaying) { tempBodies[i - 1].FindReferences(); tempBodies[i].FindReferences(); } if (tempBodies[i].Mass > tempBodies[biggestMassIndex].Mass) { biggestMassIndex = i; } } if (biggestMassIndex >= 0 && biggestMassIndex < tempBodies.Length) { _centralAttractor = tempBodies[biggestMassIndex]; } }
public Vector2 CalcAcceleration(CelestialBody body) { Vector2 forceAcceleration = Vector2.zero; for (int i = 0; i < _attractorsCache.Count; i++) { if (_attractorsCache[i] == body) { continue; } forceAcceleration += AccelerationByAttractionForce(body._transform.position, _attractorsCache[i]._transform.position, _attractorsCache[i].MG, MinAttractionRange, Mathf.Min(MaxAttractionRange, _attractorsCache[i].MaxAttractionRange)); } return forceAcceleration; }
void Start() { cbody = GetComponentInParent<CelestialBody>(); if (cbody == null) { enabled = false; } }
public void SetBiggestAttractorForBody(CelestialBody body) { body.SetAttractor(FindBiggestAttractor(), false, true); }
/// <summary> /// Test body for chain loops /// </summary> public bool AttractorChainContains(CelestialBody body) { CelestialBody current = Attractor; while (current != null) { if (current == body) { return true; } current = current.Attractor; } return false; }
/// <summary> /// Find attractor which has biggest gravitational influence on body comparing to others. If fail, null will be assigned. /// It can be used in realtime for implementing more precise transitions beetween spheres of influence, /// but, without optimisations, performance cost definetly will be very high /// </summary> /// <param name="body"></param> public void FindMostProperAttractorForBody(CelestialBody body) { CelestialBody resultAttractor = null; if (!Application.isPlaying) { _bodies = new List<CelestialBody>(GameObject.FindObjectsOfType<CelestialBody>()); } // Search logic: // calculate mutual perturbation for every pair of attractors in scene and select one, // which attracts the body with biggest force and is least affected by others. foreach (var otherBody in _bodies) { if (otherBody == body || !otherBody.isActiveAndEnabled || otherBody.Mass < MinAttractorMass || ( otherBody.transform.position - body.transform.position ).magnitude > Mathf.Min(MaxAttractionRange, otherBody.MaxAttractionRange)) { continue; } if (!Application.isPlaying) { otherBody.FindReferences(); } if (resultAttractor == null) { resultAttractor = otherBody; continue; } if (RelativePerturbationRatio(body, resultAttractor, otherBody) > RelativePerturbationRatio(body, otherBody, resultAttractor)) { resultAttractor = otherBody; } } if (!Application.isPlaying) { _bodies.Clear(); //_bodies must be empty in editor mode } if (resultAttractor != body.Attractor) { body.SetAttractor(resultAttractor, false, true); //body.Attractor = resultAttractor; } }
/// <summary> /// Fast and simple way to find attractor; /// But note, that not always nearest attractor is most proper /// </summary> public void SetNearestAttractorForBody(CelestialBody body) { body.SetAttractor(FindNearestAttractor(body), false, true); }