Slick2D Обнаружение столкновения прямоугольника

1

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

Я создаю пошаговую боевую игру (похожую на Final Fantasy или Legend of Dragoon), где персонаж игрока находится в правой части экрана, а враг - с левой стороны. Игрок и враг поочередно атакуют. Поэтому, когда игрок атакует, анимация спрайта перемещается по экрану справа налево, пока она не остановится перед врагом, не атакует и не вернется к нему, начиная с координат. И игрок, и враг имеют прямоугольник, нарисованный вокруг них, чтобы представлять границы каждого персонажа.

Когда игрок движется вперед, он проходит через прямоугольник "Враг" и останавливается внутри него. В этот момент на консоль должен выводиться сообщение "INTERSECT!" чтобы показать, что произошло столкновение между двумя прямоугольниками, но, к сожалению, этого не произошло.

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

Это моя точка входа, GameClass:

public class GameClass extends BasicGame{
//other variable declarations

public void init(GameContainer container) throws SlickException {
player = new Player();
enemy = new Enemy();
skeleton = new Skeleton();
enemy = skeleton;
playX = player.getStartX(); //700
playY = player.getStartY(); //140
playW = player.rect.getWidth(); //40
playH = player.rect.getHeight(); //70
enemyX = enemy.getStartX(); //100
enemyY = enemy.getStartY(); //140
enemyWidth = enemy.getWidth(); //50
enemyHeight = enemy.getHeight(); //55

SpriteSheet sheet = new SpriteSheet("data/homeranim.png", 36, 65);
    anim = new Animation();
    for (int i=0;i<8;i++) {
        anim.addFrame(sheet.getSprite(i,0), 150);
    }
}

public void render(GameContainer container, Graphics g)
        throws SlickException {
anim.draw(playX,playY); // draws player animation
skeletonAnim.draw(enemyX, enemyY); // draws enemy
g.draw(player.rect); //draws player bounds
g.draw(enemy.rect); //draws enemy bounds
}

public void update(GameContainer container, int delta)
        throws SlickException {
playerUpdate(delta);
if (player.rect.intersects(enemy.rect)) {
             System.out.println("INTERSECT!");

         System.out.println("Player minX: " + player.rect.getMinX());
         System.out.println("Player maxX: " + player.rect.getMaxX());
         System.out.println("Enemy minX: " + enemy.rect.getMinX());
         System.out.println("Enemy maxX: " + enemy.rect.getMaxX());
         }
      }

public void playerUpdate(int delta) {
    if (playerForward == true){
       playX -= delta * 0.4f;
       if (playX <= 140) {
             playX = 140;
             playerForward = false;
             playerBackward = true;}
  }

   if (playerBackward == true) {
         playX += delta * 0.4f;
         if (playX >= 700) {
             playX = 700;
             playerBackward = false;
             delay = 1250;
  }

public void keyReleased(int key, char c) {
       if (key == Input.KEY_ENTER){
          playerForward = true;}
}
}

Это взгляд на мой класс Player:

public class Player {

private int startX = 700;
private int startY = 140;
public Shape rect = new Rectangle(startX, startY, 40, 70);
//plus getters and setters
}

И весь мой класс Врага:

public class Enemy {

private int startX, startY, width, height;
public Shape rect = new Rectangle(startX, startY, width, height);
// plus getters and setters
   }

Мой класс Skeleton расширяет Enemy:

public class Skeleton extends Enemy {

public Skeleton() {
    // TODO Auto-generated constructor stub
    setMaxHealth(120);
    setStartX(100);
    setStartY(140);
    setWidth(50);
    setHeight(55);
}

}

Примечание. Поскольку я переключил g.drawRect() на g.draw(), прямоугольник противника не рисуется.

Прямые границы в начальной точке: http://i.imgur.com/QDDk858.png

Прямая граница, где столкновение должно быть: http://i.imgur.com/pOANfvN.png

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

  • 0
    Так в чем ваша проблема? Метод пересечений не запускается?
  • 0
    И почему вы создаете хитбоксы с centerX и centerY вместо x и y. Аргументы для конструктора Rectangle (startX, startY, width, height), а не центр. Так что это может быть вашей проблемой, так как тогда хитбоксы будут смещены.
Показать ещё 6 комментариев
Теги:
rectangles
collision-detection
intersection
slick2d

1 ответ

1
Лучший ответ

Вы не обновляете позиции hitbox самостоятельно.

Вы рисуете это:

g.drawRect(playX, playY, playW, playH); //draws player bounds
g.drawRect(enemyX, enemyY, enemyW, enemyH); //draws enemy bounds

Но это не фактический hitbox, это только позиция игрока/врага, и прямоугольники, нарисованные здесь, будут в правильном положении, в то время как сами хиты - нет.

Я предлагаю вам сделать следующее:

public void update(GameContainer container, int delta)
{
    playerUpdate(delta);

    player.rect.setLocation(playX, playY);
    enemy.rect.setLocation(enemyX, enemyY); // update the hitboxes to the new positions

    if (player.rect.intersects(enemy.rect))
    {
        System.out.println("INTERSECT!");
    }
}

public void playerUpdate(int delta)
{
    if (playerForward == true)
    {
       playX -= delta * 0.4f;

       if (playX <= 140) 
       {
             playX = 140;
             playerForward = false;
             playerBackward = true;
       }
    }

    if (playerBackward == true) 
    {
         playX += delta * 0.4f;

         if (playX >= 700) 
         {
             playX = 700;
             playerBackward = false;
             delay = 1250;
         }
    }
}

public void keyReleased(int key, char c) 
{
   if (key == Input.KEY_ENTER)
   {
      playerForward = true;
   }
}

Кроме того, поскольку вы, кажется, новичок в разработке игр на Java, некоторые советы для вас:

  • Отформатируйте свой код правильно

Всегда размещайте полный {...} после if, else, switch, while, for и т. Д.; правильный отступ строки.

  • Think OO (объектно-ориентированный)

Это очень важно. Ваш класс противников и игроков должен как расширять какой-то класс сущности, потому что они оба очень хотят получить подобное поведение (избегайте дублирования кода!). Сопоставьте аналогичное поведение с суперклассом, упростите поведение, которое нужно контролировать с помощью нескольких настраиваемых параметров и т.д.

Например, вы сохраняете позиции своего врага и игрока как статическое целое в своем основном классе. Это не OO. Переместите позиции в класс сущности, где вы можете реализовать его любым способом.

  • Не просто бросайте исключение без причины

Ваш метод update (...) генерирует исключение SlickException, даже если он никогда не нужен.

  • Будьте осторожны с инкапсуляцией

Это то, что делают многие новички: просто возьмите некоторые параметры, поместите их в класс как закрытый (или, возможно, даже открытый), и создайте для них getters- и сеттеры. Это не инкапсуляция. Это почти так же плохо, как сделать их публичными в первую очередь.

Но почему бы нам просто не сделать все публично?

Мы не хотим, чтобы кто-либо (или даже мы) полагался на некоторые параметры, которые просто происходят из-за очень конкретной реализации того, что мы, возможно, захотим изменить позже. Не просто ставьте все возможные значения там, которые нужно изменить, смысл инкапсуляции должен быть независим от того, какую реализацию мы в конечном итоге используем и чтобы защитить удобство использования нашего кода, защищая то, что можно установить/изменить.

  • Производительность имеет значение

Это один из аспектов, на которые вы должны обратить внимание, для любого программного обеспечения, но часто вы можете наиболее точно увидеть последствия в играх. Производительность важна! И тем не менее, я не имею в виду, что вам нужно следить за каждой деталью, но просто держите обзор в том, как улучшить и скорректировать код, особенно с помощью часто называемых методов, таких как обновление (..) и render (..) в Slick2D.

Обновить

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

public class Enemy {

    private int startX, startY, width, height;
    public Shape rect = new Rectangle(startX, startY, width, height);
    // plus getters and setters
}

ширина и высота могут быть равны 0, поскольку они никогда не назначаются целым числам, которые имеют значение 0 по умолчанию, поэтому у hitbox с прямоугольником противника есть 0 ширина и никогда не будет срабатывать.

Попробуйте что-нибудь вроде:

 public class Enemy {

    private int startX, startY, width = 50, height = 70;
    public Shape rect = new Rectangle(startX, startY, width, height);
    // plus getters and setters
 }

Это должно работать, но вы должны перенести все эти атрибуты в класс врага и поместить их в конструктор.

  • 0
    Да, я новичок в разработке игр на Java! Большое спасибо за полезные советы, суперкласс Entity был бы намного лучшей идеей для того, что я пытаюсь сделать. Я попытался заменить g.drawRect () на g.draw (player.rect) и добавил две строки setLocation (), которые вы рекомендовали. К сожалению, метод пересечений не запускается. Я буду продолжать вносить коррективы на основе ваших предложений.
  • 0
    @RookieCookie Хм ... это действительно странно. Обычно метод пересечения работает без каких-либо проблем. Вы пытались проверить, правильно ли обновляются границы прямоугольников? Просто напечатайте player.rect.getMinX (), player.rect.getMaxX () ... и так далее, и опубликуйте, что он говорит.
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню