A 2-dimensional point mass approximation.
상속: IPointMass
예제 #1
0
 private static bool isOutsideOfField(PointMass player, RectangleF field)
 {
     if (player.Position.Y > field.Top && player.Position.Y < field.Bottom && player.Position.X > field.Left && player.Position.X < field.Right)
         return false;
     else
         return true;
 }
예제 #2
0
        /// <summary>
        ///     Move toward a target's future position. This method assumes the player will move at their maximum speed.  It also
        ///     ignores friction on the target.
        /// </summary>
        /// <param name="player"></param>
        /// <param name="target"></param>
        /// <returns></returns>
        public static Vector2 Pursue(PointMass player, PointMass target)
        {
            // Calculate the time till intersection.
            // We want to move the perpendicular distance between the player and the target in the same amount of time to move the parallel distance to the estimated intersection point.
            // Formulas:
            //     t = perpDist / Vy
            //     Vx * t = initialParallelDist + Ball.ParallelVelocity * t         (ignores friction)
            //       => Vx * perpDist / Vy = initialParallelDist + Ball.ParallelVelocity * perpDist / Vy
            //       => Vx * perpDist = initialParallelDist * Vy + Ball.ParallelVelocity * perpDist
            //       => Vx = initialParallelDist * Vy / perpDist + Ball.ParallelVelocity
            //     player.MaxSpeed ^2 = Vx^2 + Vy^2
            //       => player.MaxSpeed ^2 = (initialParallelDist * Vy / perpDist + Ball.ParallelVelocity)^2 + Vy^2
            //       => lolno (keep these equations for future reference)

            //     We can solve for Vy/Vx together, this is equal to tan(theta)
            //     The above boils down to:
            //     (1/Ball.ParallelVelocity)^2  = (initialParallelDist/(perpDist*Ball.ParallelVelocity))^2 * t^2 - 2*initialParallelDist/(perpDist * Ball.ParallelVelocity^2) = 1/maxSpeed^2 + t^2/maxSpeed^2
            //              NOTE t is not time, it is Vy/Vx
            //        Just solve this for t
            //          https://www.wolframalpha.com/input/?i=t%5E2(d%5E2%2F(y%5E2*b%5E2)+-+1%2Fm%5E2)+-+2*d*t%2F(y*b%5E2)+%2B+1%2Fb%5E2+-+1%2Fm%5E2+%3D+0+solve+for+t

            //      => t = (sqrt(b^2 y^2 (y^2 (m^2-b^2)+d^2 m^2))+d m^2 y)/(d^2 m^2-b^2 y^2) if d^2 m^2!=b^2 y^2
            //      => t = (sqrt(b^2 y^2 (y^2 (m^2-b^2)+d^2 m^2))-d m^2 y)/(b^2 y^2-d^2 m^2) if d^2 m^2!=b^2 y^2
            //          NOTE t is not time, it is Vy/Vx
            // The final angle we want to travel towards is:
            // tan-1(t)

            return Vector2.Zero;
        }
예제 #3
0
        public static Simulation Create2V2Simulation()
        {
            const float w = 1000;
            const float h = 500;
            const float goalW = w / 20;
            const float goalH = h / 4;
            const float mass = 1;
            const float radius = 7.5f;
            const float maxForce = 100;
            const float maxSpeed = 100;

            var team1Players = new PointMass[5];
            var team2Players = new PointMass[5];

            for (var j = 0; j < 5; j++)
            {
                team1Players[j] = new PointMass(mass, radius, maxForce, maxSpeed,
                    new Vector2(-w / 4 + w / 2 + (j % 2 != 0 ? 100 : 0), -h / 4 + j * h / 8), Vector2.Zero);
                team2Players[j] = new PointMass(mass, radius, maxForce, maxSpeed,
                    new Vector2(-w / 4 + (j % 2 != 0 ? -100 : 0), -h / 4 + j * h / 8), Vector2.Zero);
                team1Players[j].id = "A" + j;
                team2Players[j].id = "B" + j;
            }

            var pitch = new RectangleF(-w / 2, -h / 2, w, h);
            var team1Goal = new RectangleF(-w / 2 - goalW, -goalH / 2, goalW, goalH);
            var team2Goal = new RectangleF(w / 2, -goalH / 2, goalW, goalH);
            var team1 = new KeepawayTeam(new ReadOnlyCollection<PointMass>(team1Players), team1Goal);
            var team2 = new KeepawayTeam(new ReadOnlyCollection<PointMass>(team2Players), team2Goal);
            var ball = new PointMass(1, 2.5f, 100000, 100, new Vector2(0, 0), Vector2.Zero);

            return new Simulation(new ReadOnlyCollection<Team>(new Team[] { team1, team2 }), ball, pitch, 10);
        }
