コード例 #1
0
ファイル: AITraining.cs プロジェクト: Onin1/shootmup
        public static Dictionary <Type, ElementProximity> ComputeProximity(Player self, List <Element> elements)
        {
            var closest = new Dictionary <Type, ElementProximity>();

            foreach (var elem in elements)
            {
                if (elem.Id == self.Id)
                {
                    continue;
                }

                ElementProximity proximity = null;
                Type             type      = elem.GetType();

                // consolidate player types
                if (elem is Player)
                {
                    type = typeof(Player);
                }
                // consolidate obstacle types
                if (elem is Obstacle)
                {
                    type = typeof(Obstacle);
                }

                if (!closest.TryGetValue(type, out proximity))
                {
                    proximity = new ElementProximity()
                    {
                        Name     = type.Name,
                        Id       = elem.Id,
                        Distance = float.MaxValue
                    };
                    closest.Add(type, proximity);
                }

                // calculate the distance between thees
                var distance = Collision.DistanceBetweenPoints(self.X, self.Y, elem.X, elem.Y);
                var angle    = Collision.CalculateAngleFromPoint(self.X, self.Y, elem.X, elem.Y);

                // retain only the closest
                if (distance < proximity.Distance)
                {
                    proximity.Id       = elem.Id;
                    proximity.Angle    = angle;
                    proximity.Distance = distance;
                }
            }

            return(closest);
        }
