maybe for completeness, you could add a bounding sphere force field shape like the one i build on my own from your bounding box shape template:
Code: Select all
/// <summary>
/// Defines the area in which a force field works using an entity's shape.
/// </summary>
public class BoundingSphereForceFieldShape : ForceFieldShape
{
private readonly List<Entity> affectedEntities = new List<Entity>();
private readonly RawList<BroadPhaseEntry> affectedEntries = new RawList<BroadPhaseEntry>();
/// <summary>
/// Constructs a new force field shape using a bounding box.
/// </summary>
/// <param name="box">Bounding box to use.</param>
public BoundingSphereForceFieldShape(BoundingSphere sphere)
{
BoundingSphere = sphere;
}
/// <summary>
/// Gets or sets the bounding box used by the shape.
/// </summary>
public BoundingSphere BoundingSphere { get; set; }
/// <summary>
/// Determines the possibly involved entities.
/// </summary>
/// <returns>Possibly involved entities.</returns>
public override IList<Entity> GetPossiblyAffectedEntities()
{
affectedEntities.Clear();
ForceField.QueryAccelerator.GetEntries(BoundingSphere, affectedEntries);
for (int i = 0; i < affectedEntries.Count; i++) // changed 'count' to 'Count', guess it's internal and not available in my assembly
{
var EntityCollidable = affectedEntries[i] as EntityCollidable;
if (EntityCollidable != null)
affectedEntities.Add(EntityCollidable.Entity);
}
affectedEntries.Clear();
return affectedEntities;
}
/// <summary>
/// Determines if the entity is affected by the force field.
/// </summary>
/// <param name="testEntity">Entity to test.</param>
/// <returns>Whether the entity is affected.</returns>
public override bool IsEntityAffected(Entity testEntity)
{
return true;
}
}
Code: Select all
public class ExplosionForceField : ForceField
{
public ExplosionForceField(Vector3 position, float speed, float range, float maxForce, float angularRatio, float dt)
: base(new BoundingSphereForceFieldShape(new BoundingSphere(position, 0.0f)))
{
this.position = position;
this.speed = speed;
this.range = range;
this.angularRatio = angularRatio;
this.oneOverWaveFrontRange = 1.0f / (range / 20.0f);
this.waveFrontExpansion = 0.5f * range;
this.maxImpulse = maxForce * dt * speed / range;
ForceWakeUp = true;
}
/// <summary>
/// Calculates the impulse to apply to the center of mass of physically simulated bodies within the volume.
/// </summary>
/// <param name="e">Target of the impulse.</param>
/// <param name="dt">Time since the last frame in simulation seconds.</param>
/// <param name="impulse">Force to apply at the given position.</param>
protected override void CalculateImpulse(Entity e, float dt, out Vector3 impulse)
{
Vector3 delta = e.Position - position;
float entityPosition = delta.Length();
if (entityPosition == 0.0f) // entity exactly at position of explosion? we better do nothing, since we can't calculate an impulse direction
{
impulse = Vector3.Zero;
return;
}
if (System.Math.Abs(entityPosition - x) < waveFrontExpansion)
{
// wavefront propagates omnidirectional with a maximum at its current position (x) and an exponential decay to both directions
Vector3 direction = delta * (1.0f / entityPosition); // normalize
float scalarImpulse = (currentMaxImpulse * (float)System.Math.Exp(-System.Math.Abs(entityPosition - x) * oneOverWaveFrontRange));
impulse = direction * scalarImpulse;
if (angularRatio > 0.0f)
{
Vector3 angularMomentum;
Vector3.Cross(ref up, ref impulse, out angularMomentum); // make rotation perpendicular to direction
e.AngularMomentum += angularMomentum * angularRatio;
}
impulse.Validate();
}
else
impulse = Vector3.Zero;
}
protected override void PreUpdate()
{
base.PreUpdate();
Space space = ((Space)Space);
t += space.TimeStepSettings.TimeStepDuration;
x = t * speed;
currentMaxImpulse = maxImpulse * t;
if (x > range)
space.SpaceObjectBuffer.Remove(this);
else
((BoundingSphereForceFieldShape)Shape).BoundingSphere = new BoundingSphere(position, x + waveFrontExpansion);
}
private float t = 0.0f;
private Vector3 position;
private float speed;
private float range;
private float oneOverWaveFrontRange;
private float waveFrontExpansion;
private float x;
private float maxImpulse;
private float currentMaxImpulse;
private float angularRatio;
private Vector3 up = Vector3.UnitY;
}
IsEntityAffected always returns true. shouldn't it do this only if the given entity is in the affectedEntities IList or how is it meant to be used? may i store a bool in the entities tag and therefor just return false in this method if the tag was set to false instead of giving back a Vector3.Zero in some cases in the CalculateImpulse of the force field? on the other hand, the field shape shouldn't make any special assumptions about the entities and even the force field its serving for...