/// <summary> /// this can be used to vary the accuracy of a player's kick. Just call it /// prior to kicking the ball using the ball's position and the ball target as /// parameters. /// /// </summary> /// <param name="BallPos"></param> /// <param name="BallTarget"></param> /// <returns></returns> public static Vector2D AddNoiseToKick(Vector2D BallPos, Vector2D BallTarget) { Random random = new Random(); double displacement = (Pi - Pi * ParameterManager.Instance.PlayerKickingAccuracy) * Utils.Math.RandomClamped(random); Vector2D toTarget = BallTarget - BallPos; Transformations.Vec2DRotateAroundOrigin(toTarget, displacement); return(toTarget + BallPos); }
/// <summary> /// given a line segment AB and a circle position and radius, this function /// determines if there is an intersection and stores the position of the /// closest intersection in the reference IntersectionPoint /// /// returns false if no intersection point is found /// </summary> /// <param name="A"></param> /// <param name="B"></param> /// <param name="pos"></param> /// <param name="radius"></param> /// <param name="IntersectionPoint"></param> /// <returns></returns> public static bool GetLineSegmentCircleClosestIntersectionPoint(Vector2D A, Vector2D B, Vector2D pos, double radius, ref Vector2D IntersectionPoint) { Vector2D toBNorm = Vector2D.Vec2DNormalize(B - A); //move the circle into the local space defined by the vector B-A with origin //at A Vector2D LocalPos = Transformations.PointToLocalSpace(pos, toBNorm, toBNorm.Perp, A); bool ipFound = false; //if the local position + the radius is negative then the circle lays behind //point A so there is no intersection possible. If the local x pos minus the //radius is greater than length A-B then the circle cannot intersect the //line segment if ((LocalPos.X + radius >= 0) && ((LocalPos.X - radius) * (LocalPos.X - radius) <= Vector2D.Vec2DDistanceSq(B, A))) { //if the distance from the x axis to the object's position is less //than its radius then there is a potential intersection. if (Math.Sqrt(LocalPos.Y) < radius) { //now to do a line/circle intersection test. The center of the //circle is represented by A, B. The intersection points are //given by the formulae x = A +/-sqrt(r^2-B^2), y=0. We only //need to look at the smallest positive value of x. double a = LocalPos.X; double b = LocalPos.Y; double ip = a - Math.Sqrt(radius * radius - b * b); if (ip <= 0) { ip = a + Math.Sqrt(radius * radius - b * b); } ipFound = true; IntersectionPoint = A + toBNorm * ip; } } return(ipFound); }
public override void Execute(FieldPlayer player) { double dot = player.Team.HomeGoal.FacingDirection.GetDotProduct(player.Heading); //if the ball is between the player and the home goal, it needs to swivel // the ball around by doing multiple small kicks and turns until the player //is facing in the correct direction if (dot < 0) { //the player's heading is going to be rotated by a small amount (Pi/4) //and then the ball will be kicked in that direction Vector2D direction = player.Heading; //calculate the sign (+/-) of the angle between the player heading and the //facing direction of the goal so that the player rotates around in the //correct direction double angle = Utils.Math.Constants.QuarterPi * -1 * player.Team.HomeGoal.FacingDirection.Sign(player.Heading); Transformations.Vec2DRotateAroundOrigin(direction, angle); //this value works well whjen the player is attempting to control the //ball and turn at the same time const double KickingForce = 0.8; player.Ball.Kick(direction, KickingForce); } //kick the ball down the field else { player.Ball.Kick(player.Team.HomeGoal.FacingDirection, ParameterManager.Instance.MaxDribbleForce); } //the player has kicked the ball so he must now change state to follow it player.StateMachine.ChangeState(ChaseBallState.Instance); return; }
//--------------------------- Render ------------------------------------- // //------------------------------------------------------------------------ public override void Render(Graphics g) { //set appropriate team color GDI.CurrentPen = (Team.Color == SoccerTeam.SoccerTeamColor.Blue) ? Pens.Blue : Pens.Red; // draw the body, translated to it's local coordinate space List <Vector2D> vectors = Transformations.WorldTransform(_vecPlayerVB, Position, Heading, Side, Scale); GDI.DrawPolygon(g, vectors); // draw his head GDI.CurrentBrush = new SolidBrush(Color.FromArgb(133, 90, 0)); if (ParameterManager.Instance.ShowHighlightIfThreatened && (Team.ControllingPlayer == this) && IsThreatened()) { GDI.CurrentBrush = Brushes.Yellow; } GDI.DrawCircle(g, Position, 6.0f); //render the state if (ParameterManager.Instance.ShowStates) { Brush stateBrush = new SolidBrush(Color.FromArgb(0, 170, 0)); g.DrawString(_stateMachine.CurrentState.ToString(), GDI.TextFont, stateBrush, new PointF((float)Position.X, (float)Position.Y - GDI.TextFont.Height)); } //show IDs if (ParameterManager.Instance.ShowIDs) { g.DrawString(ObjectId.ToString(), GDI.TextFont, textBrush, new PointF((float)Position.X - 20.0f, (float)Position.Y - GDI.TextFont.Height)); } if (ParameterManager.Instance.ShowViewTargets) { g.FillEllipse(textBrush, new RectangleF((float)SteeringBehaviors.Target.X, (float)SteeringBehaviors.Target.Y, 3.0f, 3.0f)); g.DrawString(ObjectId.ToString(), GDI.TextFont, Brushes.Red, new PointF((float)SteeringBehaviors.Target.X, (float)SteeringBehaviors.Target.Y)); } }
/// <summary> /// test if a pass from 'from' to 'to' can be intercepted by an opposing player /// /// </summary> /// <param name="from"></param> /// <param name="target"></param> /// <param name="receiver"></param> /// <param name="opp"></param> /// <param name="PassingForce"></param> /// <returns></returns> public bool IsPassSafeFromOpponent(Vector2D from, Vector2D target, PlayerBase receiver, PlayerBase opp, double PassingForce) { //move the opponent into local space. Vector2D ToTarget = target - from; Vector2D ToTargetNormalized = Vector2D.Vec2DNormalize(ToTarget); Vector2D LocalPosOpp = Transformations.PointToLocalSpace(opp.Position, ToTargetNormalized, ToTargetNormalized.Perp, from); //if opponent is behind the kicker then pass is considered okay(this is //based on the assumption that the ball is going to be kicked with a //velocity greater than the opponent's max velocity) if (LocalPosOpp.X < 0) { return(true); } //if the opponent is further away than the target we need to consider if //the opponent can reach the position before the receiver. if (Vector2D.Vec2DDistanceSq(from, target) < Vector2D.Vec2DDistanceSq(opp.Position, from)) { if (receiver != null) { if (Vector2D.Vec2DDistanceSq(target, opp.Position) > Vector2D.Vec2DDistanceSq(target, receiver.Position)) { return(true); } else { return(false); } } else { return(true); } } //calculate how long it takes the ball to cover the distance to the //position orthogonal to the opponents position double TimeForBall = Pitch.Ball.CalucateTimeToCoverDistance(new Vector2D(0, 0), new Vector2D(LocalPosOpp.X, 0), PassingForce); //now calculate how far the opponent can run in this time double reach = opp.MaxSpeed * TimeForBall + Pitch.Ball.BoundingRadius + opp.BoundingRadius; //if the distance to the opponent's y position is less than his running //range plus the radius of the ball and the opponents radius then the //ball can be intercepted if (Math.Abs(LocalPosOpp.Y) < reach) { return(false); } return(true); }
public override void Update() { //run the logic for the current state _stateMachine.Update(); //calculate the combined steering force _steeringBehaviors.CalculateSteeringForce(); //if no steering force is produced decelerate the player by applying a //braking force if (_steeringBehaviors.SteeringForce.IsZero) { double brakingRate = 0.8; Velocity = Velocity * brakingRate; } //the steering force's side component is a force that rotates the //player about its axis. We must limit the rotation so that a player //can only turn by PlayerMaxTurnRate rads per update. double TurningForce = _steeringBehaviors.SideComponent; if (TurningForce < -ParameterManager.Instance.PlayerMaxTurnRate) { TurningForce = -ParameterManager.Instance.PlayerMaxTurnRate; } if (TurningForce > ParameterManager.Instance.PlayerMaxTurnRate) { TurningForce = ParameterManager.Instance.PlayerMaxTurnRate; } //rotate the heading vector Transformations.Vec2DRotateAroundOrigin(Heading, TurningForce); //make sure the velocity vector points in the same direction as //the heading vector Velocity = Heading * Velocity.Length; //and recreate m_vSide Side = Heading.Perp; //now to calculate the acceleration due to the force exerted by //the forward component of the steering force in the direction //of the player's heading Vector2D accel = Heading * _steeringBehaviors.ForwardComponent / Mass; Velocity += accel; //make sure player does not exceed maximum velocity Velocity.Truncate(MaxSpeed); //update the position Position += Velocity; //enforce a non-penetration constraint if desired if (ParameterManager.Instance.NonPenetrationConstraint) { EntityManager.EnforceNonPenetrationContraint(this, AutoList <PlayerBase> .GetAllMembers()); } }