コード例 #2
0
        public override ActionEnum Action(List <Element> elements, float angleToCenter, bool inZone, ref float xdelta, ref float ydelta, ref float zdelta, ref float angle)
        {
            var   playerCount = 0;
            float playerX     = 0;
            float playerY     = 0;
            bool  shouldMelee = false;

            // find proximity to all types
            var closest = AITraining.ComputeProximity(this, elements);

            // gather details about if there is a crowd
            foreach (var elem in elements)
            {
                if (elem.Id == Id)
                {
                    continue;                // found myself
                }
                if (!(elem is Player))
                {
                    continue;                    // only care about players
                }
                playerCount++;
                playerX += elem.X;
                playerY += elem.Y;
            }

            // calculate the average center (if there are players near by)
            if (playerCount >= 1)
            {
                playerX /= (float)playerCount;
                playerY /= (float)playerCount;
            }

            // choose an action - set the rules in reverse order in order to set precedence
            var action = ActionEnum.None;

            xdelta = ydelta = angle = 0;

            if (PreviousAngle < 0)
            {
                // choose an angle at random
                PreviousAngle = Rand.Next() % 360;
            }
            angle = PreviousAngle;

            // 3) Shield
            if (Shield < Constants.MaxShield)
            {
                ElementProximity helmet = null;
                if (closest.TryGetValue(typeof(Shield), out helmet))
                {
                    // there is health either close or touching
                    if (IsTouching(helmet, Width / 2))
                    {
                        // choose to pickup
                        action = ActionEnum.Pickup;
                        // set direction via another decision
                        PreviousPickupId = helmet.Id;
                    }
                    else
                    {
                        // choose action via another decision
                        angle = helmet.Angle;
                    }
                }
            }

            // 2) Health
            if (Health < Constants.MaxHealth)
            {
                ElementProximity bandage = null;
                if (closest.TryGetValue(typeof(Health), out bandage))
                {
                    // there is health either close or touching
                    if (IsTouching(bandage, Width / 2))
                    {
                        // choose to pickup
                        action = ActionEnum.Pickup;
                        // set direction via another decision
                        PreviousPickupId = bandage.Id;
                    }
                    else
                    {
                        // choose action via another decision
                        angle = bandage.Angle;
                    }
                }
            }

            // 1) Have weapon
            if (Primary != null && Primary is RangeWeapon)
            {
                var weapon            = Primary as RangeWeapon;
                ElementProximity ammo = null;
                // need ammo
                if (weapon.Ammo < MinAmmo && closest.TryGetValue(typeof(Ammo), out ammo))
                {
                    // there is ammo either close or touching
                    if (IsTouching(ammo, Width / 2))
                    {
                        // choose to pickup
                        action = ActionEnum.Pickup;
                        // set direction via another decision
                        PreviousPickupId = ammo.Id;
                    }
                    else
                    {
                        // choose action via another decision
                        angle = ammo.Angle;
                    }
                }

                // needs reload
                if (!weapon.RoundsInClip(out int rounds) && rounds == 0 && weapon.HasAmmo())
                {
                    // choose to reload
                    action = ActionEnum.Reload;
                    // choose direction via another decision
                }

                ElementProximity ak47 = null;
                // pick up ak47
                if (!(Primary is AK47) && closest.TryGetValue(typeof(AK47), out ak47))
                {
                    // there is an AK47 either close or touching
                    if (IsTouching(ak47, Width / 2))
                    {
                        // choose to pickup
                        action = ActionEnum.Pickup;
                        // set direction via another decision
                        PreviousPickupId = ak47.Id;
                    }
                    else
                    {
                        // choose action via another decision
                        angle = ak47.Angle;
                    }
                }

                ElementProximity player = null;
                // shoot a player
                if (weapon.CanShoot() && closest.TryGetValue(typeof(Player), out player))
                {
                    // choose to shoot
                    action = ActionEnum.Attack;
                    // move towards the player
                    angle = player.Angle;
                }
            }

            // 0) No weapon
            if (Primary == null || !(Primary is RangeWeapon))
            {
                // AI does not have a weapon, so go ahead and melee (if no other action)
                shouldMelee = true;

                // 0.b if near a player, melee
                ElementProximity player = null;
                if (closest.TryGetValue(typeof(Player), out player))
                {
                    if (IsTouching(player, Fists.Distance))
                    {
                        // choose to melee
                        action = ActionEnum.Attack;
                        // turn towards the player
                        angle = player.Angle;
                    }
                }

                // 0.a is there a weapon within view
                ElementProximity weapon = null;
                if (!closest.TryGetValue(typeof(AK47), out weapon))
                {
                    if (!closest.TryGetValue(typeof(Pistol), out weapon))
                    {
                        if (!closest.TryGetValue(typeof(Shotgun), out weapon))
                        {
                        }
                    }
                }
                if (weapon != null)
                {
                    // there is a weapon either close or touching
                    if (IsTouching(weapon, Width / 2))
                    {
                        // choose to pickup
                        action = ActionEnum.Pickup;
                        // set direction via another decision
                        PreviousPickupId = weapon.Id;
                    }
                    else
                    {
                        // choose action via another decision
                        angle = weapon.Angle;
                    }
                }
            }

            // if there are too many players, then run away
            if (playerCount >= 5)
            {
                // choose an angle opposite from where the center of the other players are
                angle = Collision.CalculateAngleFromPoint(X, Y, playerX, playerY);
                // go the opposite way
                angle = (angle + 180) % 360;
            }

            // choose defaults
            if (action == ActionEnum.None)
            {
                // default to move
                action = ActionEnum.Move;
            }

            // check if we are in the Zone
            if (inZone)
            {
                // we should be moving towards the center
                if (action == ActionEnum.Move)
                {
                    // eek we are in the zone, indicate that we should be moving towards the center
                    angle = angleToCenter;
                }
            }

            // check if we seem to be stuck
            if (IsStuck())
            {
                // take some corrective action
                if (ShowDiagnostics)
                {
                    System.Diagnostics.Debug.WriteLine("AI seems stuck");
                }
                // try something new
                angle           = Rand.Next() % 360;
                CorrectiveAngle = 0;
            }

            // check if our last movement was obstructed
            float moveAngle = (angle + CorrectiveAngle) % 360;

            if (CorrectiveAngle > 0)
            {
                CorrectiveAngle -= 15;
            }
            if (CorrectiveAngle < 0)
            {
                CorrectiveAngle = 0;
            }

            // save angle for next time
            PreviousAngle = moveAngle;

            // set course
            float x1, y1, x2, y2;

            Collision.CalculateLineByAngle(X, Y, moveAngle, 1, out x1, out y1, out x2, out y2);

            xdelta = x2 - x1;
            ydelta = y2 - y1;

            // normalize
            var sum = (float)(Math.Abs(xdelta) + Math.Abs(ydelta));

            xdelta = xdelta / sum;
            ydelta = ydelta / sum;

            if (Math.Abs(xdelta) + Math.Abs(ydelta) > 1.0001)
            {
                throw new Exception("Invalid xdelta,ydelta : " + xdelta + "," + ydelta);
            }

            if (ShowDiagnostics)
            {
                System.Diagnostics.Debug.WriteLine("AI {0} {1} {2} {3}", action, angle, xdelta, ydelta);
            }

            // if our action is to move... do a melee while moving
            if (action == ActionEnum.Move && shouldMelee)
            {
                return(ActionEnum.Attack);
            }
            else
            {
                return(action);
            }
        }
コード例 #3
0
 public bool IsTouching(ElementProximity element, float radius)
 {
     return(element.Distance < radius);
 }