Пример #1
0
        //TODO: Make this account for attack range and entity size.
        //TODO: Maybe make this not allow them to leave their platform as well, just to avoid issues with pathing.
        private void FollowEntity(Entity e, GameTime Time)
        {
            var entity = this.Parent;
            Random r = new Random();
            float attackRange = AttributesComponent.MeleeAttackRange.X;

            if (entity.Location.Contains((int)e.Location.Center.X, (int)e.Location.Center.Y))
            {
                if (!PhysicsComponent.IsGrounded)
                    return; // Do nothing, just wait for us to fall on our location.
            }
            else
            {
                bool MissingHorizontally = e.Location.Center.X - attackRange > entity.Location.Right || e.Location.Center.X + attackRange < entity.Location.Left;
                if (entity.Location.Bottom > e.Location.Bottom && !MissingHorizontally)
                {
                    if (CanJumpToChase)
                        MovementComponent.Jump(AllowMultiJump);
                }
                if (MissingHorizontally)
                {
                    //Most of this code prevents the AI from jumping off their current platform to chase player.
                    //Often results in death.
                    float checkDistance = PhysicsComponent.VelocityX * Time.GetTimeScalar();

                    Vector2 leftPlatformVector = new Vector2(Parent.Location.Left + checkDistance, Parent.Location.Bottom + 1);
                    Vector2 rightPlatformVector = new Vector2(Parent.Location.Right + checkDistance, Parent.Location.Bottom + 1);
                    Vector2 leftWallVector = new Vector2(Parent.Location.Left + checkDistance, Parent.Location.Center.Y);
                    Vector2 rightWallVector = new Vector2(Parent.Location.Right + checkDistance, Parent.Location.Center.Y);
                    bool leftPossible = PhysicsSystem.IsLocationSolid(leftPlatformVector) && !PhysicsSystem.IsLocationSolid(leftWallVector);
                    bool rightPossible = PhysicsSystem.IsLocationSolid(rightPlatformVector) && !PhysicsSystem.IsLocationSolid(rightWallVector);

                    if (entity.Location.Center.X > e.Location.Center.X + attackRange)
                    {
                        if (leftPossible)
                            MovementComponent.BeginWalking(Direction.Left);
                        else
                            MovementComponent.StopWalking();
                    }
                    else if (entity.Location.Center.X < e.Location.Center.X - attackRange)
                    {
                        if (rightPossible)
                            MovementComponent.BeginWalking(Direction.Right);
                        else
                            MovementComponent.StopWalking();
                    }
                }
                else
                {
                    if (MovementComponent.IsWalking)
                        MovementComponent.StopWalking();
                }

                //Ensure they are facing the correct direction, if they move within AI rectangle.
                if (entity.Location.Center.X > e.Location.Center.X)
                {
                    MovementComponent.CurrentDirection = Direction.Left;
                }
                else if (entity.Location.Center.X < e.Location.Center.X)
                {
                    MovementComponent.CurrentDirection = Direction.Right;
                }
            }
        }