예제 #4
0
 /// <summary>
 /// </summary>
 /// <param name="player"></param>
 /// <param name="team"></param>
 /// <param name="otherTeam"></param>
 /// <param name="simulation"></param>
 /// <param name="passingLaneWidth"></param>
 /// <returns></returns>
 public static IEnumerable<IPointMass> GetOpenPlayers(
     PointMass player,
     ITeam team,
     ITeam otherTeam,
     ISimulation simulation,
     float passingLaneWidth)
     => from p in team.Players
         where p != player && IsPlayerOpenForPass(player, p, otherTeam.Players, passingLaneWidth)
         select p;
예제 #5
0
        public override Kick Execute(ISimulation simulation)
        {
            var ballChaser = FootballStrategies.ClosestPlayerToPoint(this.Players, simulation.Ball, 0);
            var kick = Kick.None;

            foreach (var player in Players)
            {
                if (player == ballChaser)
                {
                    //messages[player] = "Chaser";

                    var playersExceptSelf = Players.ToList();
                    playersExceptSelf.Remove(player);

                    player.Force = SteeringStrategies.Pursue(player, simulation.Ball, 1);

                    if ((player.Position - simulation.Ball.Position).Length() < player.Radius + simulation.Ball.Radius) {
                        var isLeftTeam = this.GoalBounds.Left > 0 ? true : false;
                        PointMass[] arr = new PointMass[7];
                        playersExceptSelf.CopyTo(arr, 0);
                        arr[4] = new PointMass(1, 1, 1, 1, new Vector2(isLeftTeam ? this.GoalBounds.Left : this.GoalBounds.Right, this.GoalBounds.Top + (0.2f) * this.GoalBounds.Height), Vector2.Zero);
                        arr[5] = new PointMass(1, 1, 1, 1, new Vector2(isLeftTeam ? this.GoalBounds.Left : this.GoalBounds.Right, this.GoalBounds.Top + (0.5f) * this.GoalBounds.Height), Vector2.Zero);
                        arr[6] = new PointMass(1, 1, 1, 1, new Vector2(isLeftTeam ? this.GoalBounds.Left : this.GoalBounds.Right, this.GoalBounds.Top + (0.8f) * this.GoalBounds.Height), Vector2.Zero);
                        arr[4].id = "GT";
                        arr[5].id = "GM";
                        arr[6].id = "GB";
                        ReadOnlyCollection<PointMass> roc = new ReadOnlyCollection<PointMass>(arr);
                        Vector2 middleOfGoal = new Vector2(isLeftTeam ? this.GoalBounds.Left : this.GoalBounds.Right, this.GoalBounds.Top - (0.5f) * this.GoalBounds.Height);
                        IPointMass kickTarget = ClosestPlayerToPoint(roc, player, 1, middleOfGoal);
                        messages[player] = "Chaser T: " + kickTarget.id;
                        k = kick = FootballStrategies.PassToPlayer(player, kickTarget, simulation.Ball);
                    }  else
                        k = kick = Kick.None;
                }
                else
                {
                    messages[player] = isOutsideOfField(player, simulation.PitchBounds) ? "Outside" : "inside";

                    var allPlayers = simulation.Teams[0].Players.Concat(simulation.Teams[1].Players);
                    if (isOutsideOfField(player, simulation.PitchBounds))
                        player.Force = SteeringStrategies.Seek(player, Vector2.Zero, player.MaxSpeed);
                    else
                        FootballStrategies.SpreadOut(player, allPlayers, simulation.PitchBounds, 150, 100);
                }
            }

            return kick;
        }
예제 #6
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="Simulation" /> class.
        /// </summary>
        /// <param name="teams">The teams to be played against each other.</param>
        /// <param name="ball">The ball.</param>
        /// <param name="pitchBounds">The pitch boundaries.</param>
        /// <param name="friction">The friction coefficient.</param>
        public Simulation(ReadOnlyCollection<Team> teams, PointMass ball, RectangleF pitchBounds, float friction)
        {
            Contract.Requires<ArgumentNullException>(teams != null);
            Contract.Requires<ArgumentNullException>(ball != null);
            Contract.Requires<ArgumentException>(friction >= 0);
            Contract.Requires<ArgumentException>(pitchBounds.Width > 0 && pitchBounds.Height > 0);
            Contract.Requires<ArgumentException>(Contract.ForAll(teams, t => t != null && t.IsValid(pitchBounds)));
            Contract.Requires<ArgumentException>(pitchBounds.Contains(ball.Position));

            _simulate = SimulatePlaying;
            _teams = teams;
            _startingPositions = from t in teams select t.PlayerPositions;
            _ball = ball;
            _ballStartingPosition = ball.Position;
            PitchBounds = pitchBounds;
            Friction = friction;
        }
