Базовое обнаружение столкновений в Monogame не работает

У меня странная проблема, когда дело доходит до обнаружения основного столкновения, и, честно говоря, я не могу понять, почему.

Таким образом, мое движение для моего игрока находится в моем классе Player.cs, и в этом классе содержится метод Update(), который вызывается в моем основном игровом цикле в Game1.cs. Я настроил так, что когда хитбокс моего игрока «Прямоугольник Hitbox;» пересекается с тайлом столкновения, он переключает логическое значение inAir на false. Когда это логическое значение ложно, сила тяжести должна быть равна нулю. Код в моем методе обновления Player.cs выглядит следующим образом:

public void Update(GameTime gameTime) {

    //In my constructor for the Player class
    //Position is set equal to a new Vector2(0, 0)
    //Velocity is set equal to Vector2.Zero
    //Acceleration is set equal to a new Vector2(0, 100.0f);

    float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

    Velocity += Acceleration * deltaTime;
    Position += Velocity * deltaTime;

    HitBox = new Rectangle(new Point((int)Position.X, (int)Position.Y), new Point(Width, Height));

    foreach (SpriteTile t in gameMap.CollisionSprites) {
        if (HitBox.Intersects(t.Bounds))
            inAir = false;
        else if (!HitBox.Intersects(t.Bounds))
            inAir = true;
    }

    if (!inAir) {
        Velocity.Y = -Acceleration.Y * deltaTime;
    }

}

У меня также есть простой текст, отображаемый на экране, сообщающий мне значение логического значения «inAir», которое будет показано на изображении, которое я приведу немного позже.

В моем классе Player.cs выше объект SpriteTile хранит только 2 вещи: Texture2D и позицию, которая предопределяется, когда я загружаю коллизии из моего слоя Tiled Collision.

Однако метод Bounds просто возвращает прямоугольник, показывающий границы текущей плитки. Он определяется следующим образом:

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

Для меня самое загадочное во всем этом то, что когда я добавил простой код отладки, чтобы вывести эти значения на экран и проверить, работают ли коллизии, я получил это:

введите здесь описание изображения

Судя по ограничивающим прямоугольникам, которые я рисую, они должны пересекаться, чтобы остановить падение. Даже если я неправильно понял код ответа на столкновение, логическое значение «inAir» должно быть установлено в true. (Да, верно, потому что строка отображается на экране следующим образом: «Пересечение:» + !Player.inAir означает, что если пересечение произойдет, оно будет отображаться на экране верно.

Если потребуется дополнительная информация о моем коде, дайте мне знать, и я отредактирую пост и предоставлю его.

Если кто-нибудь может помочь мне понять, где я ошибаюсь в реализации такой простой идеи, я был бы более чем благодарен! Спасибо, парни.


person BlazeXenon    schedule 20.12.2016    source источник


Ответы (1)


Проблема, скорее всего, связана с тем, как во время обновления определяется «inAir». В предоставленном цикле только последний спрайт в столкновении CollisionSprites может привести к тому, что inAir будет ложным.

Допустим, что gameMap.CollisionSprites содержит 2 спрайта. Первый спрайт, с которым вы пересекаетесь. Второй вы не делаете. При первом проходе цикла HitBox.Intersects(t.Bounds) имеет значение true, что приводит к тому, что для inAir устанавливается значение false, как вы и ожидали. Однако цикл не заканчивается, и HitBox.Intersects(t.Bounds) запускается на втором спрайте, что является ложным, и устанавливает inAir в ложное.

Есть несколько способов исправить это. Вот один из способов:

inAir = true; // assume you're in the air
foreach (SpriteTile t in gameMap.CollisionSprites) {
    if (HitBox.Intersects(t.Bounds))
    {
        inAir = false; 
        break; // you've collided, no reason to check any others
    }
}

Упрощение с использованием методов расширения Linq...

inAir = !gameMap.CollisionSprites.Any(t => HitBox.Intersects(t.Bounds));

Вероятно, есть и другие проблемы, с которыми вы сталкиваетесь, но это должно решить ваше обнаружение столкновений из того, что я могу собрать.

person Shawn Rakowski    schedule 21.12.2016
comment
Ха-ха, да, ты полностью прав. Я действительно понял это пару часов назад, когда возился во время отладки, и это решило проблему! Спасибо за вашу помощь, и было бы неплохо оставить это здесь на будущее, если у кого-то еще возникнет аналогичная проблема! - person BlazeXenon; 21.12.2016