XNA array problem

Started by
9 comments, last by Bruno Filip 7 years, 8 months ago

Hi everyone, so there is this problem I have, and I dont know why it is happening.

So first off I made a class called Entity and I made entites array(images) with 2 elemetns Entity entites = new Entity[2] in my game1.cs, I also made collision detection system.

So now In my Game1.cs class in Update() method I call a Collision() method, and a Collision() method goes like this:


private void Collision()
        {
            entites[0].CollisionWithPlayer(player.playerRectangle);
            entites[1].CollisionWithPlayer(player.playerRectangle);
        }

now when I run the game, Collision is not applied to entites[0], it is applied just to enitites[1], BUT


private void Collision()
{
entites[1].CollisionWithPlayer(player.playerRectangle); // now enitites[1] is first and 0 is second, reversed as in code above
entites[0].CollisionWithPlayer(player.playerRectangle);
}

Note that I have switched Array Indexes, And now when I build it and run the game, Collision is not applied to entites[1], it is applied just to enitites[0].

Why is that so, how can that be? How to fix this?

Thanks in advanced :/

Oh btw, here is my Coliision method in Entity Class, if it would be of any importance:


public void CollisionWithPlayer(Rectangle playerRectangle)
        {
            if (blablabla)
            {
                CanGoBot = false;
            }
            else CanGoBot = true;


            if (blablabla)
            {
                CanGoTop = false;
            }
            else CanGoTop = true;

            if (blablabla)
            {
                CanGoRight = false;
            }
            else CanGoRight = true;


            if (blablabla)
            {
                CanGoLeft = false;
            }
            else CanGoLeft = true;

        }
Advertisement
How have you declared CanGoBot, CanGoTop, etc?

You might want to show 'blablabla' as well, in case that's the problem.

I declared public static bools CanGoBot, top, right left in entity class, and used them for checking in player class if player can go bot then do this and so on,

and the bla bla part is not a problem, it is working good, the problem is the part above my last edit, somehow for some reason in game1.cs Collision method only the last code statement is executed, if I switch indexes as shown above, no matter what, only the 2nd statment in Collision method is going to be working in my game :/

Right, those variables shouldn't be static. That means there is one value shared across all instances of the class. So the result of the last call ends up overriding all the previous values.

Okay, I have now made some changes, but the issue didnt get fixed. So first I will post code, this is the code from my Player class now


public void CollisionWith(Rectangle anotherRect)
        {
            if (playerRectangle.Bottom >= (anotherRect.Top - 2) && // - 2 becouse they should not intersect becouse of bug issues
                playerRectangle.Top <= anotherRect.Top &&
                playerRectangle.Left < anotherRect.Right &&
                playerRectangle.Right > anotherRect.Left)
            {
                CanGoBot = false;
            }
            else CanGoBot = true;


            if (playerRectangle.Top <= (anotherRect.Bottom + 2) && // + 2 becouse they should not intersect becouse of bug issues
                playerRectangle.Bottom >= anotherRect.Bottom &&
                playerRectangle.Left < anotherRect.Right &&
                playerRectangle.Right > anotherRect.Left)
            {
                CanGoTop = false;
            }
            else CanGoTop = true;


            if (playerRectangle.Top < anotherRect.Bottom &&
                playerRectangle.Bottom > anotherRect.Top &&
                playerRectangle.Right >= (anotherRect.Left - 2) && // - 2 becouse they should not intersect becouse of bug issues
                playerRectangle.Left < anotherRect.Left)
            {
                CanGoRight = false;
            }
            else CanGoRight = true;


            if (playerRectangle.Top <= anotherRect.Bottom &&
                playerRectangle.Bottom >= anotherRect.Top &&
                playerRectangle.Left <= (anotherRect.Right + 2) && // + 2 becouse they should not intersect becouse of bug issues
                playerRectangle.Right > anotherRect.Right)
            {
                CanGoLeft = false;
            }
            else CanGoLeft = true;

        }

and CanGoBot, CanGoTop, CanGoLeft and CanGoRight are normal public variablesdeclared in the beginning of the Player class.

Now in my Game1.cs I declare Entity[] entites array, and then Game1.cs Inizialize method looks like this:


protected override void Initialize()
        {
            player = new Player(50, 300);
            entites = new Entity[2];
            entites[0] = new Entity("enemy",ObjectType.Enemy, 400, 300); // enemy
            entites[1] = new Entity("barrier", ObjectType.Object, 150, 200); // barrier
            DrawLowTxt = false;
            base.Initialize();
        }

this is Game1.cs Update():


protected override void Update(GameTime gameTime)
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                this.Exit();

            player.Update();
            Collision();

            base.Update(gameTime);
        }

