Ejemplo n.º 1
0
        private void InitClimbReachableNodes()
        {
            foreach (ClimbGroup climbGroup in CurrClimbGroup)
            {
                List <Collidable> climbCollidables     = climbGroup.ClimbCollidables;
                Collidable        upperClimbCollidable = climbCollidables[0];
                foreach (var navGraphNode1 in NavGraphNodes)
                {
                    CollidableResults result1 = upperClimbCollidable.CheckForCollision(navGraphNode1.Platform, Vector3.Zero);
                    //check which platform intersects the upper part of the climbable
                    if (result1.Intersect && upperClimbCollidable.MaxHeight >= navGraphNode1.Platform.MaxHeight - 10 && navGraphNode1.Platform.MinWidth <= upperClimbCollidable.MinWidth + 20 && navGraphNode1.Platform.MaxWidth >= upperClimbCollidable.MaxWidth - 20)
                    {
                        Vector2    startPos             = new Vector2(upperClimbCollidable.Center.X, upperClimbCollidable.MinHeight);
                        Collidable lowerClimbCollidable = climbCollidables[climbCollidables.Count - 1];
                        foreach (var navGraphNode2 in NavGraphNodes)
                        {
                            if (navGraphNode1 == navGraphNode2)
                            {
                                continue;
                            }
                            CollidableResults result2 = lowerClimbCollidable.CheckForCollision(navGraphNode2.Platform,
                                                                                               Vector3.Zero);
                            //check which platform intersects the lower part of the climbable
                            if (result2.Intersect && lowerClimbCollidable.MaxHeight < navGraphNode2.Platform.MaxHeight)
                            {
                                Vector2 endPos = new Vector2(lowerClimbCollidable.Center.X,
                                                             navGraphNode2.Platform.MinHeight);

                                if (startPos.Y < endPos.Y)
                                {
                                    navGraphNode1.ReachableNodes.Add(
                                        new Tuple <NavGraphNode, Vector2, Vector2>(navGraphNode2,
                                                                                   startPos - new Vector2(0, 20),
                                                                                   endPos - new Vector2(0, 20)));
                                    navGraphNode2.ReachableNodes.Add(
                                        new Tuple <NavGraphNode, Vector2, Vector2>(navGraphNode1,
                                                                                   endPos - new Vector2(0, 120),
                                                                                   startPos - new Vector2(0, 20)));
                                }
                                else
                                {
                                    navGraphNode1.ReachableNodes.Add(
                                        new Tuple <NavGraphNode, Vector2, Vector2>(navGraphNode2,
                                                                                   startPos - new Vector2(0, 120),
                                                                                   endPos - new Vector2(0, 20)));
                                    navGraphNode2.ReachableNodes.Add(
                                        new Tuple <NavGraphNode, Vector2, Vector2>(navGraphNode1,
                                                                                   endPos - new Vector2(0, 20),
                                                                                   startPos - new Vector2(0, 20)));
                                }
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 2
0
        public CharacterPhysics(Character character, Vector3 characterPosition, Vector3 characterSize, Rectangle hitboxOffset, Scene scene)
        {
            this.character    = (DefaultCharacter)character;
            initPosition      = characterPosition;
            position          = initPosition;
            this.hitboxOffset = hitboxOffset;
            BoundingBox       = new Rectangle((int)(characterPosition.X + hitboxOffset.X),
                                              (int)(characterPosition.Y + hitboxOffset.Y), hitboxOffset.Width + 5, hitboxOffset.Height);

            this.scene = scene;

            touchedActors = new List <Actor>();

            Projectiles = new List <Projectile>();
            InitMovementFields();

            rayCastResult      = new CollidableResults();
            insideClimbingArea = new CollidableResults();

            //Init Particle effects for footsteps
            footstepEffectFactory = new FootstepParticleEffectFactory(new Vector2(BoundingBox.Left, BoundingBox.Bottom), 20,
                                                                      250, Vector2.Zero, Vector2.Zero, 1f, 0.7f, Color.White, Color.White, 250);
            FootstepEffectManager = new ParticleEffectManager(ParticleConfig.FOOTSTEP_TEXTURE,
                                                              footstepEffectFactory, 1, 128, true, BlendState.NonPremultiplied)
            {
                Paused = true
            };
            scene.ParticleEffects.Add(FootstepEffectManager);

            Player currentPlayer = character.GetPosession() as Player;

            if (currentPlayer != null)
            {
                playerIndex = (int)currentPlayer.playerIndex;
            }
        }
Ejemplo n.º 3
0
        private void CheckForCollisions()
        {
            contactX           = true;
            contactYbottom     = true;
            contactYtop        = true;
            contactLeft        = true;
            contactRight       = true;
            contactFoliage     = false;
            isInClimbingArea   = false;
            insideClimbingArea = null;
            IsInAir            = true;
            bool ray1Intersect = false, ray2Intersect = false;
            bool rayLeftIntersect = false, rayRightIntersect = false;

            TrapPlacementPossible = false;
            //Multiple iterations are used for collision detection, since one correction could cause another collision
            Collidable trapPlacementRay = new Ray(new Vector2(TrapPlacementPos.X, TrapPlacementPos.Y - 50), new Vector2(TrapPlacementPos.X, TrapPlacementPos.Y + 50));

            for (var iteration = 0;
                 iteration < collisionTestIterations && (contactX || contactYbottom || contactYtop);
                 iteration++)
            {
                // Calculate the amount of X and Y movement expected by the player this frame
                var nextMove = speed * delta;

                // Store the original final expected movement of the player so we can
                // see if it has been modified due to a collision or potential collision later
                var originalMove = nextMove;

                // No collisions found yet
                contactX = contactYbottom = contactYtop = contactLeft = contactRight = false;

                insideClimbingArea = new CollidableResults()
                {
                    IntersectLeft  = false,
                    IntersectRight = false,
                    IntersectUp    = false,
                    IntersectDown  = false,
                };

                rayCastResult = new CollidableResults()
                {
                    Intersect = false
                };

                trapPlacementCastResult = new CollidableResults()
                {
                    Intersect = false
                };
                //check for potential collisions with polygons
                float tempX, tempY, tempWidth, tempHeight;
                tempX      = (float)Math.Round(position.X + hitboxOffset.X - 1, MidpointRounding.AwayFromZero);
                tempY      = (float)Math.Round(position.Y + hitboxOffset.Y - 1, MidpointRounding.AwayFromZero);
                tempWidth  = (float)Math.Round(tempX + BoundingBox.Width + 1, MidpointRounding.AwayFromZero);
                tempHeight = (float)Math.Round(tempY + BoundingBox.Height + 1, MidpointRounding.AwayFromZero);

                //Calculate the bounding polygon of the player at the current position
                var playerNextBounds = new Polygon(new List <Vector2>
                {
                    new Vector2(tempX, tempY),
                    new Vector2(tempWidth, tempY),
                    new Vector2(tempWidth, tempHeight),
                    new Vector2(tempX, tempHeight)
                }, false, false);

                var rayHeight = (tempHeight + tempY) / 2f;

                Collidable ray1 = new Ray(new Vector2(tempX, tempHeight - 10),
                                          new Vector2(tempX, tempHeight + 10));
                Collidable ray2 = new Ray(new Vector2(tempWidth, tempHeight - 10),
                                          new Vector2(tempWidth, tempHeight + 10));

                Collidable rayLeft = new Ray(new Vector2(tempX + 10, rayHeight),
                                             new Vector2(tempX - 10, rayHeight));
                Collidable rayRight = new Ray(new Vector2(tempWidth - 10, rayHeight),
                                              new Vector2(tempWidth + 10, rayHeight));

                climableYCenter = -1f;

                for (var i = 0; i < scene.GetCollidables().Count; i++)
                {
                    var currentCollidable = scene.GetCollidables()[i];

                    if (!currentCollidable.IsClimbable)
                    {
                        //----------------- Ray - Slope detection ---------------------------//
                        //The following code section shoots rays from the bottom of the player's bounding box to the ground.
                        //The results of the rays are used to check, whether the player is standing on a slope. If yes, the ..
                        //.. movement of the players is adjusted according to the steepness of the slope.
                        //!contactX && !contactYbottom && !contactYtop

                        if (!rayCastResult.Intersect)
                        {
                            rayCastResult = RayCast.DetectSlope(ray1, ray2, currentCollidable);
                        }
                        if (!ray1Intersect)
                        {
                            ray1Intersect = RayCast.CheckIfInsideClimbingArea(ray1, currentCollidable);
                        }
                        if (!ray2Intersect)
                        {
                            ray2Intersect = RayCast.CheckIfInsideClimbingArea(ray2, currentCollidable);
                        }
                        if (ray1Intersect || ray2Intersect)
                        {
                            IsInAir = false;
                        }

                        //Check if player collides left or right using rays
                        if (!rayLeftIntersect)
                        {
                            rayLeftIntersect = RayCast.CheckIfInsideClimbingArea(rayLeft, currentCollidable);
                        }
                        if (!rayRightIntersect)
                        {
                            rayRightIntersect = RayCast.CheckIfInsideClimbingArea(rayRight, currentCollidable);
                        }


                        //----------------- Ray - Slope detection -END---------------------------//
                    }
                    //------------------- Trap Placement Check -------------------------------//

                    if (!trapPlacementCastResult.Intersect)
                    {
                        trapPlacementCastResult.Intersect = RayCast.CheckIfInsideClimbingArea(trapPlacementRay, currentCollidable);
                    }

                    //------------------- Trap Placement Check  - END -------------------------------//

                    var polygonCollisionResult = currentCollidable.CheckForCollision(playerNextBounds,
                                                                                     speed * delta);


                    //Only adjust speed of the player if the polygon can't be climbed up or down( => IsClimbable)
                    if (polygonCollisionResult.WillIntersect && !currentCollidable.IsClimbable)
                    {
                        nextMove = polygonCollisionResult.MinimumTranslationVector + speed * delta;
                    }
                    else if ((polygonCollisionResult.WillIntersect || polygonCollisionResult.Intersect) &&
                             currentCollidable.IsClimbable)
                    {
                        isInClimbingArea = true;

                        bool atTop = false;

                        //--------- Ray- Climbing area detection ----------- //
                        //The following code section shoots ray left and right out of the players bounding box, in order
                        //to verify, whether the player is still inside the bounds of the climbing area and limit his movement otherwise
                        if (IsClimbing)
                        {
                            //check if player is still inside the climbable area
                            rayHeight = (tempHeight + tempY) / 2f;
                            var   rayWidth       = (tempWidth + tempX) / 2f;
                            var   deltaHeight    = (tempHeight - tempY) / 2f;
                            float collidableXMin = currentCollidable.MinWidth;
                            float collidableXMax = currentCollidable.MaxWidth;
                            float collidableYMax = currentCollidable.MaxHeight;
                            float collidableYMin = currentCollidable.ClimbGroupMinY;


                            if (rayHeight - currentCollidable.CenterYClimbGroup < 0)
                            {
                                atTop = true;
                            }


                            if (tempX >= collidableXMin)
                            {
                                Collidable leftRay = new Ray(new Vector2(collidableXMin - 10, rayHeight),
                                                             new Vector2(tempX + 10, rayHeight));
                                if (RayCast.CheckIfInsideClimbingArea(leftRay, currentCollidable))
                                {
                                    insideClimbingArea.IntersectLeft = true;
                                }
                            }

                            if (tempWidth <= collidableXMax)
                            {
                                Collidable rightRay = new Ray(new Vector2(tempWidth - 10, rayHeight),
                                                              new Vector2(collidableXMax + 10, rayHeight));
                                if (RayCast.CheckIfInsideClimbingArea(rightRay, currentCollidable))
                                {
                                    insideClimbingArea.IntersectRight = true;
                                }
                            }

                            if (tempHeight <= collidableYMax)
                            {
                                Collidable downRayLeft = new Ray(new Vector2(tempX, tempHeight + 20),
                                                                 new Vector2(tempX, collidableYMax + 30));
                                Collidable downRayRight = new Ray(new Vector2(tempWidth, tempHeight + 20),
                                                                  new Vector2(tempWidth, collidableYMax + 30));
                                Collidable downRayMiddle = new Ray(new Vector2(rayWidth, tempHeight - 2),
                                                                   new Vector2(rayWidth, collidableYMax + 10));

                                if (atTop)
                                {
                                    if (RayCast.CheckIfInsideClimbingArea(downRayMiddle, currentCollidable))
                                    {
                                        insideClimbingArea.IntersectDown = true;
                                    }
                                }
                                else
                                {
                                    if (RayCast.CheckIfInsideClimbingArea(downRayLeft, currentCollidable) && RayCast.CheckIfInsideClimbingArea(downRayRight, currentCollidable))
                                    {
                                        insideClimbingArea.IntersectDown = true;
                                    }
                                }
                            }

                            if (atTop)
                            {
                                insideClimbingArea.IntersectUp = !(tempY + deltaHeight < collidableYMin);
                            }
                            else
                            {
                                insideClimbingArea.IntersectUp = true;
                            }

                            climbableYMax   = currentCollidable.ClimbGroupMaxY;
                            climableYCenter = currentCollidable.CenterYClimbGroup;
                        }

                        //--------- Ray- Climbing area detection -END----------- //
                    }


                    // Detect what type of contact has occurred based on a comparison of
                    // the original expected movement vector and the new one

                    if (nextMove.Y > originalMove.Y)
                    {
                        contactYtop = true;
                    }

                    if (nextMove.Y < originalMove.Y)
                    {
                        contactYbottom = true;
                    }

                    if (nextMove.X < originalMove.X)
                    {
                        contactRight = true;
                    }

                    if (nextMove.X > originalMove.X)
                    {
                        contactLeft = true;
                    }

                    contactX = contactLeft || contactRight;

                    if (contactX && contactYtop && speed.Y < 0)
                    {
                        speed.Y = nextMove.Y = 0;
                    }

                    if (contactX && contactYbottom && speed.Y > 0)
                    {
                        speed.Y = nextMove.Y = 0;
                    }
                }

                if (!isInClimbingArea)
                {
                    IsClimbing = false;
                }

                if (IsClimbing)
                {
                    nextMove = originalMove;
                    var anyContact = contactYbottom || contactYtop || contactX;
                    if (anyContact && Math.Abs(originalMove.X) > 0.001)
                    {
                        if (!insideClimbingArea.IntersectLeft && originalMove.X < 0 && contactLeft)
                        {
                            nextMove.X = 0;
                            speed.X    = 0;
                        }
                        if (!insideClimbingArea.IntersectRight && originalMove.X > 0 && contactRight)
                        {
                            nextMove.X = 0;
                            speed.X    = 0;
                        }
                    }

                    if (anyContact && originalMove.Y > 0.001)
                    {
                        if ((insideClimbingArea.IntersectLeft || insideClimbingArea.IntersectRight) &&
                            !insideClimbingArea.IntersectDown)
                        {
                            nextMove.Y = 0;
                            speed.Y    = 0;
                            IsClimbing = false;
                        }
                    }

                    if (originalMove.Y < 0f && !insideClimbingArea.IntersectUp)
                    {
                        nextMove.Y -= CharacterConfig.JUMP_START_SPEED_Y / 10f;
                        IsClimbing  = false;
                    }
                }
                // If a contact has been detected, apply the re-calculated movement vector
                // and disable any further movement this frame (in either X or Y as appropriate)
                if (contactYtop || contactYbottom)
                {
                    position.Y += nextMove.Y;

                    speed.Y = 0;

                    if (contactYbottom)
                    {
                        jumping = false;
                        IsInAir = false;
                    }
                }


                if (contactX)
                {
                    if (rayCastResult.Intersect && !contactYtop && !(rayLeftIntersect && originalMove.X < 0) && !(rayRightIntersect && originalMove.X > 0))
                    {
                        position.X += nextMove.X * 0.5f * Math.Abs(rayCastResult.CollisionNormal.X);

                        if (Math.Abs(nextMove.X) > 0.0001f)
                        {
                            float newSpeed = speed.X * (1 - 0.3f * Math.Abs(rayCastResult.CollisionNormal.X));
                            speed.X = 0.6f * speed.X + 0.4f * newSpeed;
                        }
                        else
                        {
                            speed.X = 0;
                        }
                    }
                    else
                    {
                        if (!(rayLeftIntersect && nextMove.X < 0) && !(rayRightIntersect && nextMove.X > 0))
                        {
                            position.X += nextMove.X;
                        }

                        speed.X = 0;
                    }
                }
                else if (insideClimbingArea != null)
                {
                    position.X += nextMove.X;
                }

                if (jumping && IsClimbing)
                {
                    jumping = false;
                    speed.X = 0;
                }

                if (((contactX || contactYtop) && (IsInAir) && !IsClimbing))
                {
                    speed.X    = nextMove.X = 0;
                    speed.Y   += 3 * accY * delta;
                    nextMove.Y = speed.Y * delta;
                }

                if (IsInAir && !jumping)
                {
                    speed.X *= 0.9f;
                }

                if (trapPlacementCastResult.Intersect && !(rayLeftIntersect && !IsFacingRight()) && !(rayRightIntersect && IsFacingRight()))
                {
                    TrapPlacementPossible = true;
                }
            }

            //Check if the player intersects any of the other actors (like undergrowth, treasure, base etc.)
            IsTouchingShopkeeper = false;
            contactFoliage       = false;
            touchedActors.Clear();

            foreach (var actor in scene.GetActors())
            {
                Rectangle boundingBoxActor;
                if (actor.GetType() == typeof(ShopKeeper))
                {
                    ShopKeeper shopKeeper = actor as ShopKeeper;
                    boundingBoxActor = shopKeeper.BoundingBox;
                    if (!BoundingBox.Intersects(boundingBoxActor))
                    {
                        continue;
                    }
                    IsTouchingShopkeeper = true;
                    if (character.InvTreasure != null)
                    {
                        shopKeeper.ContactPlayer = true;
                    }
                }
                else
                {
                    boundingBoxActor = new Rectangle((int)actor.GetPosition().X,
                                                     (int)(actor.GetPosition().Y - actor.GetSize().Y),
                                                     (int)actor.GetSize().X, (int)actor.GetSize().Y);

                    if (!BoundingBox.Intersects(boundingBoxActor))
                    {
                        continue;
                    }

                    if (actor.GetType() == typeof(Projectile) && character.GetPosession().GetType() != typeof(AiIndigenController))
                    {
                        scene.MatchSoundManager.PlaySoundEffect(SoundEffectEnumeration.Hit);
                        ((Projectile)actor).DestroyProjectile();
                        IsStunned       = true;
                        CurrentStunTime = ProjectileConfig.BULLET_STUN_TIME;
                    }
                }

                touchedActors.Add(actor);
            }

            foreach (Foliage foliage in scene.GetFoliage())
            {
                Rectangle boundingBoxActor = new Rectangle((int)foliage.GetPosition().X,
                                                           (int)(foliage.GetPosition().Y - foliage.GetSize().Y),
                                                           (int)foliage.GetSize().X, (int)foliage.GetSize().Y);

                if (!BoundingBox.Intersects(boundingBoxActor))
                {
                    continue;
                }

                if (foliage.Active)
                {
                    contactFoliage = true;
                }
                touchedActors.Add(foliage);
            }
        }
Ejemplo n.º 4
0
        public static CollidableResults DetectSlope(Collidable ray1, Collidable ray2, Collidable collidable)
        {
            CollidableResults rayCastCollisionResult = new CollidableResults()
            {
                Intersect       = false,
                HitPoint        = Vector3.Zero,
                CollisionNormal = Vector3.Zero
            };

            if (ray1.Points.Count > 2 || ray2.Points.Count > 2)
            {
                return(null);
            }



            var  rayCastResult1   = ray1.CheckForCollision(collidable, Vector3.Zero);
            var  rayCastResult2   = ray2.CheckForCollision(collidable, Vector3.Zero);
            bool slopeOnHitPoint1 = false;
            bool slopeOnHitPoint2 = false;

            if (rayCastResult1.Intersect)
            {
                if (Math.Abs(Vector3.Dot(rayCastResult1.CollisionNormal, Vector3.UnitX)) > 0.000001)
                {
                    slopeOnHitPoint1 = true;
                }
            }
            if (rayCastResult2.Intersect)
            {
                if (Math.Abs(Vector3.Dot(rayCastResult2.CollisionNormal, Vector3.UnitX)) > 0.000001)
                {
                    slopeOnHitPoint2 = true;
                }
            }

            //Conditons for slope collision:
            //1: Both rays hit on a slope
            //2: One ray hits a slope and the hit point where the slope is detected is higher than the other hitpoint
            bool condition1 = slopeOnHitPoint1 && slopeOnHitPoint2;
            bool condition2 = slopeOnHitPoint1 && rayCastResult1.HitPoint.Y > rayCastResult2.HitPoint.Y;
            bool condition3 = slopeOnHitPoint2 && rayCastResult2.HitPoint.Y > rayCastResult1.HitPoint.Y;


            if (condition1)
            {
                //Ray centerRay = new Ray(new Vector2((ray1.Points[0].X + ray2.Points[0].X)*0.5f,ray1.Points[0].Y), new Vector2((ray1.Points[1].X + ray2.Points[1].X) * 0.5f, ray1.Points[1].Y));
                if (Math.Abs(rayCastResult1.CollisionNormal.X) < Math.Abs(rayCastResult2.CollisionNormal.X))
                {
                    rayCastCollisionResult = rayCastResult1;
                }
                else
                {
                    rayCastCollisionResult = rayCastResult2;
                }
                //rayCastCollisionResult = rayCastResult1;
            }
            else if (condition2)
            {
                rayCastCollisionResult = rayCastResult1;
            }
            else if (condition3)
            {
                rayCastCollisionResult = rayCastResult2;
            }

            return(rayCastCollisionResult);
        }