public MovingEntity(Vector2D position, double radius, Vector2D velocity, double max_speed, Vector2D heading, double mass, Vector2D scale, double turn_rate, double max_force) : base(0, position, radius) { m_vHeading = heading; m_vVelocity = velocity; m_dMass = mass; m_vSide = m_vHeading.Perp(); m_dMaxSpeed = max_speed; m_dMaxTurnRate = turn_rate; m_dMaxForce = max_force; m_vScale = scale; m_OldPos = new Vector2D(); m_vSmoothedHeading = new Vector2D(); m_intOldCellID = -1; m_pSteering = new SteeringBehavior(this); m_HeadingHistory = new List<Vector2D>(SteerParams.Instance.NumSamplesForSmoothing); m_intNextHeadingSlot = 0; }
public void CreateRandomPath(int NumWaypoints, double MinX, double MinY, double MaxX, double MaxY) { m_WayPoints.Clear(); double midX = (MaxX+MinX)/2.0; double midY = (MaxY+MinY)/2.0; double smaller = Math.Min(midX, midY); double spacing = Utils.TwoPi / (double)NumWaypoints; for (int i=0; i<NumWaypoints; ++i) { double RadialDist = Utils.RandInRange(smaller*0.2f, smaller); Vector2D temp = new Vector2D(RadialDist, 0.0f); Utils.Vec2DRotateAroundOrigin(temp, i * spacing); temp.X += midX; temp.Y += midY; m_WayPoints.Add(temp); } m_curWaypoint = m_WayPoints.GetEnumerator(); m_curWaypoint.MoveNext(); // set the first item ready to go }
public Wall2D(Vector2D A, Vector2D B) { m_vA = A; m_vB = B; m_vN = new Vector2D(); CalculateNormal(); }
public InvertedAABBox2D(Vector2D topLeft, Vector2D bottomRight) { m_vTopLeft = topLeft; m_vBottomRight = bottomRight; m_vCenter = (topLeft + bottomRight) * 0.5; m_Rectangle = new Rectangle((int)m_vTopLeft.X, (int)m_vTopLeft.Y, (int)(m_vBottomRight.X - m_vTopLeft.X), (int)(m_vBottomRight.Y - m_vTopLeft.Y)); }
public BaseGameEntity() { m_ID = NextValidID(); m_dBoundingRadius=0.0; m_vPos = new Vector2D(); m_vScale = new Vector2D(1.0,1.0); m_EntityType = default_entity_type; m_bTag = false; }
//this can be used to create an entity with a 'forced' ID. It can be used //when a previously created entity has been removed and deleted from the //game for some reason. For example, The Raven map editor uses this ctor //in its undo/redo operations. //USE WITH CAUTION! public BaseGameEntity(int entity_type, int ForcedID) { m_ID = ForcedID; m_dBoundingRadius = 0.0; m_vPos = new Vector2D(); m_vScale = new Vector2D(1.0, 1.0); m_EntityType = entity_type; m_bTag = false; }
public BaseGameEntity(int entity_type, Vector2D pos, double r) { m_ID = NextValidID(); m_dBoundingRadius = r; m_vPos = pos; m_vScale = new Vector2D(1.0, 1.0); m_EntityType = entity_type; m_bTag = false; }
//given a position in the game space this method determines the relevant cell's index private int PositionToIndex(Vector2D pos) { int idx = (int)(m_iNumCellsX * pos.X / m_dSpaceWidth) + ((int)((m_iNumCellsY) * pos.Y / m_dSpaceHeight) * m_iNumCellsX); //if the entity's position is equal to vector2d(m_dSpaceWidth, m_dSpaceHeight) //then the index will overshoot. We need to check for this and adjust if (idx > m_Cells.Count - 1) idx = m_Cells.Count - 1; return idx; }
private GameWorld() { m_bPaused = false; m_bWrap = false; m_blnSmoothing = true; m_bCellSpaceOn = false; m_dTimeElapsed = 0.0; m_Walls = null; m_pCellSpace = null; m_Obstacles = null; m_Agents = null; m_cxClient = 0; m_cyClient = 0; m_vTargetPos = new Vector2D(); }
//applies a 2D transformation matrix to a single Vector2D public void TransformVector2D(Vector2D vPoint) { double tempX = (m_Matrix._11 * vPoint.X) + (m_Matrix._21 * vPoint.Y) + (m_Matrix._31); double tempY = (m_Matrix._12 * vPoint.X) + (m_Matrix._22 * vPoint.Y) + (m_Matrix._32); vPoint.X = tempX; vPoint.Y = tempY; }
//--------------------------- Wander ------------------------------------- // // This behavior makes the agent wander about randomly //------------------------------------------------------------------------ public Vector2D Wander() { //this behavior is dependent on the update rate, so this line must //be included when using time independent framerate. double JitterThisTimeSlice = m_dWanderJitter * GameWorld.Instance.getTimeElapsed(); //first, add a small random vector to the target's position m_vWanderTarget += new Vector2D(Utils.RandomClamped() * JitterThisTimeSlice, Utils.RandomClamped() * JitterThisTimeSlice); //reproject this new vector back on to a unit circle m_vWanderTarget.Normalize(); //increase the length of the vector to the same as the radius //of the wander circle m_vWanderTarget *= m_dWanderRadius; //move the target into a position WanderDist in front of the agent Vector2D target = (m_vWanderTarget + new Vector2D(m_dWanderDistance, 0)); //project the target into world space Vector2D Target = (Utils.PointToWorldSpace(target, m_parentMovingEntity.Heading(), m_parentMovingEntity.Side(), m_parentMovingEntity.Pos)); //and steer towards it return Target - m_parentMovingEntity.Pos; }
//----------------------------- Flee ------------------------------------- // // Does the opposite of Seek //------------------------------------------------------------------------ public Vector2D Flee(Vector2D TargetPos) { //only flee if the target is within 'panic distance'. Work in distance //squared space. /* double PanicDistanceSq = 100.0f * 100.0; if (Vec2DDistanceSq(m_parentMovingEntity.Pos, target) > PanicDistanceSq) { return Vector2D(0,0); } */ Vector2D DesiredVelocity = Vector2D.Vec2DNormalize(m_parentMovingEntity.Pos - TargetPos) * m_parentMovingEntity.MaxSpeed; return (DesiredVelocity - m_parentMovingEntity.Velocity); }
//---------------------- CalculateDithered ---------------------------- // // this method sums up the active behaviors by assigning a probabilty // of being calculated to each behavior. It then tests the first priority // to see if it should be calcukated this simulation-step. If so, it // calculates the steering force resulting from this behavior. If it is // more than zero it returns the force. If zero, or if the behavior is // skipped it continues onto the next priority, and so on. // // NOTE: Not all of the behaviors have been implemented in this method, // just a few, so you get the general idea //------------------------------------------------------------------------ public Vector2D CalculateDithered() { //reset the steering force m_vSteeringForce.Zero(); if (On(behavior_type.wall_avoidance) && Utils.RandFloat() < SteerParams.Instance.PrWallAvoidance) { m_vSteeringForce = WallAvoidance(GameWorld.Instance.Walls) * m_dWeightWallAvoidance / SteerParams.Instance.PrWallAvoidance; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } if (On(behavior_type.obstacle_avoidance) && Utils.RandFloat() < SteerParams.Instance.PrObstacleAvoidance) { m_vSteeringForce += ObstacleAvoidance(GameWorld.Instance.Obstacles) * m_dWeightObstacleAvoidance / SteerParams.Instance.PrObstacleAvoidance; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } if (!GameWorld.Instance.SpacePartitioningOn) { if (On(behavior_type.separation) && Utils.RandFloat() < SteerParams.Instance.PrSeparation) { m_vSteeringForce += Separation(GameWorld.Instance.Agents) * m_dWeightSeparation / SteerParams.Instance.PrSeparation; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } } else { if (On(behavior_type.separation) && Utils.RandFloat() < SteerParams.Instance.PrSeparation) { m_vSteeringForce += SeparationPlus(GameWorld.Instance.Agents) * m_dWeightSeparation / SteerParams.Instance.PrSeparation; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } } if (On(behavior_type.flee) && Utils.RandFloat() < SteerParams.Instance.PrFlee) { Debug.Assert(!Vector2D.IsNull(GameWorld.Instance.TargetPos), "TargetPos not assigned"); m_vSteeringForce += Flee(GameWorld.Instance.TargetPos) * m_dWeightFlee / SteerParams.Instance.PrFlee; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } if (On(behavior_type.evade) && Utils.RandFloat() < SteerParams.Instance.PrEvade) { Debug.Assert(m_pTargetAgent1 != null, "Evade target not assigned"); m_vSteeringForce += Evade(m_pTargetAgent1) * m_dWeightEvade / SteerParams.Instance.PrEvade; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } if (!GameWorld.Instance.SpacePartitioningOn) { if (On(behavior_type.allignment) && Utils.RandFloat() < SteerParams.Instance.PrAlignment) { m_vSteeringForce += Alignment(GameWorld.Instance.Agents) * m_dWeightAlignment / SteerParams.Instance.PrAlignment; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } if (On(behavior_type.cohesion) && Utils.RandFloat() < SteerParams.Instance.PrCohesion) { m_vSteeringForce += Cohesion(GameWorld.Instance.Agents) * m_dWeightCohesion / SteerParams.Instance.PrCohesion; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } } else { if (On(behavior_type.allignment) && Utils.RandFloat() < SteerParams.Instance.PrAlignment) { m_vSteeringForce += AlignmentPlus(GameWorld.Instance.Agents) * m_dWeightAlignment / SteerParams.Instance.PrAlignment; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } if (On(behavior_type.cohesion) && Utils.RandFloat() < SteerParams.Instance.PrCohesion) { m_vSteeringForce += CohesionPlus(GameWorld.Instance.Agents) * m_dWeightCohesion / SteerParams.Instance.PrCohesion; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } } if (On(behavior_type.wander) && Utils.RandFloat() < SteerParams.Instance.PrWander) { m_vSteeringForce += Wander() * m_dWeightWander / SteerParams.Instance.PrWander; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } if (On(behavior_type.seek) && Utils.RandFloat() < SteerParams.Instance.PrSeek) { Debug.Assert(!Vector2D.IsNull(GameWorld.Instance.TargetPos), "TargetPos not assigned"); m_vSteeringForce += Seek(GameWorld.Instance.TargetPos) * m_dWeightSeek / SteerParams.Instance.PrSeek; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } if (On(behavior_type.arrive) && Utils.RandFloat() < SteerParams.Instance.PrArrive) { Debug.Assert(!Vector2D.IsNull(GameWorld.Instance.TargetPos), "TargetPos not assigned"); m_vSteeringForce += Arrive(GameWorld.Instance.TargetPos, (int)m_Deceleration) * m_dWeightArrive / SteerParams.Instance.PrArrive; if (!m_vSteeringForce.isZero()) { m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; } } return m_vSteeringForce; }
//--------------------- AccumulateForce ---------------------------------- // // This function calculates how much of its max steering force the // vehicle has left to apply and then applies that amount of the // force to add. //------------------------------------------------------------------------ public bool AccumulateForce(ref Vector2D RunningTot, Vector2D ForceToAdd) { //calculate how much steering force the vehicle has used so far double MagnitudeSoFar = RunningTot.Length(); //calculate how much steering force remains to be used by this vehicle double MagnitudeRemaining = m_parentMovingEntity.MaxForce - MagnitudeSoFar; //return false if there is no more force left to use if (MagnitudeRemaining <= 0.0) return false; //calculate the magnitude of the force we want to add double MagnitudeToAdd = ForceToAdd.Length(); //if the magnitude of the sum of ForceToAdd and the running total //does not exceed the maximum force available to this vehicle, just //add together. Otherwise add as much of the ForceToAdd vector is //possible without going over the max. if (MagnitudeToAdd < MagnitudeRemaining) { RunningTot += ForceToAdd; } else { //add it to the steering force RunningTot += (Vector2D.Vec2DNormalize(ForceToAdd) * MagnitudeRemaining); } return true; }
//-------------------------------- Cohesion ------------------------------ // // returns a steering force that attempts to move the agent towards the // center of mass of the agents in its immediate area //------------------------------------------------------------------------ public Vector2D Cohesion(List<MovingEntity> neighbors) { //first find the center of mass of all the agents Vector2D CenterOfMass = new Vector2D(0.0, 0.0); Vector2D SteeringForce = new Vector2D(0.0, 0.0); int NeighborCount = 0; //iterate through the neighbors and sum up all the position vectors foreach (MovingEntity neighbor in neighbors) { //make sure *this* agent isn't included in the calculations and that //the agent being examined is close enough ***also make sure it doesn't //include the evade target *** if ((neighbor != m_parentMovingEntity) && neighbor.IsTagged() && (neighbor != m_pTargetAgent1)) { CenterOfMass += neighbor.Pos; ++NeighborCount; } } if (NeighborCount > 0) { //the center of mass is the average of the sum of positions CenterOfMass /= (double)NeighborCount; //now seek towards that position SteeringForce = Seek(CenterOfMass); } //the magnitude of cohesion is usually much larger than separation or //allignment so it usually helps to normalize it. return Vector2D.Vec2DNormalize(SteeringForce); }
public void OffsetPursuitOn(MovingEntity v1, Vector2D offset) { m_iFlags |= (int)behavior_type.offset_pursuit; m_vOffset = offset; m_pTargetAgent1 = v1; }
//----------------------- Calculate -------------------------------------- // // calculates the accumulated steering force according to the method set // in m_SummingMethod //------------------------------------------------------------------------ public Vector2D Calculate() { //reset the steering force m_vSteeringForce.Zero(); //use space partitioning to calculate the neighbours of this vehicle //if switched on. If not, use the standard tagging system if (!GameWorld.Instance.SpacePartitioningOn) { //tag neighbors if any of the following 3 group behaviors are switched on if (On(behavior_type.separation) || On(behavior_type.allignment) || On(behavior_type.cohesion)) { GameWorld.Instance.TagAgentsWithinViewRange(m_parentMovingEntity, m_dViewDistance); } } else { //calculate neighbours in cell-space if any of the following 3 group //behaviors are switched on if (On(behavior_type.separation) || On(behavior_type.allignment) || On(behavior_type.cohesion)) { GameWorld.Instance.CellSpaces.CalculateNeighbors(m_parentMovingEntity.Pos, m_dViewDistance); } } switch (m_SummingMethod) { case summing_method.weighted_average: m_vSteeringForce = CalculateWeightedSum(); break; case summing_method.prioritized: m_vSteeringForce = CalculatePrioritized(); break; case summing_method.dithered: m_vSteeringForce = CalculateDithered(); break; default: m_vSteeringForce = new Vector2D(0, 0); break; }//end switch return m_vSteeringForce; }
/* NOTE: the next three behaviors are the same as the above three, except that they use a cell-space partition to find the neighbors */ //---------------------------- Separation -------------------------------- // // this calculates a force repelling from the other neighbors // // USES SPACIAL PARTITIONING //------------------------------------------------------------------------ public Vector2D SeparationPlus(List<MovingEntity> neighbors) { Vector2D SteeringForce = new Vector2D(0.0, 0.0); //iterate through the neighbors and sum up all the position vectors foreach (MovingEntity pV in GameWorld.Instance.CellSpaces.ListOfNeighbours()) { //make sure this agent isn't included in the calculations and that //the agent being examined is close enough if (pV != m_parentMovingEntity) { Vector2D ToAgent = (m_parentMovingEntity.Pos - pV.Pos); //scale the force inversely proportional to the agents distance //from its neighbor. SteeringForce += Vector2D.Vec2DNormalize(ToAgent) / ToAgent.Length(); } } return SteeringForce; }
//---------------------- CalculateWeightedSum ---------------------------- // // this simply sums up all the active behaviors X their weights and // truncates the result to the max available steering force before // returning //------------------------------------------------------------------------ public Vector2D CalculateWeightedSum() { if (On(behavior_type.wall_avoidance)) { m_vSteeringForce += WallAvoidance(GameWorld.Instance.Walls) * m_dWeightWallAvoidance; } if (On(behavior_type.obstacle_avoidance)) { m_vSteeringForce += ObstacleAvoidance(GameWorld.Instance.Obstacles) * m_dWeightObstacleAvoidance; } if (On(behavior_type.evade)) { Debug.Assert(m_pTargetAgent1 != null, "Evade target not assigned"); m_vSteeringForce += Evade(m_pTargetAgent1) * m_dWeightEvade; } //these next three can be combined for flocking behavior (wander is //also a good behavior to add into this mix) if (!GameWorld.Instance.SpacePartitioningOn) { if (On(behavior_type.separation)) { m_vSteeringForce += Separation(GameWorld.Instance.Agents) * m_dWeightSeparation; } if (On(behavior_type.allignment)) { m_vSteeringForce += Alignment(GameWorld.Instance.Agents) * m_dWeightAlignment; } if (On(behavior_type.cohesion)) { m_vSteeringForce += Cohesion(GameWorld.Instance.Agents) * m_dWeightCohesion; } } else { if (On(behavior_type.separation)) { m_vSteeringForce += SeparationPlus(GameWorld.Instance.Agents) * m_dWeightSeparation; } if (On(behavior_type.allignment)) { m_vSteeringForce += AlignmentPlus(GameWorld.Instance.Agents) * m_dWeightAlignment; } if (On(behavior_type.cohesion)) { m_vSteeringForce += CohesionPlus(GameWorld.Instance.Agents) * m_dWeightCohesion; } } if (On(behavior_type.wander)) { m_vSteeringForce += Wander() * m_dWeightWander; } if (On(behavior_type.seek)) { Debug.Assert(!Vector2D.IsNull(GameWorld.Instance.TargetPos), "TargetPos not assigned"); m_vSteeringForce += Seek(GameWorld.Instance.TargetPos) * m_dWeightSeek; } if (On(behavior_type.flee)) { Debug.Assert(!Vector2D.IsNull(GameWorld.Instance.TargetPos), "TargetPos not assigned"); m_vSteeringForce += Flee(GameWorld.Instance.TargetPos) * m_dWeightFlee; } if (On(behavior_type.arrive)) { Debug.Assert(!Vector2D.IsNull(GameWorld.Instance.TargetPos), "TargetPos not assigned"); m_vSteeringForce += Arrive(GameWorld.Instance.TargetPos, (int)m_Deceleration) * m_dWeightArrive; } if (On(behavior_type.pursuit)) { Debug.Assert(m_pTargetAgent1 != null, "pursuit target not assigned"); m_vSteeringForce += Pursuit(m_pTargetAgent1) * m_dWeightPursuit; } if (On(behavior_type.offset_pursuit)) { Debug.Assert(m_pTargetAgent1 != null, "pursuit target not assigned"); Debug.Assert(!Vector2D.IsNull(m_vOffset), "No offset assigned"); m_vSteeringForce += OffsetPursuit(m_pTargetAgent1, m_vOffset) * m_dWeightOffsetPursuit; } if (On(behavior_type.interpose)) { Debug.Assert(m_pTargetAgent1 != null && m_pTargetAgent2 != null, "Interpose agents not assigned"); m_vSteeringForce += Interpose(m_pTargetAgent1, m_pTargetAgent2) * m_dWeightInterpose; } if (On(behavior_type.hide)) { Debug.Assert(m_pTargetAgent1 != null, "Hide target not assigned"); m_vSteeringForce += Hide(m_pTargetAgent1, GameWorld.Instance.Obstacles) * m_dWeightHide; } if (On(behavior_type.follow_path)) { m_vSteeringForce += FollowPath() * m_dWeightFollowPath; } m_vSteeringForce.Truncate(m_parentMovingEntity.MaxForce); return m_vSteeringForce; }
//---------------------------- Alignment --------------------------------- // // returns a force that attempts to align this agents heading with that // of its neighbors // // USES SPACIAL PARTITIONING //------------------------------------------------------------------------ public Vector2D AlignmentPlus(List<MovingEntity> neighbors) { //This will record the average heading of the neighbors Vector2D AverageHeading = new Vector2D(); //This count the number of vehicles in the neighborhood double NeighborCount = 0.0; //iterate through the neighbors and sum up all the position vectors foreach (MovingEntity pV in GameWorld.Instance.CellSpaces.ListOfNeighbours()) { //make sure *this* agent isn't included in the calculations and that //the agent being examined is close enough if (pV != m_parentMovingEntity) { AverageHeading += pV.Heading(); ++NeighborCount; } } //if the neighborhood contained one or more vehicles, average their //heading vectors. if (NeighborCount > 0.0) { AverageHeading /= NeighborCount; AverageHeading -= m_parentMovingEntity.Heading(); } return AverageHeading; }
/////////////////////////////////////////////////////////////////////////////// START OF BEHAVIORS //------------------------------- Seek ----------------------------------- // // Given a target, this behavior returns a steering force which will // direct the agent towards the target //------------------------------------------------------------------------ public Vector2D Seek(Vector2D TargetPos) { Vector2D DesiredVelocity = Vector2D.Vec2DNormalize(TargetPos - m_parentMovingEntity.Pos) * m_parentMovingEntity.MaxSpeed; return (DesiredVelocity - m_parentMovingEntity.Velocity); }
//-------------------------------- Cohesion ------------------------------ // // returns a steering force that attempts to move the agent towards the // center of mass of the agents in its immediate area // // USES SPACIAL PARTITIONING //------------------------------------------------------------------------ public Vector2D CohesionPlus(List<MovingEntity> neighbors) { //first find the center of mass of all the agents Vector2D CenterOfMass = new Vector2D(); Vector2D SteeringForce = new Vector2D(); int NeighborCount = 0; //iterate through the neighbors and sum up all the position vectors foreach (MovingEntity pV in GameWorld.Instance.CellSpaces.ListOfNeighbours()) { //make sure *this* agent isn't included in the calculations and that //the agent being examined is close enough if (pV != m_parentMovingEntity) { CenterOfMass += pV.Pos; ++NeighborCount; } } if (NeighborCount > 0) { //the center of mass is the average of the sum of positions CenterOfMass /= (double)NeighborCount; //now seek towards that position SteeringForce = Seek(CenterOfMass); } //the magnitude of cohesion is usually much larger than separation or //allignment so it usually helps to normalize it. return Vector2D.Vec2DNormalize(SteeringForce); }
//--------------------------- Arrive ------------------------------------- // // This behavior is similar to seek but it attempts to arrive at the // target with a zero velocity //------------------------------------------------------------------------ public Vector2D Arrive(Vector2D TargetPos, int decelerationStep) { Vector2D ToTarget = TargetPos - m_parentMovingEntity.Pos; //calculate the distance to the target double dist = ToTarget.Length(); if (dist > 0) { //because Deceleration is enumerated as an int, this value is required //to provide fine tweaking of the deceleration.. double DecelerationTweaker = 0.3; //calculate the speed required to reach the target given the desired //deceleration double speed = dist / ((double)decelerationStep * DecelerationTweaker); //make sure the velocity does not exceed the max speed = Math.Min(speed, m_parentMovingEntity.MaxSpeed); //from here proceed just like Seek except we don't need to normalize //the ToTarget vector because we have already gone to the trouble //of calculating its length: dist. Vector2D DesiredVelocity = (ToTarget * speed / dist); return (DesiredVelocity - m_parentMovingEntity.Velocity); } return new Vector2D(0, 0); }
//--------------------------- Hide --------------------------------------- // //------------------------------------------------------------------------ public Vector2D Hide(MovingEntity hunter, List<BaseGameEntity> obstacles) { double DistToClosest = Double.MaxValue; Vector2D BestHidingSpot = new Vector2D(0.0, 0.0); foreach (BaseGameEntity curOb in obstacles) { //calculate the position of the hiding spot for this obstacle Vector2D HidingSpot = GetHidingPosition(curOb.Pos, curOb.BRadius, hunter.Pos); //work in distance-squared space to find the closest hiding //spot to the agent double dist = Vector2D.Vec2DDistanceSq(HidingSpot, m_parentMovingEntity.Pos); if (dist < DistToClosest) { DistToClosest = dist; BestHidingSpot = HidingSpot; } }//end while //if no suitable obstacles found then Evade the hunter if (DistToClosest == Double.MaxValue) { return Evade(hunter); } //else use Arrive on the hiding spot return Arrive(BestHidingSpot, (int)Deceleration.fast); }
public Wall2D() { m_vN = new Vector2D(); }
//------------------------- GetHidingPosition ---------------------------- // // Given the position of a hunter, and the position and radius of // an obstacle, this method calculates a position DistanceFromBoundary // away from its bounding radius and directly opposite the hunter //------------------------------------------------------------------------ public Vector2D GetHidingPosition(Vector2D posOb, double radiusOb, Vector2D posHunter) { //calculate how far away the agent is to be from the chosen obstacle's //bounding radius double DistanceFromBoundary = 30.0; double DistAway = radiusOb + DistanceFromBoundary; //calculate the heading toward the object from the hunter Vector2D ToOb = Vector2D.Vec2DNormalize(posOb - posHunter); //scale it to size and add to the obstacles position to get //the hiding spot. return (ToOb * DistAway) + posOb; }
public Wall2D(Vector2D A, Vector2D B, Vector2D N) { m_vA = A; m_vB = B; m_vN = N; }
//------------------------- Offset Pursuit ------------------------------- // // Produces a steering force that keeps a vehicle at a specified offset // from a leader vehicle //------------------------------------------------------------------------ public Vector2D OffsetPursuit(MovingEntity leader, Vector2D offset) { //calculate the offset's position in world space Vector2D WorldOffsetPos = Utils.PointToWorldSpace(offset, leader.Heading(), leader.Side(), leader.Pos); Vector2D ToOffset = WorldOffsetPos - m_parentMovingEntity.Pos; //the lookahead time is propotional to the distance between the leader //and the pursuer; and is inversely proportional to the sum of both //agent's velocities double LookAheadTime = ToOffset.Length() / (m_parentMovingEntity.MaxSpeed + leader.Speed()); //now Arrive at the predicted future position of the offset return Arrive(WorldOffsetPos + leader.Velocity * LookAheadTime, (int)Deceleration.fast); }
//create a rotation matrix from a 2D vector public void Rotate(Vector2D fwd, Vector2D side) { Matrix mat = new Matrix(); mat._11 = fwd.X; mat._12 = fwd.Y; mat._13 = 0; mat._21 = side.X; mat._22 = side.Y; mat._23 = 0; mat._31 = 0; mat._32 = 0; mat._33 = 1; //and multiply MatrixMultiply(mat); }
public void SetOffset(Vector2D offset) { m_vOffset = offset; }