public string ApproachPrediction(string moonName) { // @TODO: Too much C&P! // Step 1: Determine the patched conic xfer OrbitData shipOrbit = new OrbitData(); NBody shipNbody = spaceshipCtrl.GetNBody(); shipOrbit.SetOrbit(shipNbody, centralMass); OrbitData moonOrbit = new OrbitData(); NBody moonNbody = GetTargetByName(moonName); moonOrbit.SetOrbit(moonNbody, centralMass); //Make a copy of the universe state and evolve forward to find min distance to // moon. GravityEngine ge = GravityEngine.Instance(); GravityState gs = ge.GetGravityStateCopy(); // run a simulation and find the closest approach (Expensive!) LunarCourseCorrection lcc = new LunarCourseCorrection(shipNbody, moonNbody); // want to be within 10% of Earth-Moon distance, before start checking courseCorrectionData = new LunarCourseCorrection.CorrectionData(); courseCorrectionData.gravityState = gs; courseCorrectionData.approachDistance = 0.1f * moonOrbit.a;; courseCorrectionData.correction = 0; courseCorrectionData.maxPhysTime = time_to_moon_phys; lcc.ClosestApproachAsync(courseCorrectionData, MoonPreviewCompleted); return("Calculation started...\n"); }
public void PreEvolve(GravityState gravityState, ref byte[] info) { double[] mass = gravityState.m; double[,] pos = gravityState.r; Get_acc_jerk_pot_coll(ref mass, ref pos, ref info); initialEnergy = NUtils.GetEnergy(numBodies, ref mass, ref pos, ref vel); }
private void GravitySetter() { if (IsOnFloor()) { gravityState = GravityState.NORMAL; } if (rb.velocity.y < 0) { gravityState = GravityState.FALL; } if (rb.velocity.y > 0 && !(Input.GetButton("Jump"))) { gravityState = GravityState.LOWJUMP; } switch (gravityState) { case GravityState.NORMAL: gravityMultiplier = 1.0f; break; case GravityState.FALL: gravityMultiplier = fallMultiplier; break; case GravityState.LOWJUMP: gravityMultiplier = lowJumpMultiplier; break; } rb.velocity += Vector2.up * Physics2D.gravity.y * (gravityMultiplier - 1.0f) * Time.deltaTime; }
// Game wrapper to limit number of evolution loops public double Evolve(double time, GravityState gravityState, ref byte[] info) { double[] mass = gravityState.m; double[,] pos = gravityState.r; double t = 0; double maxDt = time / 5.0f; // minimum of 5 evolutions per update double minDt = time / 1000.0f; // maximum of 1000 evolutions per update int nloops = 0; while (t < time) { // If only one body collision time will be MAXFLOAT t += dt; Evolve_step(ref mass, ref pos, ref info); dt = dtInitial * coll_time; if (dt > maxDt) { dt = maxDt; } if (dt < minDt) { dt = minDt; } nloops++; } return(t); }
// void Jump() // { // if (isgrounded) // can remoce "True" because just saying it means its true.. "!" before will make it opposite (false).. "!=" means opposite of current result (isDead example with Time) // { // if (Input.GetButtonDown("Jump")) // { // // rb.AddForce(0, jumpforce, 0, ForceMode.Impulse); //I can jump one and dash forever, I might keep that // // // } // // } // } // void Dash() // This feature punishes players that use it too much. It gets harder to control // { // if (isgrounded) // { // if (Input.GetButtonDown("Dash")) // { // rb.AddForce(direction * dashforce, ForceMode.Impulse); // because in this case direction is a Vector3 // // } // // Debug.Log(rb.velocity); // // rb.velocity -= rb.velocity * Time.deltaTime * decceleration; // // // } // } // void GetDirectionInput() // { // float horizontalAxis = // Input.GetAxisRaw("Horizontal"); //this variable collects the value of the button pressed (1,0, or -1) // // float verticalAxis = Input.GetAxisRaw("Vertical"); // // // // Vector3 moveForward = transform.forward * verticalAxis; // Vector3 moveSide = transform.right * horizontalAxis; // // // // direction = (moveForward + moveSide); // // } // private void OnCollisionEnter(Collision collision) // { // if (collision.gameObject.tag == "Ground") // { // isgrounded = true; // // } // // // } void characterStateMethod() { RaycastHit hit; // Does the ray intersect any objects excluding the player layer if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.down), out hit, Mathf.Infinity)) { if (hit.distance > 0.5f) { //canJump = false; characterState = GravityState.Flying; print("State " + characterState); } //will check the hit distance and verify if we can jump or not if (hit.distance < 0.5f) { //canJump = true; characterState = GravityState.Ground; print("State " + characterState); } Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.down) * hit.distance, Color.yellow); } else { characterState = GravityState.Flying; Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.down) * hit.distance, Color.white); } // print("distance "+ hit.distance); }
private void Awake() { gravityState = GravityState.NORMAL; rb = GetComponent <Rigidbody2D>(); animator = GetComponent <Animator>(); player = GetComponent <PlayerScript>(); }
void Awake() { // Convert from real world units // Rocket engine thrust is given in SI units, so acceleration is in SI units // For Orbital scale need to convert to km/hr^2 accelerationConversion = GravityScaler.AccelSItoGEUnits(); // and convert to the physics scale used in the engine accelerationConversion = accelerationConversion * GravityScaler.AccelGEtoInternalUnits(); burnStart = new double[MAX_STAGES]; burnRateScale = GravityScaler.GetGameSecondPerPhysicsSecond(); fuelLevel = new double[MAX_STAGES]; for (int i = 0; i < numStages; i++) { fuelLevel[i] = massFuel[i]; } // acceleration will be opposite to thrust direction accelDirection = -thrustAxis; activeStage = 0; activeState = GravityEngine.Instance().GetWorldState(); SetEngine(engineOn); }
/// <summary> /// Sets the gravity state for a certain duration. /// </summary> /// <param name="state">New state to set.</param> /// <param name="duration">Optional delay until the new state is set.</param> public void SetGravityState(GravityState state, float duration = 1f) { currentState = state; SetRigidbodyGravity(); // TODO - Glow animation? returnToInitial = true; timer = duration; }
// Checks if check for ground is needed protected void CheckIfGrounded() { if (checkForGround) { if (Physics.CheckSphere(groundCheck.position, groundDistance, groundMask)) { currentGravityState = GravityState.Grounded; currentFallSpeed = gravityOnGround; } } }
public override double[] acceleration(double time, GravityState gravityState, ref double massKg) { // a(t) = Thrust/m(t) // Called on every integration timestep - so favour speed over beauty // Will be called by both trajectory prediction and game evolution, so needs to be a function of time // (i.e. cannot reduce fuel each time this routine is called!) double[] a = new double[3] { 0, 0, 0 }; double activeFuel = 0; // always need the mass for drag calc (even if engine is off) massKg = payloadMass; // TODO - could optimize and precompute (mass per stage - fuel) in that stage // add stage masses for (int i = activeStage; i < numStages; i++) { massKg += massStageEmpty[i]; } // add fuel of unused stages for (int i = activeStage + 1; i < numStages; i++) { massKg += massFuel[i]; } // thrust if (engineOn && (fuelLevel[activeStage] > 0)) { if (gravityState == activeState) { fuelLevel[activeStage] -= throttle * burnRateScale * burnRate[activeStage] * (time - lastTime); if (fuelLevel[activeStage] < 0) { fuelLevel[activeStage] = 0; } activeFuel = fuelLevel[activeStage]; lastTime = time; } else { activeFuel = fuelLevel[activeStage] - throttle * burnRateScale * burnRate[activeStage] * (time - lastTime); } if (activeFuel > 0) { massKg += activeFuel; double a_scalar = accelerationConversion * thrust[activeStage] * throttle / massKg; a[0] = a_scalar * accelDirection.x; a[1] = a_scalar * accelDirection.y; a[2] = a_scalar * accelDirection.z; } } return(a); }
public void PreEvolve(GravityState gravityState, ref byte[] info) { double[] m = gravityState.m; double[,] r = gravityState.r; // Precalc initial acceleration double[] rji = new double[GravityEngine.NDIM]; double r2; double r3; double r_sep; double accel; for (int i = 0; i < numBodies; i++) { for (int k = 0; k < GravityEngine.NDIM; k++) { a[i, k] = 0.0; } } for (int i = 0; i < numBodies; i++) { for (int j = i + 1; j < numBodies; j++) { r2 = 0; for (int k = 0; k < GravityEngine.NDIM; k++) { rji[k] = r[j, k] - r[i, k]; r2 += rji[k] * rji[k]; } if (forceDelegate == null) { r3 = r2 * System.Math.Sqrt(r2) + EPSILON; for (int k = 0; k < GravityEngine.NDIM; k++) { a[i, k] += m[j] * rji[k] / r3; a[j, k] -= m[i] * rji[k] / r3; } } else { r_sep = System.Math.Sqrt(r2) + EPSILON; accel = forceDelegate.CalcF(r_sep); for (int k = 0; k < GravityEngine.NDIM; k++) { a[i, k] += m[j] * accel * (rji[k] / r_sep); a[j, k] -= m[i] * accel * (rji[k] / r_sep); } } } } initialEnergy = NUtils.GetEnergy(numBodies, ref m, ref r, ref v); }
private void SetGravityState(GravityState state) { gravState = state; switch (gravState) { case GravityState.AIRBORN: SetAirbornPhysics(); break; case GravityState.GROUND: SetGroundPhysics(); break; } }
void Start() { SetEngine(engineOn); // Convert from real world units // Rocket engine thrust is given in SI units, so acceleration is in SI units // For Orbital scale need to convert to km/hr^2 accelerationConversion = GravityScaler.AccelSItoGEUnits(); // and convert to the physics scale used in the engine accelerationConversion = accelerationConversion * GravityScaler.AccelGEtoInternalUnits(); burnRateScaled = burnRate * GravityScaler.GetGameSecondPerPhysicsSecond(); thrustDirection = thrustAxis; fuelLevel = massFuel; activeState = GravityEngine.Instance().GetWorldState(); }
public void Impact(NBody nbody, GravityState gravityState) { if (!impactFlag) { Vector3 vel = GravityEngine.Instance().GetScaledVelocity(nbody); Vector3 pos = gravityState.GetPhysicsPosition(nbody); pos = GravityEngine.Instance().physToWorldFactor *pos; Debug.LogFormat("Set pos={0} |pos| = {1}", pos, pos.magnitude); GravityEngine.Instance().InactivateBody(nbody.gameObject); nbody.GEUpdate(pos, vel, GravityEngine.Instance()); this.nbody = nbody; impactFlag = true; } }
// Called by Evolve after particles have been inited. // - calculate the current acceleration on each particle so that on first LF step will evolve smoothly private void PreEvolve(int fromP, int toP, int numBodies, GravityState gravityState, ref byte[] info) { double[] m = gravityState.m; double[,] r_m = gravityState.r; // Precalc initial acceleration double[] rji = new double[GravityState.NDIM]; double r2; double r3; for (int i = fromP; i < toP; i++) { for (int k = 0; k < GravityState.NDIM; k++) { a[i, k] = 0.0; } } // evolve over all massive objects for (int i = 0; i < numBodies; i++) { if ((info[i] & GravityEngine.INACTIVE) == 0) { for (int j = fromP; j < toP; j++) { for (int k = 0; k < GravityState.NDIM; k++) { rji[k] = r[j, k] - r_m[i, k]; } r2 = 0; for (int k = 0; k < GravityState.NDIM; k++) { r2 += rji[k] * rji[k]; } r3 = r2 * System.Math.Sqrt(r2) + EPSILON; for (int k = 0; k < GravityState.NDIM; k++) { a[j, k] += m[i] * rji[k] / r3; } #pragma warning disable 162, 429 // disable unreachable code warning if (debugLogs && j == 0) { Debug.Log(string.Format("PreEvolve : Initial a={0} {1} {2} rji={3} {4} {5} body={6} m={7}", a[0, 0], a[0, 1], a[0, 2], rji[0], rji[1], rji[2], i, m[i])); } #pragma warning restore 162, 429 } } } }
/// <summary> /// Pre-evolve the massless bodies based in the array information about the massive bodies in the /// system. /// </summary> /// <param name="numMasses">Number masses.</param> /// <param name="m">Mass array for massive bodies</param> /// <param name="r_m">Position array for massive bodies.</param> public void PreEvolve(int numMasses, GravityState gravityState) { double[] m = gravityState.m; double[,] r_m = gravityState.r; if (numMasses == 0 && numBodies == 0) { return; } // Precalc initial acceleration double[] rji = new double[GravityEngine.NDIM]; double r2; double r3; for (int i = 0; i < numBodies; i++) { a[i, 0] = 0.0; a[i, 1] = 0.0; a[i, 2] = 0.0; } // precalc initial acceleration due to massive bodies for (int i = 0; i < numMasses; i++) { for (int j = 0; j < numBodies; j++) { for (int k = 0; k < GravityEngine.NDIM; k++) { rji[k] = r[j, k] - r_m[i, k]; } r2 = 0; for (int k = 0; k < GravityEngine.NDIM; k++) { r2 += rji[k] * rji[k]; } r3 = r2 * System.Math.Sqrt(r2) + EPSILON; for (int k = 0; k < GravityEngine.NDIM; k++) { a[j, k] += m[i] * rji[k] / r3; } } } #pragma warning disable 162 // disable unreachable code warning if (GravityEngine.DEBUG) { Debug.Log(string.Format("PreEvolve: Initial a={0} {1} {2}", a[0, 0], a[0, 1], a[0, 2])); } #pragma warning restore 162 }
private void SetGravity(GravityState gstate) { gravityState = gstate; switch (GravityState) { case GravityState.Moon: Current = moonGrav; break; case GravityState.Earth: Current = earthGrav; break; default: Current = Vector2.zero; break; } }
public double Evolve(double time, GravityState gravityState, ref byte[] info) { double[] mass = gravityState.m; double[,] pos = gravityState.r; this.gravityState = gravityState; t_offset = 0; t_evolveStart = gravityState.GetPhysicsTime(); int nloops = 0; if (dt > time) { dt = time; } while (t_offset < time) { // If only one body collision time will be MAXFLOAT t_offset += dt; Evolve_step(ref mass, ref pos, ref info); // timestep adjustement, relative to initial collision time coll_time_avg = COLL_AVERAGE_FACTOR * coll_time_avg + (1 - COLL_AVERAGE_FACTOR) * coll_time; dt = dtInitial * coll_time_avg / coll_time_initial; if (dt > maxDt) { dt = maxDt; } else if (dt < minDt) { dt = minDt; } nloops++; } #pragma warning disable 162 // disable unreachable code warning if (GravityEngine.DEBUG) { if (logCount++ > LOG_INTERVAL) { logCount = 0; Debug.LogFormat("time={0} dt={1} coll_time={2} coll_factor={3} coll_time_initial={4} nloops={5} numbodies={6}", time, dt, coll_time, coll_time_avg / coll_time_initial, coll_time_initial, nloops, numBodies); } } #pragma warning restore 162 return(t_offset); }
/// <summary> /// Execute the maneuver. Called automatically by Gravity Engine for maneuvers that /// have been added to the GE via AddManeuver(). /// /// Unusual to call this method directly. /// </summary> /// <param name="ge"></param> public void Execute(GravityState gs) { double[] vel = new double[3] { 0, 0, 0 }; gs.GetVelocityDouble(nbody, ref vel); switch (mtype) { case Mtype.vector: vel[0] += velChange[0]; vel[1] += velChange[1]; vel[2] += velChange[2]; break; case Mtype.scalar: // scalar: adjust existing velocity by dV Vector3d vel3d = new Vector3d(ref vel); Vector3d change = Vector3d.Normalize(vel3d) * dV; vel[0] += change[0]; vel[1] += change[1]; vel[2] += change[2]; break; case Mtype.setv: // direct assignement (this mode normally used for debug) vel[0] = velChange[0]; vel[1] = velChange[1]; vel[2] = velChange[2]; break; } #pragma warning disable 162 // disable unreachable code warning if (GravityEngine.DEBUG) { if (!gs.isAsync) { Debug.Log("Applied manuever: " + LogString() + " engineRef.index=" + nbody.engineRef.index + " engineRef.bodyType=" + nbody.engineRef.bodyType + " timeError=" + (worldTime - gs.time)); Debug.LogFormat("r={0} v=({1},{2},{3}) ", Vector3.Magnitude(nbody.transform.position), vel[0], vel[1], vel[2]); } } #pragma warning restore 162 // enable unreachable code warning gs.SetVelocityDouble(nbody, ref vel); }
private void SetGravity(GravityState gstate) { gravityState = gstate; switch (GravityState) { case GravityState.Low: Current = lowGrav; break; case GravityState.Normal: Current = normalGrav; break; default: Current = Vector2.zero; break; } }
/// <summary> /// Returns the gravity value for a given state. /// </summary> /// <param name="state">State to get gravity value from.</param> /// <returns>Gravity value of the state.</returns> public static float GetStateGravity(GravityState state) { switch (state) { case GravityState.NormalGravity: return(normalGravity); case GravityState.MoonGravity: return(moonGravity); case GravityState.GroundedGravity: return(groundedGravity); case GravityState.Weightless: return(zeroGravity); default: return(normalGravity); } }
public double[] acceleration(double time, GravityState gravityState, ref double massKg) { a_rocket = engine.acceleration(time, gravityState, ref massKg); // need to update mass as fuel is consumed atmosphere.inertialMassKg = massKg; a_atmosphere = atmosphere.acceleration(time, gravityState, ref massKg); a[0] = a_rocket[0] + a_atmosphere[0]; a[1] = a_rocket[1] + a_atmosphere[1]; a[2] = a_rocket[2] + a_atmosphere[2]; // cache the last atmosphere accel for world state (need to check since could be trajectories // asking for accel as well) if (gravityState == worldState) { a_last[0] = a[0]; a_last[1] = a[1]; a_last[2] = a[2]; } return(a); }
public string MoonPreview(string moonName, float lambda1, bool async) { // Step 1: Determine the patched conic xfer OrbitData shipOrbit = new OrbitData(); NBody shipNbody = spaceshipCtrl.GetNBody(); shipOrbit.SetOrbit(shipNbody, centralMass); OrbitData moonOrbit = new OrbitData(); NBody moonNbody = GetTargetByName(moonName); moonOrbit.SetOrbit(moonNbody, centralMass); OrbitTransfer xfer = new PatchedConicXfer(shipOrbit, moonOrbit, lambda1); // Step 2: Make a copy of the universe state and evolve forward to find min distance to // moon. GravityEngine ge = GravityEngine.Instance(); GravityState gs = ge.GetGravityStateCopy(); // there is only one maneuver to add gs.maneuverMgr.Add(xfer.GetManeuvers()[0]); // run a simulation and find the closest approach (Expensive!) LunarCourseCorrection lcc = new LunarCourseCorrection(shipNbody, moonNbody); // want to be within 10% of Earth-Moon distance, before start checking courseCorrectionData = new LunarCourseCorrection.CorrectionData(); courseCorrectionData.gravityState = gs; courseCorrectionData.approachDistance = 0.1f * moonOrbit.a;; courseCorrectionData.correction = 0; courseCorrectionData.maxPhysTime = time_to_moon_phys; // Direct (unthreaded) calculation if (async) { lcc.ClosestApproachAsync(courseCorrectionData, MoonPreviewCompleted); return("Calculation started...\n"); } else { predictedDistance = lcc.ClosestApproach(courseCorrectionData); return(string.Format("Patched Conic with lambda={0} => approach={1}\n", lambda1, predictedDistance)); } }
public override double[] acceleration(double time, GravityState gravityState, ref double massKg) { // a(t) = Thrust/m(t) // Will be called by both trajectory prediction and game evolution, so needs to be a function of time // (i.e. cannot reduce fuel each time this routine is called!) double[] a = new double[3] { 0, 0, 0 }; double activeFuel = 0; if (engineOn) { massKg = massEmpty; if (gravityState == activeState) { fuelLevel -= throttle * burnRate * burnRateScaled * (time - lastTime); if (fuelLevel < 0) { fuelLevel = 0; } activeFuel = fuelLevel; lastTime = time; } else { activeFuel = fuelLevel - throttle * burnRate * burnRateScaled * (time - lastTime); } if (activeFuel > 0) { massKg += activeFuel; double a_scalar = accelerationConversion * thrust / massKg; a[0] = a_scalar * thrustDirection.x; a[1] = a_scalar * thrustDirection.y; a[2] = a_scalar * thrustDirection.z; } //Debug.Log(string.Format("a=({0}, {1}, {2}) fuel={3}", a[0], a[1], a[2], fuel)); } return(a); }
IEnumerator RotateWorld(bool clockwise) { rotating = true; movement.gravity = Vector3.zero; GravityState oldState = gravityStates[gravityIndex]; gravityIndex = RangeMath.CycleInt(gravityIndex, gravityStates.Length - 1, clockwise); GravityState newState = gravityStates[gravityIndex]; Quaternion oldRotation = Quaternion.Euler(oldState.objectRotation); Quaternion newRotation = Quaternion.Euler(newState.objectRotation); float oldZAngle = pivot.localEulerAngles.z; float newZAngle = oldZAngle + rotationDegrees * (clockwise ? -1 : 1); float timer = 0; while (timer < rotationTime) { timer += Time.deltaTime; if (timer > rotationTime) { timer = rotationTime; } foreach (Transform rotor in toRotate) { rotor.rotation = Quaternion.Lerp(oldRotation, newRotation, timer / rotationTime); } float z = Mathf.Lerp(oldZAngle, newZAngle, timer / rotationTime); VectorMath.SetZRotation(pivot, z); yield return(null); } movement.gravity = newState.gravityDirection; rotating = false; }
/// <summary> /// Validation: /// - confirmed velocity in SI units matches expected orbital velocity of ISS /// - checked that SI acceleration = -g at terminal velocity (9.73 m/s^2 at 28 km) /// </summary> // Use this for initialization void Start() { if (inertialMassKg == 0) { Debug.LogError("Mass is zero. Drag calculation will fail."); } if (spaceship == null) { spaceship = GetComponent <NBody>(); } geDistanceToKm = 1; v_ship = new double[] { 0, 0, 0 }; v_earth = new double[] { 0, 0, 0 }; velocityScaleInternalToSI = GravityScaler.VelocityScaletoSIUnits() / GravityScaler.GetVelocityScale(); accelSItoGE = GravityScaler.AccelSItoGEUnits() / GravityScaler.AccelerationScaleInternalToGEUnits(); LoadDensityProfile(); liveState = GravityEngine.Instance().GetWorldState(); }
// clone constructor public GravityState(GravityState fromState) { m = new double[fromState.arraySize]; r = new double[fromState.arraySize, GravityEngine.NDIM]; physicalTime = new double[System.Enum.GetNames(typeof(Evolvers)).Length]; arraySize = fromState.arraySize; for (int i = 0; i < physicalTime.Length; i++) { physicalTime[i] = fromState.physicalTime[i]; } time = fromState.time; for (int i = 0; i < arraySize; i++) { m[i] = fromState.m[i]; for (int j = 0; j < GravityEngine.NDIM; j++) { r[i, j] = fromState.r[i, j]; } } }
void Start() { worldState = GravityEngine.Instance().GetWorldState(); accelGEtoSI = GravityScaler.AccelerationScaleInternalToGEUnits() / GravityScaler.AccelSItoGEUnits(); }
/// <summary> /// Evolves particles using massice bodies the with force delegate provided. /// </summary> /// <returns>The with force.</returns> /// <param name="evolveTime">Evolve time.</param> /// <param name="numBodies">Number bodies.</param> /// <param name="m">M.</param> /// <param name="r_m">R m.</param> /// <param name="size2">Size2.</param> /// <param name="info">Info.</param> /// <param name="force">Force.</param> public double EvolveWithForce(double evolveTime, int numBodies, GravityState gravityState, ref double[] size2, ref byte[] info, IForceDelegate force) { // do nothing if all inactive if (inactive == null || allInactive) { return(evolveTime); // Particle system has not init-ed yet or is done } // (did not work in Start() -> Unity bug? Init sequencing?) if (!playing) { gravityParticles.Play(); playing = true; } double[] m = gravityState.m; double[,] r_m = gravityState.r; ParticleLifeCycleHandler(numBodies, gravityState, ref info); // // physics integration of particles in the field of the masses passed in by NBE // double time = 0; while (time < evolveTime) { time += dt; // Update v and r for (int i = 0; i < particleCount; i++) { if (!inactive[i]) { v[i, 0] += a[i, 0] * 0.5 * dt; r[i, 0] += v[i, 0] * dt; v[i, 1] += a[i, 1] * 0.5 * dt; r[i, 1] += v[i, 1] * dt; v[i, 2] += a[i, 2] * 0.5 * dt; r[i, 2] += v[i, 2] * dt; } } // advance acceleration double[] rji = new double[GravityState.NDIM]; double r2; // r squared double r_sep; // r double accel; // a = 0 for (int i = 0; i < particleCount; i++) { a[i, 0] = 0.0; a[i, 1] = 0.0; a[i, 2] = 0.0; } // calc a for (int i = 0; i < numBodies; i++) { // check mass has inactive clear if ((info[i] & GravityEngine.INACTIVE) == 0) { for (int j = 0; j < particleCount; j++) { // only evolve active particles if (!inactive[j]) { rji[0] = r[j, 0] - r_m[i, 0]; rji[1] = r[j, 1] - r_m[i, 1]; rji[2] = r[j, 2] - r_m[i, 2]; // Particles that have moved outside of view are marked inactive r2 = rji[0] * rji[0] + rji[1] * rji[1] + rji[2] * rji[2]; // Check for incursion on massive bodies and inactivate particles that have collided // (Do not want to incur collider overhead per particle) if (allowRemoval && r2 < size2[i]) { inactive[j] = true; inactiveCount++; #pragma warning disable 162 // disable unreachable code warning if (debugLogs) { Debug.Log(string.Format("Inactivate particle {0} size2={1} due to object at {2} {3} {4} r2={5} count={6} p={7} {8}", j, size2[i], r_m[i, 0], r_m[i, 1], r_m[i, 2], r2, inactiveCount, r[j, 0], r[j, 1])); } #pragma warning restore 162 if (oneTimeBurst) { r[j, 0] = OUT_OF_VIEW; } else { particles[j].remainingLifetime = 0; } continue; } r_sep = System.Math.Sqrt(r2) + EPSILON; accel = force.CalcPseudoForce(r_sep, i, j); a[j, 0] -= m[i] * accel * (rji[0] / r_sep); a[j, 1] -= m[i] * accel * (rji[1] / r_sep); a[j, 2] -= m[i] * accel * (rji[2] / r_sep); } // for j } // info } // for i } // update velocity for (int i = 0; i < particleCount; i++) { if (!inactive[i]) { v[i, 0] += a[i, 0] * 0.5 * dt; v[i, 1] += a[i, 1] * 0.5 * dt; v[i, 2] += a[i, 2] * 0.5 * dt; } } } // while return(time); }
// // Emmisive particle management // - per cycle look for new particles or cases where particles expired and were shuffled // void ParticleLifeCycleHandler(int numBodies, GravityState gravityState, ref byte[] info) { // Particle life cycle management // - need GetParticles() call to get the correct number of active particle (p.particleCount did not work) // - IIUC this is a re-copy and it would be better to avoid this if possible particleCount = gravityParticles.GetParticles(particles); if (lastParticleCount < particleCount) { // there are new particles if (particlesInit != null) { particlesInit.InitNewParticles(lastParticleCount, gravityParticles.particleCount, ref r, ref v); // apply mass scale to particle velocities } else { NoInitDelegateSetup(lastParticleCount, gravityParticles.particleCount); } PreEvolve(lastParticleCount, gravityParticles.particleCount, numBodies, gravityState, ref info); for (int i = lastParticleCount; i < gravityParticles.particleCount; i++) { inactive[i] = false; seed[i] = particles[i].randomSeed; particleBySeed[particles[i].randomSeed] = i; } lastParticleCount = gravityParticles.particleCount; } if (oneTimeBurst) { // not doing life cycle for this particle system return; } // Check if any existing particles were replaced. // As particles expire, Unity will move particles from the end down into their slot and reduce // the number of active particles. Need to detect this and move their physics data. // This makes emmisive particle systems more CPU intensive. for (int i = 0; i < gravityParticles.particleCount; i++) { if (seed[i] != particles[i].randomSeed) { #pragma warning disable 162 // disable unreachable code warning if (debugLogs) { Debug.Log("Seed changed was:" + seed[i] + " now:" + particles[i].randomSeed); } #pragma warning restore 162 // particle has been replaced particleBySeed.Remove(seed [i]); // remove old seed from hash if (particleBySeed.ContainsKey(particles[i].randomSeed)) { // particle was moved - copy physical data down int oldIndex = particleBySeed[particles[i].randomSeed]; for (int k = 0; k < 3; k++) { r [i, k] = r [oldIndex, k]; v [i, k] = v [oldIndex, k]; a [i, k] = a [oldIndex, k]; } particleBySeed [particles[i].randomSeed] = i; #pragma warning disable 162 // disable unreachable code warning if (debugLogs) { Debug.Log("Shuffling particle from " + oldIndex + " to " + i + " vel=" + v[i, 0] + " " + v[i, 1]); } #pragma warning restore 162 } else { #pragma warning disable 162 // disable unreachable code warning if (debugLogs) { Debug.Log("Reusing particle " + i + " vel=" + particles[i].velocity); } #pragma warning restore 162 if (particlesInit != null) { particlesInit.InitNewParticles(i, i + 1, ref r, ref v); } else { NoInitDelegateSetup(i, i + 1); } PreEvolve(i, i + 1, numBodies, gravityState, ref info); particleBySeed[particles[i].randomSeed] = i; #pragma warning disable 162 // disable unreachable code warning if (debugLogs) { Debug.Log("Post-Setup Reusing particle " + i + " v[i,0]=" + v[i, 0] + " v[i,1]=" + v[i, 1]); } #pragma warning restore 162 } seed[i] = particles[i].randomSeed; inactive[i] = false; } } }
/// <summary> /// Evolves using the force delegate. Internals differ slightly and for effeciency do not want /// a conditional on forceDelegate in the inner loop. /// /// </summary> /// <returns>The force delegate.</returns> /// <param name="time">Time.</param> /// <param name="m">M.</param> /// <param name="r">The red component.</param> /// <param name="info">Info.</param> private double EvolveForceDelegate(double time, GravityState gravityState, ref byte[] info) { int numSteps = 0; double[] m = gravityState.m; double[,] r = gravityState.r; // advance acceleration double r2; double r_sep; double f; // If objects are fixed want to use their mass but not update their position // Better to calc their acceleration and ignore than add an if statement to core loop. for (double t = 0; t < time; t += dt) { numSteps++; // Update v and r for (int i = 0; i < numBodies; i++) { if ((info[i] & GravityEngine.FIXED_MOTION) == 0) { v[i, 0] += a[i, 0] * 0.5 * dt; r[i, 0] += v[i, 0] * dt; v[i, 1] += a[i, 1] * 0.5 * dt; r[i, 1] += v[i, 1] * dt; v[i, 2] += a[i, 2] * 0.5 * dt; r[i, 2] += v[i, 2] * dt; } } // a = 0 for (int i = 0; i < numBodies; i++) { a[i, 0] = 0.0; a[i, 1] = 0.0; a[i, 2] = 0.0; } // calc a for (int i = 0; i < numBodies; i++) { if ((info[i] & GravityEngine.INACTIVE) == 0) { for (int j = i + 1; j < numBodies; j++) { if ((info[j] & GravityEngine.INACTIVE) == 0) { // O(N^2) in here, unpack loops to optimize r2 = 0; rji[0] = r[j, 0] - r[i, 0]; r2 += rji[0] * rji[0]; rji[1] = r[j, 1] - r[i, 1]; r2 += rji[1] * rji[1]; rji[2] = r[j, 2] - r[i, 2]; r2 += rji[2] * rji[2]; r_sep = System.Math.Sqrt(r2) + EPSILON; f = forceDelegate.CalcF(r_sep); a[i, 0] += m[j] * f * (rji[0] / r_sep); a[i, 1] += m[j] * f * (rji[1] / r_sep); a[i, 2] += m[j] * f * (rji[2] / r_sep); a[j, 0] -= m[i] * f * (rji[0] / r_sep); a[j, 1] -= m[i] * f * (rji[1] / r_sep); a[j, 2] -= m[i] * f * (rji[2] / r_sep); } } } } // update velocity for (int i = 0; i < numBodies; i++) { if ((info[i] & GravityEngine.FIXED_MOTION) == 0) { v[i, 0] += a[i, 0] * 0.5 * dt; v[i, 1] += a[i, 1] * 0.5 * dt; v[i, 2] += a[i, 2] * 0.5 * dt; //DebugBody(i, ref m, ref r, "evolve"); } } // coll_time code } return(numSteps * dt); }