Monogame Basic Collision Detection не работает
У меня странная проблема, когда дело доходит до обнаружения базового столкновения, и, честно говоря, я не могу понять, почему.
Таким образом, мое движение за моего игрока находится в моем классе Player.cs, и в этом классе содержится метод Update(), который вызывается в моем основном игровом цикле в Game1.cs. Я настроил его так, чтобы когда хитбокс моего игрока "Прямоугольный хитбокс"; пересекается с плиткой столкновения, она переключает логическое значение с именем 'inAir' на false. Когда это логическое значение ложно, сила тяжести должна быть равна нулю. Код в методе Update моего 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 и Position, которые предопределены, когда я загружаю столкновения из моего Tiled Collision Layer.
Однако метод Bounds просто возвращает прямоугольник, показывающий границы текущей плитки. Он определяется следующим образом:
public Rectangle Bounds {
get {
return new Rectangle(
(int)Position.X,
(int)Position.Y,
Texture.Width,
Texture.Height);
}
}
Загадочная часть всего этого для меня заключается в том, что когда я добавил простой отладочный код для рисования этих значений на экране и проверки работоспособности столкновения, я получил следующее:
В соответствии с ограничивающими рамками, которые я рисую, он должен пересекаться, поэтому останавливать падение. Даже если я неправильно понял код ответа на столкновение, булево значение 'inAir' должно быть установлено в true. (Да, потому что строка выводится на экран следующим образом: "Пересекается: " +!Player.inAir, означая, что если пересечение будет иметь место, оно будет отображаться на экране true.
Если потребуется дополнительная информация о моем коде, дайте мне знать, и я отредактирую сообщение и предоставлю его.
Если кто-нибудь может помочь мне выяснить, где я ошибаюсь при реализации такой простой идеи, я был бы более чем благодарен! Спасибо, парни.
1 ответ
Скорее всего, проблема связана с тем, как во время обновления определяется "inAir". Согласно предоставленному циклу, только последний спрайт в столкновении CollisionSprites может вызвать inAir, чтобы быть ложным.
Допустим, gameMap.CollisionSprites содержит 2 спрайта. Первый спрайт, с которым вы пересекаетесь. Второе, что вы не делаете. На первом проходе цикла HitBox.Intersects(t.Bounds)
Значение true, в результате чего inAir будет установлено в значение false, как вы ожидаете Однако цикл не заканчивается и HitBox.Intersects(t.Bounds)
запускается на втором спрайте, который имеет значение false, и устанавливает inAir в значение false.
Есть несколько способов исправить это. Вот один из способов:
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));
Вероятно, есть другие проблемы, с которыми вы сталкиваетесь, но это должно решить вашу проблему обнаружения столкновений из того, что я могу собрать.