public Vector AvoidCollisions(Vector IntendedVelocity) { //store the target that collides then, and other stuff //that we will need and can avoid recalculating //store the first collision time float ShortestTime = float.NegativeInfinity; Unit FirstTarget = null; float FirstMinSeperation = 0; float FirstDistance = 0; Vector FirstRelativePos = new Vector(); Vector FirstRelativeVel = new Vector(); var UnitsInRange = GetAllUnitsInAvoidanceRange(); float Distance = 0; Vector RelativePos = new Vector(); float CollisionRadiusToAvoid = 0F; foreach (var unit in UnitsInRange) { //calc min coll. range float CollisionRadius = (float)this.Radius + (float)unit.Radius; //Calculate time to collision RelativePos = unit.Location.ToVector().Subtract(this.Location.ToVector()); Distance = RelativePos.Len(); Vector RelativeVel = unit.Velocity.Subtract(this.Velocity); //Vector RelativeVel = unit.Velocity.Subtract(IntendedVelocity); float RelativeSpeed = RelativeVel.Mag(); float TimeToCollision = VectorOps.dot(RelativePos, RelativeVel) / (RelativeSpeed * RelativeSpeed); TimeToCollision = -TimeToCollision; if (TimeToCollision == double.NaN || TimeToCollision > 10 || TimeToCollision < 0) { continue; } if (ShortestTime < TimeToCollision) { ShortestTime = TimeToCollision; } //Check if it is going to be a collision at all //var MyPositionAtCollision = (this.Location.World.ToVector()).Add2(this.Velocity.Mult2(TimeToCollision)); var MyPositionAtCollision = (this.Location.World.ToVector()).Add2(IntendedVelocity.Mult2(TimeToCollision)); var HisPositionAtCollision = (unit.Location.World.ToVector()).Add2(unit.Velocity.Mult2(TimeToCollision)); float MinSeperation = (MyPositionAtCollision.Subtract(HisPositionAtCollision)).Len(); //float MinSeperation = Distance - RelativeSpeed * ShortestTime; if (MinSeperation > CollisionRadius) { continue; //skip to the next iteration } if (TimeToCollision > 0 && TimeToCollision <= ShortestTime) { ShortestTime = TimeToCollision; FirstTarget = unit; FirstMinSeperation = MinSeperation; FirstDistance = Distance; FirstRelativePos = RelativePos; FirstRelativeVel = RelativeVel; CollisionRadiusToAvoid = CollisionRadius; } } if (FirstTarget == null) { return(new Vector()); //if we have no target, exit } //if we're going to hit, or if we're hitting already, then do steering based on current pos if (FirstMinSeperation <= 0 || Distance < CollisionRadiusToAvoid) { RelativePos = FirstTarget.Location.ToVector().Subtract(this.Location.ToVector()); } else { Vector vMultipliedFirstRelativeVel = FirstRelativeVel.Mult2(ShortestTime); RelativePos = FirstRelativePos.Add2(vMultipliedFirstRelativeVel); } RelativePos.Normalize(); RelativePos.Mult(MaxSpeed); RelativePos.Y = -RelativePos.Y; RelativePos.X = -RelativePos.X; //float dot = VectorOps.dot(RelativePos.Normalize2(), Velocity.Normalize2()); //if (dot >= 0.01 || dot <= -0.01) //means our velocity is close to perpendicular to collision line ////if (true) //{ // //todo: consider the special case of midVector2 // //otherwise the target is to my right // RelativePos = this.Location.World.ToVector().Add2(GetNormal(Velocity.ToLine())); //} return(RelativePos); //apply steering }
public void Act() { foreach (var Ability in AbilityList) { Ability.Update(); } if (isObstacleCourse && this.Owner.Up == 2) { return; } //outputs acceleration Acceleration = new Vector(); Attacking = false; var EnemyUnitsInSightRange = GetEnemyUnitsInSightRange(); if (isObstacleCourse || EnemyUnitsInSightRange.Count == 0) { //this.Velocity = this.Owner.DefaultVelocity; this.TargetLocation.World.X = this.Owner.TargetLocation.World.X; this.TargetLocation.World.Y = this.Location.World.Y; //this.TargetLocation.World.Y = float.Epsilon; } else { var closestEnemy = EnemyUnitsInSightRange.OrderBy(a => Distance(a)).Where(a => a.HitPoints > 0).FirstOrDefault(); if (closestEnemy != null) { if (Distance(closestEnemy) <= this.WeaponRange) { CurrentEnemy = closestEnemy; //Acceleration = new Vector(0,0); //S T O P! //Velocity = new Vector(0,0); //we will need to change this later; we do not deal with velocity Attacking = true; } else { TargetLocation.World = closestEnemy.Location.World; } } } //double angle = Math.Atan2(TargetLocation.World.Y - this.Location.World.Y, TargetLocation.World.X - this.Location.World.X); SeekingForce = Seek(TargetLocation.ToVector()); if (!Attacking) { //EvasionForce = Evade(); //AvoidingCollisions = AvoidCollisions(); } else { //EvasionForce = new Vector(0, 0); //AvoidingCollisions = AvoidCollisions(); } SeekingForce = SeekingForce.Normalize2(); SeekingForce = SeekingForce.Mult2(MaxAcceleration); Vector IntendedVelocity = GetIntendedVelocity(SeekingForce); //Vector IntendedVelocity = TargetLocation.World.ToVector(); IntendedVelocity.Normalize(); IntendedVelocity.Mult(MaxSpeed); AvoidingCollisions = AvoidCollisions(IntendedVelocity); AvoidingCollisions = AvoidingCollisions.Normalize2(); AvoidingCollisions = AvoidingCollisions.Mult2(MaxAcceleration); //without evasion Acceleration = SeekingForce; if (AvoidingCollisions.Mag() > 0) { Acceleration = Acceleration.Div2(1F); Acceleration = Acceleration.Add2(AvoidingCollisions); } }