and Collision method:


private void Collision()
        {
            player.CollisionWith(entites[0].EntityRect); // 1st statment
            player.CollisionWith(entites[1].EntityRect); // 2nd stament
        }

Now the Collision system is only applied to 2nd statment of Collision() method

if I would switch array indexes of those 2 staments, the Collision will be applied only to the rectangle of an object thats on the 2nd stament,

whatever the object is, and 1st statment will not be working :/

Draw() method works cause everything is drawn perfectly :/

So now there are no static variables or methods, so idk :/

Those conditions look wrong, at a glance. For example:


if (playerRectangle.Top <= anotherRect.Bottom &&
playerRectangle.Bottom >= anotherRect.Top &&

If playerRectangle's top is lower than the other rectangle's bottom, that's okay, but then how could playerRectangle's bottom ever be above the other rectangle's top as well?

Instead of manually calculating each direction, it's usually easier to perform collision detection like this:

1. Calculate where the player would be, if they moved the way we expect, and create a rectangle for that location

2. Check if that rectangle overlaps with any other object

3. If it does, we can't perform that move. If it doesn't, then we can.

Those conditions look wrong, at a glance. For example:

if (playerRectangle.Top <= anotherRect.Bottom &&
playerRectangle.Bottom >= anotherRect.Top &&

Well, It can, becouse we are on an Y axis.

The top of the Screen is 0 and bottom is idk lets say 1000.

lets say enemy.Rect.Bottom = 500; and enemy.Rect.Top = 450; (Top is less becouse we are on the Y axis, not X)
So if player,Rect.Bottom is >= 450 && player.Rectangle.Top <= 50, Then that means, that if Player is going to move right or left,
he will at some point intersect with enemyRectangle. The Collision logic is good, I made it working, My problem here is, as the
thread title says: Array problem. I have written everything above, and again, I am experiencing a strange thing.

Now I moved my CollisionLogic away from player or entity classes, I made a public static class RectangleCollision with static method called
CollisionAmong() that takes 2 arguments -> 2 rectangles that might intersect, and then if they do the player wont be able to move.
public static class RectangleCollision
    {

        public static void CollisionAmong(Rectangle oneRect, Rectangle anotherRect)
        {
            if (oneRect.Bottom >= (anotherRect.Top - 2) && // - 2 becouse they should not intersect becouse of bug issues
                oneRect.Top <= anotherRect.Top &&
                oneRect.Left < anotherRect.Right &&
                oneRect.Right > anotherRect.Left)
            {
                Player.CanGoBot = false;
            }
            else Player.CanGoBot = true;


            if (oneRect.Top <= (anotherRect.Bottom + 2) && // + 2 becouse they should not intersect becouse of bug issues
                oneRect.Bottom >= anotherRect.Bottom &&
                oneRect.Left < anotherRect.Right &&
                oneRect.Right > anotherRect.Left)
            {
                Player.CanGoTop = false;
            }
            else Player.CanGoTop = true;


            if (oneRect.Top < anotherRect.Bottom &&
                oneRect.Bottom > anotherRect.Top &&
                oneRect.Right >= (anotherRect.Left - 2) && // - 2 becouse they should not intersect becouse of bug issues
                oneRect.Left < anotherRect.Left)
            {
                Player.CanGoRight = false;
            }
            else Player.CanGoRight = true;


            if (oneRect.Top <= anotherRect.Bottom &&
                oneRect.Bottom >= anotherRect.Top &&
                oneRect.Left <= (anotherRect.Right + 2) && // + 2 becouse they should not intersect becouse of bug issues
                oneRect.Right > anotherRect.Right)
            {
                Player.CanGoLeft = false;
            }
            else Player.CanGoLeft = true;

        }
    }

CollisionChecking on its own is correct, tested it a lot and was struggling with it for some time and I finally made it good, I like it the way it is now
and I dont want to change it, it is not a problem.

The problem comes now:

As I said, In my Game1.cs class I made player and 2 things, barrier and enemy.
Entity[] entites;
protected override void Initialize()
        {
            player = new Player(50, 300);
            entites = new Entity[2];
            entites[0] = new Entity("enemy",ObjectType.Enemy, 400, 300); // enemy
            entites[1] = new Entity("barrier", ObjectType.Object, 150, 200); // barrier
            DrawLowTxt = true;
            base.Initialize();
        }
and I will post this draw method here as well:
 protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.DimGray);
            spriteBatch.Begin();
            map.DrawMap(spriteBatch);
            player.Draw(spriteBatch);

            foreach (Entity entity in entites)
            {
                entity.Draw(spriteBatch);
            }
            spriteBatch.End();            
            base.Draw(gameTime);
        }

