【问题标题】:XNA intersect/collision with multiple classes?XNA 与多个类相交/碰撞?
【发布时间】:2012-05-09 10:12:09
【问题描述】:

在过去的 12 小时里,我一直在尝试我能想到的“所有”不同方法,以便在 XNA (4.0) 中正确地使两个矩形相交/测试碰撞。

我有三个类(只是示例名称):

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

在 Game1 中,我加载如下内容:

// Game1 开始时:

    Player player;
    Man man;

// 加载内容:

    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);

但是,我想检查人和玩家之间的碰撞,但我不明白如何“加入”这两个类以便能够在 Game1 中执行 if(intersects) (如果这是执行此操作的地方)。

播放器矩形如下所示:

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

我只是在这里完全“编码盲”,还是什么?任何人都可以帮助我解决这个问题,经过 12 小时的碰撞测试后,动力下降了。

【问题讨论】:

  • 我可能不明白这个问题,但是如果你能得到两个 Rectangle 对象,一个给玩家,一个给男人,你不能在 Game1 中写一个函数来检查两个矩形相交?那你就不用担心“加入”课程了,对吧?只需为人和玩家创建一个 GetRect() 函数,然后将这两个矩形发送到 Game1 中的 Intersects() 函数。

标签: c# xna collision intersect


【解决方案1】:

您可以为这两个类添加一个属性

public Rectangle PositionRectangle { get; private set; }

那么,在相关的构造函数中,你需要初始化这个属性

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);
}

您不必担心要显示的帧,因为这与 源矩形有关,而不是 目标矩形(这就是您需要测试碰撞)。

然后您可以轻松测试这些碰撞

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

当然,每次更改位置(或宽度和高度,如果它们是可更改的)时,您都需要注意更新这些矩形


稍作修改(或更好的版本)

如果您想轻松定位 Man 和 Player 而不必担心他们的矩形是如何更新的,您可以这样设置:

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);
    }
}

在这里,我给您提供了如何使用属性访问器来动态生成相关矩形的示例!

您使用PositionRectangle 来确定您的玩家(或人)将在屏幕上的位置,并使用SourceRectangle 来确定您要绘制纹理的哪个部分。

另外,如果你的人和球员的宽度和高度不会改变,那么你应该将他们的set 访问器设置为private

当你需要改变位置时,你只需设置它们的位置属性

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

您的碰撞和绘制逻辑将自动使用新的矩形,无需任何进一步的干预!

希望你喜欢!

编辑2

关于源矩形是公开的,你只需要从外部绘制这些矩形(即Game1 调用spriteBatch.Draw(player.Texture, player.PositionRectangle, player.SourceRectangle, Color.White);)。

如果您像示例中那样(从内部)绘制它,您可以直接废弃整个 public Recangle SourceRectangle{...} 并直接在绘图中使用该矩形:

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

【讨论】:

  • 这似乎是一个很棒的主意,当然!我现在一直在实施您更新的想法,但到目前为止,玩家角色完全静止(但是,当我使用键时,精灵动画可以工作),但它不会在屏幕上移动。我认为这与 frameCount 和 currentFrame 有关。我还实现了“Edit2”功能,但我必须处理角色的移动。
  • 嗯,这应该与 currentFrame 无关(这仅用于源)-您确定要更新 player.Position 吗?尝试为其分配一些值,以查看玩家是否移动到那里
  • 哈哈,真是个愚蠢的错误。我不小心在 Game1 更新中使用了 player.Position(开始位置)而不是 LoadContent。现在它工作得很好!但是,我尝试使用简单的 if 检查来拒绝“离开屏幕”,通过使用它,但 playerPosition “不是变量”它说。关于那个有什么想法吗? if (playerPosition.Y >= 480) playerPosition.Y = 480;
  • 你应该像这样设置它:player.Position = new Vector2(player.Position.X, 480); 这是因为player.Position的类型是Vector2,这是一个值类型(struct)而不是一个引用类型(@987654338 @)。
  • 但这会将玩家的位置设置为 480,对吗?我尝试在玩家无法进入的地方(例如空中或视口外)创建一些“墙”。而且我不能使用if(player.Position.X &gt;= 480) { player.Position.X = 480; },因为Position 不是变量。对不起,如果你解释的是这个问题的答案,我可能会误解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
  • 1970-01-01
相关资源
最近更新 更多