예제 #7
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="Simulation" /> class.
        /// </summary>
        /// <param name="teams">The teams to be played against each other.</param>
        /// <param name="ball">The ball.</param>
        /// <param name="pitchBounds">The pitch boundaries.</param>
        /// <param name="friction">The friction coefficient.</param>
        public Simulation(ReadOnlyCollection<Team> teams, PointMass ball, RectangleF pitchBounds, float friction)
        {
            Contract.Requires<ArgumentNullException>(teams != null);
            Contract.Requires<ArgumentNullException>(ball != null);
            Contract.Requires<ArgumentException>(friction >= 0);
            Contract.Requires<ArgumentException>(pitchBounds.Width > 0 && pitchBounds.Height > 0);
            Contract.Requires<ArgumentException>(Contract.ForAll(teams, t =>
                t != null &&
                pitchBounds.IntersectsOrBorders(t.GoalBounds) &&
                t.Players.All(p => pitchBounds.Contains(p.Position))));
            Contract.Requires<ArgumentException>(pitchBounds.Contains(ball.Position));

            _simulate = SimulatePlaying;
            _teams = teams;
            _startingPositions = (from t in teams select (from p in t.Players select p.Position).ToList().AsReadOnly()).ToList().AsReadOnly();
            _ball = ball;
            _ballStartingPosition = ball.Position;
            PitchBounds = pitchBounds;
            Friction = friction;
        }
예제 #8
0
 /// <summary>
 /// </summary>
 /// <param name="player"></param>
 /// <param name="target"></param>
 /// <param name="desiredSpeed"></param>
 /// <returns></returns>
 public static Vector2 FleeNormalized(PointMass player, Vector2 target, float desiredSpeed)
     => Vector2.Normalize(Flee(player, target, desiredSpeed));
예제 #9
0
 /// <summary>
 ///     Move away from a specified position.
 /// </summary>
 /// <param name="player"></param>
 /// <param name="target"></param>
 /// <param name="desiredSpeed"></param>
 /// <returns></returns>
 public static Vector2 Flee(PointMass player, Vector2 target, float desiredSpeed)
 {
     var desiredVelocity = Vector2.Normalize(target - player.Position).ClampMagnitude(desiredSpeed);
     return desiredVelocity - player.Velocity;
 }
예제 #10
0
 /// <summary>
 ///     Move away from a target's future position.
 /// </summary>
 /// <param name="player"></param>
 /// <param name="target"></param>
 /// <returns></returns>
 public static Vector2 Evade(PointMass player, PointMass target) => Vector2.Zero;
예제 #11
0
        /// <summary>
        /// </summary>
        /// <param name="player"></param>
        /// <param name="allPlayers"></param>
        /// <param name="pitchBounds"></param>
        /// <param name="playerOverlapRadius"></param>
        /// <param name="edgeOverlapRadius"></param>
        public static void SpreadOut(
            PointMass player,
            IEnumerable<IPointMass> allPlayers,
            RectangleF pitchBounds,
            float playerOverlapRadius,
            float edgeOverlapRadius)
        {
            var v = (from otherPlayer in allPlayers
                where player != otherPlayer
                select player.Position - otherPlayer.Position
                into between
                where between.Length() < playerOverlapRadius
                select between).Aggregate(Vector2.Zero, (current, between) => current + Vector2.Normalize(between));

            var force = Vector2.Normalize(v)*10;
            var stoppingForce = -player.Velocity;

            force = v.Length() > 0 ? force : stoppingForce;
            if (Math.Abs(player.Position.X - pitchBounds.X) < edgeOverlapRadius && player.Velocity.X < 0)
                force = new Vector2(-player.Velocity.X, force.Y);
            if (Math.Abs(player.Position.X - pitchBounds.Right) < edgeOverlapRadius && player.Velocity.X > 0)
                force = new Vector2(-player.Velocity.X, force.Y);
            if (Math.Abs(player.Position.Y - pitchBounds.Y) < edgeOverlapRadius && player.Velocity.Y < 0)
                force = new Vector2(force.X, -player.Velocity.Y);
            if (Math.Abs(player.Position.Y - pitchBounds.Bottom) < edgeOverlapRadius && player.Velocity.Y > 0)
                force = new Vector2(force.X, -player.Velocity.Y);
            player.Force = force;
        }