Пример #2
0
        protected override void OnUpdate(GameTime Time)
        {
            base.OnUpdate(Time);
            if (AIEnabled)
            {
                //Begin process of death if entity has run out of health.
                if (((AttributesComponent.CurrentHealth / AttributesComponent.MaxHealth) * 100) < 10)
                {
                    if (!DeathStarted)
                        DeathTime = DateTime.Now;

                    DeathStarted = true;
                }

                //Begin process of fleeing if entity's health is <25%.
                if (((AttributesComponent.CurrentHealth / AttributesComponent.MaxHealth) * 100) < 25)
                {
                    FleeingStarted = true;
                }

                bool shouldFlee = FleeingStarted && FleeingEnabled;
                bool shouldDie = DeathStarted && DeathEnabled;

                if (!shouldFlee && !shouldDie) //NORMAL AI
                {
                    bool foundEntity = false;
                    bool projectileFlyingToMe = false;
                    bool entityAttackingMe = false;
                    bool entityAttackable = false;
                    bool entityFollowable = false;
                    Entity entityToFollow = null;

                    //TODO: This could be very ineffecient.
                    //Foreach entity in this entity's reaction box.
                    foreach (Entity e in PhysicsSystem.GetEntitiesAtLocation(GetReactionBox()))
                    {
                        var clc = e.GetComponent<ClassificationComponent>();
                        var coc = e.GetComponent<CombatComponent>();

                        if (clc.Classification == EntityClassification.Player) //If Player
                        {
                            foundEntity = true;

                            entityFollowable = true;
                            entityToFollow = e;

                            if (coc.IsAttacking && WithinEntitysAttackRange(e) && EntityFacingMe(e))
                                entityAttackingMe = true;

                            if (!MovementComponent.IsWalking && EntityWithinAttackRange(e))
                                entityAttackable = true;
                        }
                        else if (clc.Classification == EntityClassification.Projectile) //If Projectile
                        {
                            foundEntity = true;

                            //Basically, projectiles within our rectangle might hit us, so we'll just block.
                            if (EntityGoingToMe(e))
                                projectileFlyingToMe = true;
                        }
                    }

                    if (foundEntity) //If we found an entity.
                    {
                        //We're reacting to an entity.
                        IsReacting = true;

                        //If we're following a path and we're aggressive, stop following the path.
                        if (PathComponent.PathingEnabled && Aggressive)
                        {
                            PathComponent.StopFollowing();
                        }

                        //If we're able to follow an entity and we're aggressive, follow the entity.
                        if (entityFollowable && entityToFollow != null && Aggressive)
                        {
                            FollowEntity(entityToFollow, Time);
                        }

                        //If an entity is attackable and if i (the enemy) am not blocking, attack.
                        if (entityAttackable && !CombatComponent.IsBlocking)
                        {
                            CombatComponent.AttackAI();
                        }
                    }
                    else //If we found nothing.
                    {
                        IsReacting = false;

                        //Resume following the path.
                        if (!PathComponent.PathingEnabled)
                            PathComponent.StartFollowing();
                    }

                    //If a projectile is coming to us, or an entity is attacking us, block.
                    if (entityAttackingMe || projectileFlyingToMe)
                    {
                        if (!CombatComponent.IsBlocking)
                            CombatComponent.BeginBlock();
                    }

                    //If there's no projectile coming to us, or no entity attacking us, end the block.
                    if (!entityAttackingMe && !projectileFlyingToMe)
                    {
                        if (CombatComponent.IsBlocking)
                            CombatComponent.EndBlock();
                    }
                }
                else if (shouldDie) //DYING AI
                {
                    //Stop blocking if we were doing so at the moment death occured.
                    if (CombatComponent.IsBlocking)
                        CombatComponent.EndBlock();

                    Direction walkDirection = MovementComponent.WalkDirection == Direction.Left ? Direction.Right : Direction.Left;
                    double walkTime = 200;

                    if ((DateTime.Now - DeathTime).TotalMilliseconds > walkTime)
                    {
                        MovementComponent.BeginWalking(walkDirection);
                        DeathTime = DateTime.Now;
                    }
                }
                else if (shouldFlee) //FLEEING AI
                {
                    //Stop blocking if we were doing so at the moment fleeing occured.
                    if (CombatComponent.IsBlocking)
                        CombatComponent.EndBlock();

                    float checkDistance = PhysicsComponent.VelocityX * Time.GetTimeScalar();

                    //Run back and forth on platform.
                    Vector2 leftPlatformVector = new Vector2(Parent.Location.Left + checkDistance, Parent.Location.Bottom + 1);
                    Vector2 rightPlatformVector = new Vector2(Parent.Location.Right + checkDistance, Parent.Location.Bottom + 1);
                    Vector2 leftWallVector = new Vector2(Parent.Location.Left + checkDistance, Parent.Location.Center.Y);
                    Vector2 rightWallVector = new Vector2(Parent.Location.Right + checkDistance, Parent.Location.Center.Y);
                    bool leftPossible = PhysicsSystem.IsLocationSolid(leftPlatformVector) && !PhysicsSystem.IsLocationSolid(leftWallVector);
                    bool rightPossible = PhysicsSystem.IsLocationSolid(rightPlatformVector) && !PhysicsSystem.IsLocationSolid(rightWallVector);

                    //Set a location if one hasn't been set (default is Direction.Down). Very unlikely to happen here, but can't say impossible.
                    if (MovementComponent.CurrentDirection == Direction.Down)
                        MovementComponent.CurrentDirection = Direction.Left;

                    if (MovementComponent.CurrentDirection == Direction.Left)
                    {
                        if (leftPossible)
                            MovementComponent.BeginWalking(Direction.Left);
                        else if (rightPossible)
                            MovementComponent.BeginWalking(Direction.Right);
                    }
                    else if (MovementComponent.CurrentDirection == Direction.Right)
                    {
                        if (rightPossible)
                            MovementComponent.BeginWalking(Direction.Right);
                        else if (leftPossible)
                            MovementComponent.BeginWalking(Direction.Left);
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Decides which direction the AI should walk to follow the path. Simple x value check.
        /// </summary>
        /// <param name="Time"></param>
        protected override void OnUpdate(GameTime Time)
        {
            if (PathingEnabled)
            {
                if (Nodes.Count != 0)
                {
                    var entity = this.Parent;
                    var mc = entity.GetComponent<MovementComponent>();
                    var pc = entity.GetComponent<PhysicsComponent>();
                    var ps = Scene.GetSystem<PhysicsSystem>();
                    //Formerly Vector2.Distance(entity.Position, CurrentNode) for Y stuff, but not needed.
                    if (entity.Location.Contains((int)CurrentNode.X, (int)CurrentNode.Y))
                    {
                        if (!pc.IsGrounded)
                            return; // Do nothing, just wait for us to fall on our location.
                        AdvanceNode();
                    }
                    else
                    {
                        bool MissingHorizontally = CurrentNode.X > entity.Location.Right || CurrentNode.X < entity.Location.Left;
                        if (entity.Location.Top > CurrentNode.Y && /*(DateTime.Now - _LastJump).TotalMilliseconds > JumpDelay &&*/ !MissingHorizontally)
                        {
                            mc.Jump(AllowMultiJump);
                            _LastJump = DateTime.Now;
                        }
                        if (MissingHorizontally)
                        {
                            if (entity.Location.Left > CurrentNode.X)
                            {
                                mc.BeginWalking(Direction.Left);
                                // Check if we'll need to jump this frame.
                                if (!ps.IsLocationSolid(new Vector2(entity.Location.Left - pc.VelocityX * Time.GetTimeScalar(), entity.Location.Bottom + 5)))
                                    mc.Jump(AllowMultiJump);
                            }
                            else if (entity.Location.Right < CurrentNode.X)
                            {
                                mc.BeginWalking(Direction.Right);
                                if (!ps.IsLocationSolid(new Vector2(entity.Location.Right + pc.VelocityX * Time.GetTimeScalar(), entity.Location.Bottom + 5)))
                                    mc.Jump(AllowMultiJump);
                            }
                        }
                        else
                            mc.StopWalking();
                    }
                }
                else
                {
                    float checkDistance = PhysicsComponent.VelocityX * Time.GetTimeScalar();

                    //Run back and forth on platform.
                    //This is fairly close to fleeing AI.
                    Vector2 leftPlatformVector = new Vector2(Parent.Location.Left + checkDistance, Parent.Location.Bottom + 1);
                    Vector2 rightPlatformVector = new Vector2(Parent.Location.Right + checkDistance, Parent.Location.Bottom + 1);
                    Vector2 leftWallVector = new Vector2(Parent.Location.Left + checkDistance, Parent.Location.Center.Y);
                    Vector2 rightWallVector = new Vector2(Parent.Location.Right + checkDistance, Parent.Location.Center.Y);
                    bool leftPossible = PhysicsSystem.IsLocationSolid(leftPlatformVector) && !PhysicsSystem.IsLocationSolid(leftWallVector);
                    bool rightPossible = PhysicsSystem.IsLocationSolid(rightPlatformVector) && !PhysicsSystem.IsLocationSolid(rightWallVector);

                    //Set a location if one hasn't been set (default is Direction.Down), which is likely when we have no path.
                    if (MovementComponent.CurrentDirection == Direction.Down)
                        MovementComponent.CurrentDirection = Direction.Left;

                    if (MovementComponent.CurrentDirection == Direction.Left)
                    {
                        if (leftPossible)
                            MovementComponent.BeginWalking(Direction.Left);
                        else if (rightPossible)
                            MovementComponent.BeginWalking(Direction.Right);
                    }
                    else if (MovementComponent.CurrentDirection == Direction.Right)
                    {
                        if (rightPossible)
                            MovementComponent.BeginWalking(Direction.Right);
                        else if (leftPossible)
                            MovementComponent.BeginWalking(Direction.Left);
                    }
                }
            }

            base.OnUpdate(Time);
        }
Пример #4
0
        private void PerformStaticCollision(GameTime Time)
        {
            // This is safe to multi-thread because we're never modifying anything besides the Component itself.
            // But each iteration is so cheap that the overhead of threading outweighs performance benefits.
            List<Task> Tasks = new List<Task>();
            foreach(var Component in GetFilteredComponents<PhysicsComponent>()) {
                var Parent = Component.Parent;
                if(!Component.IsGrounded)
                    Component.VelocityY += Gravity * Time.GetTimeScalar() * Parent.GetComponent<PhysicsComponent>().GravityCoefficient; //Prolly not the best thing to do GetComponent, eventually make something else.
                //if(Component.IsMoving) {
                    float CurrSign = Math.Sign(Component.VelocityX);
                    Component.VelocityX += -CurrSign * HorizontalDrag * Time.GetTimeScalar() * Parent.GetComponent<PhysicsComponent>().HorizontalDragCoefficient;
                    if(Math.Sign(Component.VelocityX) != CurrSign)
                        Component.VelocityX = 0;
                //}
                Vector2 PositionDelta = Component.Velocity * Time.GetTimeScalar();
                // First, handle falling. Check for collision a bit below bottom + PositionDelta, and put them back to the top of the tile if hit.
                if(Component.VelocityY >= 0 && CheckStaticCollision(Parent, new Vector2(0, (Parent.Size.Y / 2) + PositionDelta.Y + 1), (Tile) => new Vector2(Parent.Position.X, Tile.Location.Top - Parent.Size.Y))) {
                    // We're going to hit a tile while falling, so stop falling.
                    Component.IsGrounded = true;
                    Component.VelocityY = 0;
                    PositionDelta.Y = 0;
                } else {
                    // Otherwise, we're not grounded, and check for collision above.
                    Component.IsGrounded = false;
                    if(Component.VelocityY < 0 && CheckStaticCollision(Parent, new Vector2(0, (-Parent.Size.Y / 2) + PositionDelta.Y - 1), (Tile) => new Vector2(Parent.Position.X, Tile.Location.Bottom))) {
                        Component.VelocityY = 0;
                        PositionDelta.Y = 0;
                    }
                }
                // Now, check horizontal collision.
                if(Component.VelocityX >= 0.001f && CheckStaticCollision(Parent, new Vector2(Parent.Size.X / 2 + PositionDelta.X + 1, 0), (Tile) => new Vector2(Tile.Location.Left - Parent.Size.X, Parent.Position.Y))) {
                    PositionDelta.X = 0;
                    Component.VelocityX = 0;
                } else if(Component.VelocityX <= 0.001f && CheckStaticCollision(Parent, new Vector2(-Parent.Size.X / 2 + PositionDelta.X - 1, 0), (Tile) => new Vector2(Tile.Location.Right, Parent.Position.Y))) {
                    PositionDelta.X = 0;
                    Component.VelocityX = 0;
                }

                Parent.Position += PositionDelta;
                Parent.Y = Math.Max(0, Parent.Y);
                Parent.X = Math.Max(-Scene.TileSize.X / 2, Parent.X);
                Parent.X = Math.Min(Scene.MapSize.X - Scene.TileSize.X, Parent.X);
                // Special case: If we're at the bottom of the level, we should be considered grounded.
                if(Parent.Y > Scene.MapSize.Y - Parent.Size.Y) {
                    Parent.Y = Scene.MapSize.Y - Parent.Size.Y;
                    Component.VelocityY = 0;
                    Component.IsGrounded = true;
                }
            }
        }
Пример #5
0
 protected override void OnUpdate(GameTime Time)
 {
     base.OnUpdate(Time);
     if(_WalkDirection == Direction.Left)
         PhysicsComponent.VelocityX -= Math.Max(0, Math.Min(MaxWalkingSpeed + PhysicsComponent.VelocityX, WalkAcceleration * Time.GetTimeScalar()));
     else if(_WalkDirection == Direction.Right)
         PhysicsComponent.VelocityX += Math.Max(0, Math.Min(MaxWalkingSpeed - PhysicsComponent.VelocityX, WalkAcceleration * Time.GetTimeScalar()));
     if(!PhysicsComponent.IsGrounded && _WasGrounded)
         _LastUngrounded = DateTime.Now;
     _WasGrounded = PhysicsComponent.IsGrounded;
     if(PhysicsComponent.IsGrounded && !_JumpedThisFrame) // This may be called after the Jump, before PhysicsSystem updates position.
         _JumpedSinceUngrounded = false;
     _JumpedThisFrame = false;
 }