1
votes

For the past 12 hours I've been trying "all" different methods I can think of, in order to make two rectangles intersect/test collision correctly in XNA (4.0).

I have three classes (just example names):

  • Game1.cs
  • Player.cs
  • Man.cs

In Game1 I load the content like this:

// In the beginning of Game1:

    Player player;
    Man man;

// LoadContent:

    man = new Man(Content.Load<Texture2D>("ManImage"), new Rectangle(440, 310, 150, 98));
    player = new Player(Content.Load<Texture2D>("playerSheet"), new Vector2(40, 420), 50, 44);

However, I want to check for collision between man and player, but I don't understand how to "join" those two classes to be able to do an if(intersects) in Game1 (if that's the place to do it).

The player rectangle looks like this:

playerRect = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);

Have I just gone completely "code blind" here, or what? Anyone able to help me out with this, motivation went down after 12 hours of collision testing.

1
I might not be understanding the question, but if you can get two Rectangle objects, one for the player and one for the man, can't you just write a function in Game1 that checks if two rectangles intersect? Then you don't have to worry about "joining" the classes, right? Just make a GetRect() function for both the man and the player, and then send those two rects to an Intersects() functin in Game1.M Katz

1 Answers

1
votes

You could, for both of the classes, add a property

public Rectangle PositionRectangle { get; private set; }

then, in the relevant constructors, you'd need to initiate this property

public Man(..., Rectangle rectangle)
{
    PositionRectangle = rectangle;
}

public Player(..., Vector2 position, int width, int height)
{
    PositionRectangle = new rectangle((int)position.X, (int)position.Y, width, height);
}

You don't need to worry about what frame you're displaying, since this is related to the source rectangle, not to the destination rectangle (which is what you need to test for collisions).

Then you can test for these collisions easily

if(man.PositionRectangle.Intersects(player.PositionRectangle))
{
    //collision logic
}

Of course, you'd need to take care to update these rectangles any time you change the positions (or widths and heights if those are changeable)


Slight edit (or a better version)

If you would like to position Man and Player easily without having to worry about how their rectangles are updated, you could set it up like this:

class Man
{
    Texture2D _texture;

    public Vector2 Position { get; set; }
    public int Width { get; set; } 
    public int Height { get; set; }

    public Rectangle PositionRectangle
    {
        get
        {
            return new Rectangle((int)Position.X, (int)Position.Y, Width, Height);
        }
    }

    public Man(Texture2D texture)
    {
        this._texture = texture;
        this.Width = texture.Width;
        this.Height = texture.Height;
    }

    ... //other man related logic!
}

class Player
{
    Texture2D _texture;
    int _frameCount;
    int _currentFrame;
    //other frame related logic...

    public Vector2 Position { get; set; }
    public int Width { get; set; } 
    public int Height { get; set; }

    public Rectangle PositionRectangle
    {
        get
        {
            return new Rectangle((int)Position.X, (int)Position.Y, Width, Height);
        }
    }

    public Rectangle SourceRectangle
    {
        get
        {
            return new Rectangle(Width * _currentFrame, 0, Width, Height);
        }
    }

    public Player(Texture2D texture, int frameWidth, int frameCount)
    {
        this._texture = texture;
        this.Width = frameWidth;
        this.Height = texture.Height;
        this._frameCount = frameCount;
        this._currentFrame = 0;
        //etc...
    }

    ... //other player related logic! such as updating _currentFrame

    public Draw(SpriteBatch spriteBatch)
    {
         spriteBatch.Draw(_texture, PositionRectangle, SourceRectangle, Color.White);
    }
}

Here I've given you example of how you could make use of property accessors to dynamically generate your relevant rectangles!

You use PositionRectangle to determine where your player (or man) will be located on screen, and you use SourceRectangle to determine which part of the texture you're gonna draw.

Also, if your man and player widths and heights aren't going to change then you should set their set accessors to private.

When you need to change the locations, you just set their position property

man.Position = new Vector2(100, 100); //i.e.

and your collisions and draw logic will automatically use the new rectangles without any further intervention!

Hope you like it!

Edit2

Relating to source rectangle being public, you only need that if you're drawing these from outside (i.e. Game1 calls spriteBatch.Draw(player.Texture, player.PositionRectangle, player.SourceRectangle, Color.White);).

If you're drawing it like in the example (from the inside), you could just scrap the whole public Recangle SourceRectangle{...} thing and just use that rectangle directly in the draw:

    public Draw(SpriteBatch spriteBatch)
    {
         spriteBatch.Draw(_texture, PositionRectangle, new Rectangle(Width * _currentFrame, 0, Width, Height), Color.White);
    }