Обнаружение столкновения работает только на верхней стороне стены - Java - PullRequest
0 голосов
/ 05 декабря 2018

У меня есть задание для создания 2D-игры, эта игра должна использовать абстрактный класс Shape, который используется для рисования фигур.Я решил сделать 2D-платформер, но я впервые делаю что-то подобное.Я пытаюсь реализовать обнаружение столкновений и решил создать смещение моего объекта игрока, чтобы увидеть, сталкивается ли он с моим прямоугольным объектом, и остановить движение, если это произойдет.Это работает только для верхней стороны, однако справа, слева и снизу игрок будет двигаться через прямоугольник, и я не понимаю, почему.Я ожидал, что обнаружение столкновения сработает для всех сторон.Я хотел бы знать, как я могу изменить обнаружение столкновений для работы со всеми сторонами прямоугольника.

Вот рисунок, показывающий, что происходит: enter image description here

МойКласс приложения:

package A2;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.util.TreeSet;

import static java.awt.event.KeyEvent.*;

public class App extends JFrame {

    private static final int GRAVITY = 10;
    private static final int MAX_FALL_SPEED = 30;

    public App() {

        final Player player = new Player(200, 300);
        final Rectangle rectangle = new Rectangle(100, 400);
        JPanel mainPanel = new JPanel() {
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                player.draw(g);
                rectangle.draw(g);
            }
        };

        mainPanel.addKeyListener(new controlHandler(this, player, rectangle));
        mainPanel.setFocusable(true);
        add(mainPanel);

        setLayout(new GridLayout());
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(600, 600);
    }


    class controlHandler implements ActionListener, KeyListener {
        int keyCode;
        App app;
        Player player;
        Rectangle rectangle;
        TreeSet<Integer> keys = new TreeSet<>();
        Timer time = new Timer(5, this);
        boolean collision = false;


        public controlHandler(App app, Player player, Rectangle rectangle) {
            this.app = app;
            this.player = player;
            this.rectangle = rectangle;
            time.start();
        }

        public void actionPerformed(ActionEvent e) {
            player.x += player.xVelocity;
            player.y += player.yVelocity;

            Rectangle2D offset = player.getOffsetBounds();

            if(offset.intersects(this.rectangle.wallObj.getBounds2D())){
                collision = true;
                player.xVelocity = 0;
                player.yVelocity = 0;
            }
            else collision = false;

            repaint();
        }

        public void keyPressed(KeyEvent e) {
            keyCode = e.getKeyCode();
            keys.add(keyCode);


            switch (keyCode) {
                case VK_UP:
                    moveUp();
                    break;
                case VK_DOWN:
                    moveDown();
                    break;
                case VK_LEFT:
                    moveLeft();
                    break;
                case VK_RIGHT:
                    moveRight();
                    break;
            }
        }

        public void keyReleased(KeyEvent e) {
            released();
        }
        public void keyTyped(KeyEvent e) { }

        public void moveUp() {
            player.xVelocity = 0;
            player.yVelocity = -2;
        }

        public void moveDown() {
            if(!collision) {
                player.xVelocity = 0;
                player.yVelocity = 2;
            }
        }

        public void moveLeft() {
            player.xVelocity = -2;
            player.yVelocity = 0;
        }

        public void moveRight() {
            player.xVelocity = 2;
            player.yVelocity = 0;
        }

        public void released() {
            player.xVelocity = 0;
            player.yVelocity = 0;
        }
    }

    public static void main(String[] args) {
        App app = new App();
        app.setVisible(true);
    }
}

abstract class Shape {
    public double x;
    public double y;

    public void draw(Graphics g) { }
}

Класс игрока:

package A2;

import java.awt.*;
import java.awt.geom.Rectangle2D;

public class Player extends Shape {
    public double xVelocity;
    public double yVelocity;
    public double length = 60;
    public double top;
    public double right;
    public double left;
    public double bottom;
    public  Rectangle2D playerObj;


    public Player(double x, double y) {
        this.x = x;
        this.y = y;
        playerObj = new Rectangle2D.Double(x, y, length, length);
    }

    public Rectangle2D getOffsetBounds(){
        return new Rectangle2D.Double(x + xVelocity , y + yVelocity , length, length);
    }

    public void draw(Graphics g) {
        playerObj = new Rectangle2D.Double(x, y, length, length);
        g.setColor(Color.BLACK);
        Graphics2D g2 = (Graphics2D)g;
        g2.fill(playerObj);

    }
}

Класс прямоугольника (будет платформой):

package A2;

import java.awt.*;
import java.awt.geom.Rectangle2D;

public class Rectangle extends Shape {
    public double width = 400;
    public double height = 30;
    public double top;
    public double right;
    public double left;
    public double bottom;
    public Rectangle2D wallObj;

    public Rectangle(double x, double y) {
        this.x = x;
        this.y = y;
        wallObj = new Rectangle2D.Double(x, y, width, height);
    }

    public void draw(Graphics g) {
        g.setColor(Color.ORANGE);
        Graphics2D g2 = (Graphics2D)g;
        g2.fill(wallObj);

    }
}

1 Ответ

0 голосов
/ 05 декабря 2018

Итак, исходя из моего понимания, ваш процесс обнаружения столкновений в основном заключается в создании «виртуального» экземпляра объекта и определении, будет ли он сталкиваться.

Ваш код на самом деле работает, вы можете сказать поТот факт, что объект «прекращает» движение после столкновения, но то, что вы не делаете, сбрасывает положение объекта после него.

Давайте посмотрим на оригинальный код ...

public void actionPerformed(ActionEvent e) {
  player.x += player.xVelocity;
  player.y += player.yVelocity;

  Rectangle2D offset = player.getOffsetBounds();

  if (offset.intersects(this.rectangle.wallObj.getBounds2D())) {
    collision = true;
    player.xVelocity = 0;
    player.yVelocity = 0;
  } else {
    collision = false;
  }

  repaint();
}
  • Обновление позиции объекта
  • Создание виртуального экземпляра объекта, который применяет скорость к текущей позиции объекта ... снова?
  • Определить, сталкивается ли объект
  • Остановить движение, если есть
  • ... где вы сбрасываете положение объекта, чтобы он больше не сталкивался?!?

Вместо этого вы не должныt установить положение объекта до ПОСЛЕ того, как вы определите, произошло ли столкновение или нет, например ...

public void actionPerformed(ActionEvent e) {

  Rectangle2D offset = player.getOffsetBounds();

  if (offset.intersects(this.rectangle.wallObj.getBounds2D())) {
    collision = true;
    player.xVelocity = 0;
    player.yVelocity = 0;
  } else {
    player.x += player.xVelocity;
    player.y += player.yVelocity;
    collision = false;
  }

  repaint();
}

Однако проблема с этим подходом заключается в том, что скорость достаточно велика,объект будет казаться не сталкивающимся, но остановится немного перед ним, так как количество изменений больше, чем оставшийся разрыв.

Что вам нужно сделать, это как только вы обнаружили столкновение, это вычислить разницумежду суммой, которую вы хотите переместить, и доступным пространством и переместите объект только на эту сумму вместо

...