/// <summary> /// Copies the given Magnet's data into this Magnet's data /// </summary> /// <param name="cMagnetToCopy">The Magnet to copy from</param> public void CopyFrom(DefaultParticleSystemMagnet cMagnetToCopy) { Mode = cMagnetToCopy.Mode; DistanceFunction = cMagnetToCopy.DistanceFunction; meMagnetType = cMagnetToCopy.MagnetType; MinDistance = cMagnetToCopy.MinDistance; MaxDistance = cMagnetToCopy.MaxDistance; MaxForce = cMagnetToCopy.MaxForce; UserDefinedMagnetType = cMagnetToCopy.UserDefinedMagnetType; }
/// <summary> /// Calculates how much affect each of the Particle System's Magnets should have on /// this Particle and updates the Particle's Velocity accordingly. /// </summary> /// <param name="cParticle">The Particle to update</param> /// <param name="fElapsedTimeInSeconds">How long it has been since the last update</param> protected void UpdateParticleVelocityAccordingToMagnets(DPSFDefaultBaseParticle cParticle, float fElapsedTimeInSeconds) { // Loop through each of the Particle System's Magnets for (int index = 0; index < MagnetList.Count; index++) { DefaultParticleSystemMagnet magnet = MagnetList[index]; // If this is not a custom user Magnet (i.e. it is Attracting or Repelling) if (magnet.Mode != DefaultParticleSystemMagnet.MagnetModes.Other) { // Apply the Force to the Particle's Position cParticle.Velocity += (CalculateForceMagnetShouldExertOnParticle(magnet, cParticle) * fElapsedTimeInSeconds); } } }
/// <summary> /// Calculates how much affect each of the Particle System's Magnets should have on /// this Particle and updates the Particle's Velocity accordingly. /// </summary> /// <param name="cParticle">The Particle to update</param> /// <param name="fElapsedTimeInSeconds">How long it has been since the last update</param> protected void UpdateParticleVelocityAccordingToMagnets(DPSFDefaultBaseParticle cParticle, float fElapsedTimeInSeconds) { // Temp handle to a Magnet DefaultParticleSystemMagnet cMagnet = null; // Loop through each of the Particle System's Magnets LinkedListNode <DefaultParticleSystemMagnet> cNode = MagnetList.First; while (cNode != null) { // Get a handle to this Magnet cMagnet = (DefaultParticleSystemMagnet)cNode.Value; // If this is not a custom user Magnet (i.e. it is Attracting or Repelling) if (cMagnet.Mode != DefaultParticleSystemMagnet.MagnetModes.Other) { // Apply the Force to the Particle's Position cParticle.Velocity += (CalculateForceMagnetShouldExertOnParticle(cMagnet, cParticle) * fElapsedTimeInSeconds); } // Move to the next Magnet in the list cNode = cNode.Next; } }
/// <summary> /// Copy Constructor /// </summary> /// <param name="cMagnetToCopy">The Magnet to copy from</param> protected DefaultParticleSystemMagnet(DefaultParticleSystemMagnet cMagnetToCopy) { CopyFrom(cMagnetToCopy); }
/// <summary> /// Copies the given Magnet's data into this Magnet's data /// </summary> /// <param name="cMagnetToCopy">The Magnet to copy from</param> public void CopyFrom(DefaultParticleSystemMagnet cMagnetToCopy) { Mode = cMagnetToCopy.Mode; DistanceFunction = cMagnetToCopy.DistanceFunction; meMagnetType = cMagnetToCopy.MagnetType; MinDistance = cMagnetToCopy.MinDistance; MaxDistance = cMagnetToCopy.MaxDistance; MaxForce = cMagnetToCopy.MaxForce; UserDefinedMagnetType = cMagnetToCopy.UserDefinedMagnetType; }
/// <summary> /// Copy Constructor /// </summary> /// <param name="cMagnetToCopy">The Magnet to copy from</param> public DefaultParticleSystemMagnet(DefaultParticleSystemMagnet cMagnetToCopy) { CopyFrom(cMagnetToCopy); }
/// <summary> /// Returns the vector force that a Magnet should exert on a Particle /// </summary> /// <param name="cMagnet">The Magnet affecting the Particle</param> /// <param name="cParticle">The Particle being affected by the Magnet</param> /// <returns>Returns the vector force that a Magnet should exert on a Particle</returns> protected Vector3 CalculateForceMagnetShouldExertOnParticle(DefaultParticleSystemMagnet cMagnet, DPSFDefaultBaseParticle cParticle) { // Variable to store the Force to Exert on the Particle Vector3 sForceToExertOnParticle = Vector3.Zero; // Calculate which Direction to push the Particle Vector3 sDirectionToPushParticle; // If this is a Point Magnet if (cMagnet.MagnetType == DefaultParticleSystemMagnet.MagnetTypes.PointMagnet) { // Cast the Magnet to the proper type MagnetPoint cPointMagnet = (MagnetPoint)cMagnet; // Calculate the direction to attract the Particle to the point in space where the Magnet is sDirectionToPushParticle = cPointMagnet.PositionData.Position - cParticle.Position; } // Else If this is a Line Magnet else if (cMagnet.MagnetType == DefaultParticleSystemMagnet.MagnetTypes.LineMagnet) { // Cast the Magnet to the proper type MagnetLine cLineMagnet = (MagnetLine)cMagnet; // Calculate the closest point on the Line to the Particle. // Equation taken from http://ozviz.wasp.uwa.edu.au/~pbourke/geometry/pointline/ // Also explained at http://www.allegro.cc/forums/thread/589720 // Calculate 2 points on the Line Vector3 sPosition1 = cLineMagnet.PositionOnLine; Vector3 sPosition2 = cLineMagnet.PositionOnLine + cLineMagnet.Direction; // Put calculations into temp variables for speed and easy readability float fA = cParticle.Position.X - sPosition1.X; float fB = cParticle.Position.Y - sPosition1.Y; float fC = cParticle.Position.Z - sPosition1.Z; float fD = sPosition2.X - sPosition1.X; float fE = sPosition2.Y - sPosition1.Y; float fF = sPosition2.Z - sPosition1.Z; // Next calculate the value of U. // NOTE: The Direction is normalized, so the distance between Position1 and Position2 is one, so we // don't need to bother squaring and dividing by the length here. float fU = (fA * fD) + (fB * fE) + (fC * fF); // Calculate the closest point on the Line to the Particle Vector3 sClosestPointOnLine = new Vector3(); sClosestPointOnLine.X = sPosition1.X + (fU * fD); sClosestPointOnLine.Y = sPosition1.Y + (fU * fE); sClosestPointOnLine.Z = sPosition1.Z + (fU * fF); // Calculate the direction to attract the Particle to the closest point on the Line sDirectionToPushParticle = sClosestPointOnLine - cParticle.Position; } // Else if the is a Line Segment Magnet else if (cMagnet.MagnetType == DefaultParticleSystemMagnet.MagnetTypes.LineSegmentMagnet) { // Cast the Magnet to the proper type MagnetLineSegment cLineSegmentMagnet = (MagnetLineSegment)cMagnet; // Calculate the closest point on the Line to the Particle. // Equation taken from http://ozviz.wasp.uwa.edu.au/~pbourke/geometry/pointline/ // Also explained at http://www.allegro.cc/forums/thread/589720 // Calculate 2 points on the Line Vector3 sPosition1 = cLineSegmentMagnet.EndPoint1; Vector3 sPosition2 = cLineSegmentMagnet.EndPoint2; // Put calculations into temp variables for speed and easy readability float fA = cParticle.Position.X - sPosition1.X; float fB = cParticle.Position.Y - sPosition1.Y; float fC = cParticle.Position.Z - sPosition1.Z; float fD = sPosition2.X - sPosition1.X; float fE = sPosition2.Y - sPosition1.Y; float fF = sPosition2.Z - sPosition1.Z; // Next calculate the value of U float fDot = (fA * fD) + (fB * fE) + (fC * fF); float fLengthSquared = (fD * fD) + (fE * fE) + (fF * fF); float fU = fDot / fLengthSquared; // Calculate the closest point on the Line to the Particle Vector3 sClosestPointOnLine = new Vector3(); // If the Particle is closest to the first End Point if (fU < 0.0f) { sClosestPointOnLine = sPosition1; } // Else If the Particle is closest to the second End Point else if (fU > 1.0f) { sClosestPointOnLine = sPosition2; } // Else the Particle is closest to the Line Segment somewhere between the End Points else { // Calculate where in between the End Points the Particle is closest to sClosestPointOnLine.X = sPosition1.X + (fU * (sPosition2.X - sPosition1.X)); sClosestPointOnLine.Y = sPosition1.Y + (fU * (sPosition2.Y - sPosition1.Y)); sClosestPointOnLine.Z = sPosition1.Z + (fU * (sPosition2.Z - sPosition1.Z)); } // Calculate the direction to attract the Particle to the closest point on the Line sDirectionToPushParticle = sClosestPointOnLine - cParticle.Position; } // Else If this is a Plane Magnet else if (cMagnet.MagnetType == DefaultParticleSystemMagnet.MagnetTypes.PlaneMagnet) { // Cast the Magnet to the proper type MagnetPlane cPlaneMagnet = (MagnetPlane)cMagnet; // Calculate the closest point on the Plane to the Particle. // Equation taken from http://ozviz.wasp.uwa.edu.au/~pbourke/geometry/pointline/ // Calculate how far from the Plane the Particle is float fDistanceFromPlane = Vector3.Dot(cParticle.Position - cPlaneMagnet.PositionOnPlane, cPlaneMagnet.Normal); // Calculate the closest point on the Plane to the Particle Vector3 sClosestPointOnPlane = cParticle.Position + (-cPlaneMagnet.Normal * fDistanceFromPlane); // Calculate the direction to attract the Particle to the closest point on the Plane sDirectionToPushParticle = sClosestPointOnPlane - cParticle.Position; } // Else we don't know what kind of Magnet this is else { // So exit returning no force return(Vector3.Zero); } // If the Particle should be Repelled away from the Magnet (instead of attracted to it) if (cMagnet.Mode == DefaultParticleSystemMagnet.MagnetModes.Repel) { // Reverse the direction we are going to push the Particle sDirectionToPushParticle *= -1; } // If the Direction To Push the Particle is not valid and we should be Repelling the Particle if (sDirectionToPushParticle == Vector3.Zero && cMagnet.Mode == DefaultParticleSystemMagnet.MagnetModes.Repel) { // Pick a random Direction vector with a very short length to repel the Particle with sDirectionToPushParticle = DPSFHelper.RandomNormalizedVector() * 0.00001f; } // Get how far away the Particle is from the Magnet float fDistanceFromMagnet = sDirectionToPushParticle.Length(); // If the Particle is within range to be affected by the Magnet if (fDistanceFromMagnet >= cMagnet.MinDistance && fDistanceFromMagnet <= cMagnet.MaxDistance) { // If the Direction To Push the Particle is valid if (sDirectionToPushParticle != Vector3.Zero) { // Normalize the Direction To Push the Particle sDirectionToPushParticle.Normalize(); } // Calculate the normalized distance from the Magnet that the Particle is float fLerpAmount = 0.0f; if (cMagnet.MaxDistance != cMagnet.MinDistance) { fLerpAmount = (fDistanceFromMagnet - cMagnet.MinDistance) / (cMagnet.MaxDistance - cMagnet.MinDistance); } // Else the Max Distance equals the Min Distance else { // So to avoid a divide by zero we just assume a full Lerp amount fLerpAmount = 1.0f; } // Calculate how much of the Max Force to apply to the Particle float fNormalizedForce = 0.0f; switch (cMagnet.DistanceFunction) { default: case DefaultParticleSystemMagnet.DistanceFunctions.Constant: fNormalizedForce = cMagnet.MaxForce; break; case DefaultParticleSystemMagnet.DistanceFunctions.Linear: fNormalizedForce = MathHelper.Lerp(0, cMagnet.MaxForce, fLerpAmount); break; case DefaultParticleSystemMagnet.DistanceFunctions.Squared: fNormalizedForce = MathHelper.Lerp(0, cMagnet.MaxForce, fLerpAmount * fLerpAmount); break; case DefaultParticleSystemMagnet.DistanceFunctions.Cubed: fNormalizedForce = MathHelper.Lerp(0, cMagnet.MaxForce, fLerpAmount * fLerpAmount * fLerpAmount); break; case DefaultParticleSystemMagnet.DistanceFunctions.LinearInverse: fNormalizedForce = MathHelper.Lerp(cMagnet.MaxForce, 0, fLerpAmount); break; case DefaultParticleSystemMagnet.DistanceFunctions.SquaredInverse: fNormalizedForce = MathHelper.Lerp(cMagnet.MaxForce, 0, fLerpAmount * fLerpAmount); break; case DefaultParticleSystemMagnet.DistanceFunctions.CubedInverse: fNormalizedForce = MathHelper.Lerp(cMagnet.MaxForce, 0, fLerpAmount * fLerpAmount * fLerpAmount); break; } // Calculate how much Force should be Exerted on the Particle sForceToExertOnParticle = sDirectionToPushParticle * (fNormalizedForce * cMagnet.MaxForce); } // Return how much Force to Exert on the Particle return(sForceToExertOnParticle); }
/// <summary> /// Copy Constructor /// </summary> /// <param name="cMagnetToCopy">The Magnet to copy from</param> public DefaultParticleSystemMagnet(DefaultParticleSystemMagnet cMagnetToCopy) { CopyFrom(cMagnetToCopy); }