public Vector2 computeAlignment(NPC member) { Vector2 v = new Vector2(); int neighbourCount = 0; foreach (NPC npc in Members) { if (npc != member) { float distSq = (npc.Position - member.Position).LengthSquared(); if (distSq < flockDist * flockDist) { v += npc.ComponentPhysics.Velocity; ++neighbourCount; } } } if (neighbourCount == 0 || v.LengthSquared() == 0) return v; v /= neighbourCount; v.Normalize(); return v * alignmentWeight; }
/// <summary> /// Calculates current position based on velocity and acceleration /// </summary> /// <param name="time">Time elapsed (in seconds) since the last update of position</param> /// <param name="position">New position</param> public void UpdatePosition(double time, out Vector2 position, NPC flockingEntity = null) { UpdatePosition(time, flockingEntity); position = this.position; }
/// <summary> /// Calculates current position based on velocity and acceleration /// </summary> /// <param name="time">Time elapsed (in seconds) since the last update of position</param> public void UpdatePosition(double time, NPC flockingEntity = null) { // Steering if (isSteering) { updatePositionSteering(time, flockingEntity); } else { updatePositionKinematic(time, flockingEntity); } // Calculates position position += velocity * (float)time; }
/// <summary> /// Position update if kinematic /// </summary> /// <param name="time">Time since last update call</param> private void updatePositionKinematic(double time, NPC flockingEntity = null) { // If stopping if (isStopping) { // Stop velocity = Vector2.Zero; } else { // Move at max speed in direction of the target velocity = movementDirection; velocity *= maxVelocity; } }
/// <summary> /// Position update if steering /// </summary> /// <param name="time">Time since last update call</param> private void updatePositionSteering(double time, NPC flockingEntity = null) { // If stopping if (isStopping) { // Acceleration opposes last movement acceleration = velocity * -friction; // Capped by max acceleration if (acceleration.Length() > maxAcceleration) { if(acceleration.LengthSquared() > 0) acceleration.Normalize(); acceleration *= maxAcceleration; } // Update velocity int signX = Math.Sign(velocity.X), signY = Math.Sign(velocity.Y); velocity += acceleration * (float)time; if (Math.Sign(velocity.X) != signX || Math.Abs(velocity.X) < 25) { velocity.X = 0; } if (Math.Sign(velocity.Y) != signY || Math.Abs(velocity.Y) < 25) { velocity.Y = 0; } if (flockingEntity != null && flockingEntity.flock != null) { float mult = 1; if (maxVelocity == maxVelocityRun) { mult = maxVelocityRun / maxVelocityWalk; } velocity += flockingEntity.flock.computeAlignment(flockingEntity) * mult; velocity += flockingEntity.flock.computeCohesion(flockingEntity) * mult; velocity += flockingEntity.flock.computeSeparation(flockingEntity) * mult; } // Capped by max velocity if (velocity.Length() > maxVelocity) { if(velocity.LengthSquared() > 0) velocity.Normalize(); velocity *= maxVelocity; } } else { // Accelerate fully in the direction of the target acceleration = movementDirection; acceleration *= maxAcceleration; velocity += acceleration * (float)time; if (flockingEntity != null && flockingEntity.flock != null) { float mult = 1; if (maxVelocity == maxVelocityRun) { mult = maxVelocityRun / maxVelocityWalk; } velocity += flockingEntity.flock.computeAlignment(flockingEntity) * mult; velocity += flockingEntity.flock.computeCohesion(flockingEntity) * mult; velocity += flockingEntity.flock.computeSeparation(flockingEntity) * mult; } // Capped by max velocity if (velocity.Length() > maxVelocity) { if (velocity.LengthSquared() > 0) velocity.Normalize(); velocity *= maxVelocity; } } }
/// <summary> /// Sets the position to target /// </summary> /// <param name="targetPosition">Desired position</param> public void SetTarget(Vector2 targetPosition, NPC flockingEnt = null) { this.targetPosition = targetPosition; }