Okay now everything works great, there are player barrier and enemy drawn. (and map but it has nothing to do with anything and is not
important right now).

So now, In Game1.cs Update()method I call Collison() method.
Collision method is a method in Game1.cs class which I want to have for
Collision Checks, and now, my Collision() method looks like this:
private void Collision()
        { 
            RectangleCollision.CollisionAmong(player.playerRectangle, entities[0].EntityRect); // 1st statment
            RectangleCollision.CollisionAmong(player.playerRectangle, entities[1].EntityRect); // 2nd statemnt
        }
As I said many times before, Now when I build and run my game, player will have Collision stuff with barrier only, not enemy
cause barrier is on 2nd stament (as I said before, I dont know why but only second statement is executed in game, and 1st statment is not working <--- THIS IS THE PROBLEM).

Again, If that Collision method looked like this:
private void Collision()
        { 
            RectangleCollision.CollisionAmong(player.playerRectangle, entities[1].EntityRect); // now 1st stament is checking for collision with entities[1]
            RectangleCollision.CollisionAmong(player.playerRectangle, entities[0].EntityRect); // other way around than when it was like above
        }
Now player will have Collision with enemy, not barrier, becouse, enemy is on 2nd stament, and Collision wont work on barrier.

I hope that now you guys can realize what is my problem, and maybe someone knows why this is happening :/

Look more carefully at your CollisionAmong code. You're resetting the values of CanGoBot, CanGoTop, etc.... every time you call the function. Hence, your state is only determined by the last call to CollisionAmong.

Okaay I made some changes now, here is my RectangleCollision class:


static class RectangleCollision
    {
        public static bool TouchTop(this Rectangle oneRect, Rectangle anotherRect)
        {
            if (oneRect.Bottom >= (anotherRect.Top - 2) && // - 2 becouse they should not intersect becouse of bug issues
                oneRect.Top <= anotherRect.Top &&
                oneRect.Left < anotherRect.Right &&
                oneRect.Right > anotherRect.Left)
            {
                return true;
            }
            else return false;
        }

        public static bool TouchBot(this Rectangle oneRect, Rectangle anotherRect)
        {
            if (oneRect.Top <= (anotherRect.Bottom + 2) && // + 2 becouse they should not intersect becouse of bug issues
                oneRect.Bottom >= anotherRect.Bottom &&
                oneRect.Left < anotherRect.Right &&
                oneRect.Right > anotherRect.Left)
            {
                 return true;
            }
            else return false;

        }

        public static bool TouchLeft(this Rectangle oneRect, Rectangle anotherRect)
        {
            if (oneRect.Top < anotherRect.Bottom &&
                oneRect.Bottom > anotherRect.Top &&
                oneRect.Right >= (anotherRect.Left - 2) && // - 2 becouse they should not intersect becouse of bug issues
                oneRect.Left < anotherRect.Left)
            {
                return true;
            }
            else return false;
        }

        public static bool TouchRight(this Rectangle oneRect, Rectangle anotherRect)
        {
            if (oneRect.Top <= anotherRect.Bottom &&
                oneRect.Bottom >= anotherRect.Top &&
                oneRect.Left <= (anotherRect.Right + 2) && // + 2 becouse they should not intersect becouse of bug issues
                oneRect.Right > anotherRect.Right)
            {
                return true;
            }
            else return false;
        }
        
    }

and then In my player class I did this:


public void Collision(Rectangle rect)
        {
            if (playerRectangle.TouchTop(rect))
                CanGoBot = false;
            else CanGoBot = true;

            if (playerRectangle.TouchBot(rect))
                CanGoTop = false;
            else CanGoTop = true;

            if (playerRectangle.TouchLeft(rect))
                CanGoRight = false;
            else CanGoRight = true;

            if (playerRectangle.TouchRight(rect))
                CanGoLeft = false;
            else CanGoLeft = true;
        }

and last bit, in Game1.cs:


foreach(Entity entity in entities)
            {
                player.Collision(entity.EntityRect);
            }   

And still my problem remains the same, Collision is working only with one rectangle... So how can I not reset values of those CanGoBot CanGoTop etc bools?

What should I do?

And still my problem remains the same, Collision is working only with one rectangle... So how can I not reset values of those CanGoBot CanGoTop etc bools? What should I do?

In your collision function, set CanGoBot, CanGoTop, etc... to false if the rects are touching (as you do now). Otherwise, don't touch the variables.

Just before you make your call your collision methods, reset CanGoBot, CanGoTop, etc.. to true.

Then call your collision methods.

This topic is closed to new replies.

Advertisement